From 7789035c1c7ef288061e6715f8ec924284fbcae6 Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:36:20 -0400 Subject: [PATCH] fix(contract-client): when options should go first Make the `methodOptions` object the first argument for ContractClient methods that take no arguments. This makes it match the types generated by the CLI. In order to get eslint to stop complaining about TypeScript feature `Pick`, I also switched eslint's parser to `@typescript-eslint/parser` --- .eslintrc.js | 2 +- CHANGELOG.md | 4 ++ package.json | 3 +- src/contract_client/client.ts | 63 +++++++++++++------------ test/e2e/src/test-hello-world.js | 7 +++ yarn.lock | 80 ++++++++++++++++++++++---------- 6 files changed, 102 insertions(+), 57 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 1ad7098b9..2b366f290 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -4,7 +4,7 @@ module.exports = { }, extends: ["airbnb-base", "prettier"], plugins: ["@babel", "prettier", "prefer-import"], - parser: "@babel/eslint-parser", + parser: "@typescript-eslint/parser", rules: { "node/no-unpublished-require": 0, }, diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c5087a35..e1f17db9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ A breaking change will get clearly marked in this log. ## Unreleased +### Fixed + +* ContractClient now properly handles methods that take no arguments. While most methods take two arguments (arguments for the function, `args`, as well as various `MethodOptions`), if there are no arguments for the functions, then we can omit the first. This brings the ContractClient inline with the types generated by Soroban CLI's `soroban contract bindings typescript`. Full details: [#940](https://github.com/stellar/js-stellar-sdk/pull/940) + ## [v11.3.0](https://github.com/stellar/js-stellar-sdk/compare/v11.2.2...v11.3.0) ### Added diff --git a/package.json b/package.json index 04d7328fc..f43561b76 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,6 @@ "devDependencies": { "@babel/cli": "^7.24.1", "@babel/core": "^7.24.3", - "@babel/eslint-parser": "^7.24.1", "@babel/eslint-plugin": "^7.22.10", "@babel/preset-env": "^7.24.3", "@babel/preset-typescript": "^7.24.1", @@ -97,7 +96,7 @@ "@types/randombytes": "^2.0.1", "@types/sinon": "^17.0.2", "@types/urijs": "^1.19.20", - "@typescript-eslint/parser": "^6.20.0", + "@typescript-eslint/parser": "^7.7.1", "ava": "^5.3.1", "axios-mock-adapter": "^1.22.0", "babel-loader": "^9.1.3", diff --git a/src/contract_client/client.ts b/src/contract_client/client.ts index 2446e3e3b..1fa0f2f9a 100644 --- a/src/contract_client/client.ts +++ b/src/contract_client/client.ts @@ -1,6 +1,6 @@ -import { ContractSpec, xdr } from '..' -import { AssembledTransaction } from './assembled_transaction' -import type { ContractClientOptions, MethodOptions } from './types' +import { ContractSpec, xdr } from ".."; +import { AssembledTransaction } from "./assembled_transaction"; +import type { ContractClientOptions, MethodOptions } from "./types"; export class ContractClient { /** @@ -15,43 +15,46 @@ export class ContractClient { public readonly spec: ContractSpec, public readonly options: ContractClientOptions, ) { - let methods = this.spec.funcs(); - for (let method of methods) { - let name = method.name().toString(); - // @ts-ignore - this[name] = async ( - args: Record, - options: MethodOptions - ) => { - return await AssembledTransaction.build({ - method: name, - args: spec.funcArgsToScVals(name, args), + this.spec.funcs().forEach((xdrFn) => { + const method = xdrFn.name().toString(); + const assembleTransaction = ( + args?: Record, + methodOptions?: MethodOptions, + ) => + AssembledTransaction.build({ + method, + args: args && spec.funcArgsToScVals(method, args), ...options, - ...this.options, - errorTypes: spec - .errorCases() - .reduce( - (acc, curr) => ({ - ...acc, - [curr.value()]: { message: curr.doc().toString() }, - }), - {} as Pick - ), - parseResultXdr: (result: xdr.ScVal) => spec.funcResToNative(name, result), + ...methodOptions, + errorTypes: spec.errorCases().reduce( + (acc, curr) => ({ + ...acc, + [curr.value()]: { message: curr.doc().toString() }, + }), + {} as Pick, + ), + parseResultXdr: (result: xdr.ScVal) => + spec.funcResToNative(method, result), }); - }; - } + + // @ts-ignore error TS7053: Element implicitly has an 'any' type + this[method] = + spec.getFunc(method).inputs().length === 0 + ? (opts?: MethodOptions) => assembleTransaction(undefined, opts) + : assembleTransaction; + }); } txFromJSON = (json: string): AssembledTransaction => { - const { method, ...tx } = JSON.parse(json) + const { method, ...tx } = JSON.parse(json); return AssembledTransaction.fromJSON( { ...this.options, method, - parseResultXdr: (result: xdr.ScVal) => this.spec.funcResToNative(method, result), + parseResultXdr: (result: xdr.ScVal) => + this.spec.funcResToNative(method, result), }, tx, ); - } + }; } diff --git a/test/e2e/src/test-hello-world.js b/test/e2e/src/test-hello-world.js index 738585373..fbd927be3 100644 --- a/test/e2e/src/test-hello-world.js +++ b/test/e2e/src/test-hello-world.js @@ -21,3 +21,10 @@ test("inc", async (t) => { t.is(startingBalance, 0) t.is((await client.get_count()).result, startingBalance + 1) }); + +test("options for methods with no arguments", async (t) => { + const { client } = await clientFor('helloWorld') + // check that options object is FIRST, no need to pass `undefined` for the first argument + const inc = await client.inc({ simulate: false }) + t.falsy(inc.simulation) +}); diff --git a/yarn.lock b/yarn.lock index b8e633ccf..d49a9ad05 100644 --- a/yarn.lock +++ b/yarn.lock @@ -65,15 +65,6 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/eslint-parser@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.24.1.tgz#e27eee93ed1d271637165ef3a86e2b9332395c32" - integrity sha512-d5guuzMlPeDfZIbpQ8+g1NaCNuAGBBGNECh0HVqz1sjOeVLh2CEaifuOysCH18URW6R7pqXINvf5PaR/dC6jLQ== - dependencies: - "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" - eslint-visitor-keys "^2.1.0" - semver "^6.3.1" - "@babel/eslint-plugin@^7.22.10": version "7.23.5" resolved "https://registry.yarnpkg.com/@babel/eslint-plugin/-/eslint-plugin-7.23.5.tgz#77d4703e9f83b81e9fc13382810372beb2f10f94" @@ -1255,13 +1246,6 @@ resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ== -"@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": - version "5.1.1-v1" - resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" - integrity sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg== - dependencies: - eslint-scope "5.1.1" - "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -1584,7 +1568,7 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/parser@^6.19.0", "@typescript-eslint/parser@^6.20.0": +"@typescript-eslint/parser@^6.19.0": version "6.21.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.21.0.tgz#af8fcf66feee2edc86bc5d1cf45e33b0630bf35b" integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== @@ -1595,6 +1579,17 @@ "@typescript-eslint/visitor-keys" "6.21.0" debug "^4.3.4" +"@typescript-eslint/parser@^7.7.1": + version "7.7.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.7.1.tgz#f940e9f291cdca40c46cb75916217d3a42d6ceea" + integrity sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw== + dependencies: + "@typescript-eslint/scope-manager" "7.7.1" + "@typescript-eslint/types" "7.7.1" + "@typescript-eslint/typescript-estree" "7.7.1" + "@typescript-eslint/visitor-keys" "7.7.1" + debug "^4.3.4" + "@typescript-eslint/scope-manager@6.21.0": version "6.21.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz#ea8a9bfc8f1504a6ac5d59a6df308d3a0630a2b1" @@ -1603,6 +1598,14 @@ "@typescript-eslint/types" "6.21.0" "@typescript-eslint/visitor-keys" "6.21.0" +"@typescript-eslint/scope-manager@7.7.1": + version "7.7.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz#07fe59686ca843f66e3e2b5c151522bc38effab2" + integrity sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA== + dependencies: + "@typescript-eslint/types" "7.7.1" + "@typescript-eslint/visitor-keys" "7.7.1" + "@typescript-eslint/type-utils@6.21.0": version "6.21.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz#6473281cfed4dacabe8004e8521cee0bd9d4c01e" @@ -1618,6 +1621,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== +"@typescript-eslint/types@7.7.1": + version "7.7.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.7.1.tgz#f903a651fb004c75add08e4e9e207f169d4b98d7" + integrity sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w== + "@typescript-eslint/typescript-estree@6.21.0", "@typescript-eslint/typescript-estree@^6.19.0": version "6.21.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz#c47ae7901db3b8bddc3ecd73daff2d0895688c46" @@ -1632,6 +1640,20 @@ semver "^7.5.4" ts-api-utils "^1.0.1" +"@typescript-eslint/typescript-estree@7.7.1": + version "7.7.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz#5cafde48fe390fe1c1b329b2ce0ba8a73c1e87b2" + integrity sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ== + dependencies: + "@typescript-eslint/types" "7.7.1" + "@typescript-eslint/visitor-keys" "7.7.1" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + "@typescript-eslint/utils@6.21.0", "@typescript-eslint/utils@^6.19.0": version "6.21.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.21.0.tgz#4714e7a6b39e773c1c8e97ec587f520840cd8134" @@ -1653,6 +1675,14 @@ "@typescript-eslint/types" "6.21.0" eslint-visitor-keys "^3.4.1" +"@typescript-eslint/visitor-keys@7.7.1": + version "7.7.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz#da2294796220bb0f3b4add5ecbb1b9c3f4f65798" + integrity sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw== + dependencies: + "@typescript-eslint/types" "7.7.1" + eslint-visitor-keys "^3.4.3" + "@ungap/structured-clone@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" @@ -3678,11 +3708,6 @@ eslint-visitor-keys@^1.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== -eslint-visitor-keys@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" @@ -5627,6 +5652,13 @@ minimatch@^5.0.1: dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.4: + version "9.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" @@ -6703,7 +6735,7 @@ schema-utils@^4.0.0, schema-utils@^4.2.0: ajv-formats "^2.1.1" ajv-keywords "^5.1.0" -"semver@2 >=2.2.1 || 3.x || 4 || 5 || 7", semver@^7.3.2, semver@^7.3.4, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: +"semver@2 >=2.2.1 || 3.x || 4 || 5 || 7", semver@^7.3.2, semver@^7.3.4, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0: version "7.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== @@ -7358,7 +7390,7 @@ tough-cookie@~2.5.0: psl "^1.1.28" punycode "^2.1.1" -ts-api-utils@^1.0.1: +ts-api-utils@^1.0.1, ts-api-utils@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==