@algorandfoundation/algokit-client-generator 3.0.6 → 4.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +4 -2
  2. package/cli.d.ts +6 -0
  3. package/cli.js +47 -16
  4. package/cli.js.map +1 -1
  5. package/cli.mjs +47 -17
  6. package/cli.mjs.map +1 -1
  7. package/client/{call-factory.d.ts → app-client.d.ts} +1 -1
  8. package/client/app-client.js +345 -0
  9. package/client/app-client.js.map +1 -0
  10. package/client/app-client.mjs +343 -0
  11. package/client/app-client.mjs.map +1 -0
  12. package/client/{call-client.d.ts → app-factory.d.ts} +1 -1
  13. package/client/app-factory.js +252 -0
  14. package/client/app-factory.js.map +1 -0
  15. package/client/app-factory.mjs +250 -0
  16. package/client/app-factory.mjs.map +1 -0
  17. package/client/app-types.js +206 -112
  18. package/client/app-types.js.map +1 -1
  19. package/client/app-types.mjs +210 -97
  20. package/client/app-types.mjs.map +1 -1
  21. package/client/call-composer-types.js +27 -57
  22. package/client/call-composer-types.js.map +1 -1
  23. package/client/call-composer-types.mjs +27 -38
  24. package/client/call-composer-types.mjs.map +1 -1
  25. package/client/call-composer.js +47 -59
  26. package/client/call-composer.js.map +1 -1
  27. package/client/call-composer.mjs +49 -42
  28. package/client/call-composer.mjs.map +1 -1
  29. package/client/deploy-types.d.ts +8 -4
  30. package/client/deploy-types.js +52 -34
  31. package/client/deploy-types.js.map +1 -1
  32. package/client/deploy-types.mjs +53 -36
  33. package/client/deploy-types.mjs.map +1 -1
  34. package/client/generate.d.ts +2 -2
  35. package/client/generate.js +18 -7
  36. package/client/generate.js.map +1 -1
  37. package/client/generate.mjs +18 -7
  38. package/client/generate.mjs.map +1 -1
  39. package/client/generator-context.d.ts +4 -4
  40. package/client/generator-context.js +5 -24
  41. package/client/generator-context.js.map +1 -1
  42. package/client/generator-context.mjs +5 -5
  43. package/client/generator-context.mjs.map +1 -1
  44. package/client/helpers/get-call-config-summary.d.ts +8 -3
  45. package/client/helpers/get-call-config-summary.js +22 -20
  46. package/client/helpers/get-call-config-summary.js.map +1 -1
  47. package/client/helpers/get-call-config-summary.mjs +22 -20
  48. package/client/helpers/get-call-config-summary.mjs.map +1 -1
  49. package/client/helpers/get-equivalent-type.d.ts +6 -1
  50. package/client/helpers/get-equivalent-type.js +20 -10
  51. package/client/helpers/get-equivalent-type.js.map +1 -1
  52. package/client/helpers/get-equivalent-type.mjs +20 -10
  53. package/client/helpers/get-equivalent-type.mjs.map +1 -1
  54. package/client/imports.js +21 -24
  55. package/client/imports.js.map +1 -1
  56. package/client/imports.mjs +21 -24
  57. package/client/imports.mjs.map +1 -1
  58. package/client/params-factory.d.ts +3 -0
  59. package/client/params-factory.js +126 -0
  60. package/client/params-factory.js.map +1 -0
  61. package/client/params-factory.mjs +124 -0
  62. package/client/params-factory.mjs.map +1 -0
  63. package/client/utility-types.d.ts +0 -7
  64. package/client/utility-types.js +37 -50
  65. package/client/utility-types.js.map +1 -1
  66. package/client/utility-types.mjs +38 -50
  67. package/client/utility-types.mjs.map +1 -1
  68. package/output/writer.d.ts +5 -5
  69. package/output/writer.js +26 -6
  70. package/output/writer.js.map +1 -1
  71. package/output/writer.mjs +26 -6
  72. package/output/writer.mjs.map +1 -1
  73. package/package.json +7 -5
  74. package/schema/application.schema.json.js +2 -2
  75. package/schema/application.schema.json.mjs +2 -2
  76. package/schema/arc56.schema.json.js +751 -0
  77. package/schema/arc56.schema.json.js.map +1 -0
  78. package/schema/arc56.schema.json.mjs +741 -0
  79. package/schema/arc56.schema.json.mjs.map +1 -0
  80. package/schema/load.d.ts +3 -3
  81. package/schema/load.js +28 -8
  82. package/schema/load.js.map +1 -1
  83. package/schema/load.mjs +29 -9
  84. package/schema/load.mjs.map +1 -1
  85. package/util/sanitization.js +13 -8
  86. package/util/sanitization.js.map +1 -1
  87. package/util/sanitization.mjs +13 -8
  88. package/util/sanitization.mjs.map +1 -1
  89. package/client/call-client.js +0 -341
  90. package/client/call-client.js.map +0 -1
  91. package/client/call-client.mjs +0 -320
  92. package/client/call-client.mjs.map +0 -1
  93. package/client/call-factory.js +0 -142
  94. package/client/call-factory.js.map +0 -1
  95. package/client/call-factory.mjs +0 -121
  96. package/client/call-factory.mjs.map +0 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # AlgoKit TypeScript client generator (algokit-client-generator-ts)
2
2
 
3
- This project generates a type-safe smart contract client in TypeScript for the Algorand Blockchain that wraps the [application client](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/docs/capabilities/app-client.md) in [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-ts) and tailors it to a specific smart contract. It does this by reading an [ARC-0032](https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0032.md) application spec file and generating a client which exposes methods for each ABI method in the target smart contract, along with helpers to create, update, and delete the application.
3
+ This project generates a type-safe smart contract client in TypeScript for the Algorand Blockchain that wraps the [application client](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/docs/capabilities/app-client.md) in [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-ts) and tailors it to a specific smart contract. It does this by reading an [ARC-56](https://github.com/algorandfoundation/ARCs/pull/258) or [ARC-32](https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0032.md) application spec file and generating a client which exposes methods for each ABI method in the target smart contract, along with helpers to create, update, and delete the application.
4
4
 
5
5
  ## Usage
6
6
 
@@ -12,6 +12,8 @@ To be able to consume the generated file you need to include it in a TypeScript
12
12
  npm install @algorandfoundation/algokit-utils
13
13
  ```
14
14
 
15
+ Note: you need at least version 7 of AlgoKit Utils to work with the latest version of the generator. It currently only works with algosdk v2.
16
+
15
17
  ### Use
16
18
 
17
19
  The cli can be used to generate a client via the following command.
@@ -48,7 +50,7 @@ For details on how to use the generated client see the more detailed [usage docs
48
50
 
49
51
  ## Examples
50
52
 
51
- There are a range of [examples](./examples) that you can look at to see a source smart contract (`{contract.py}`), the generated client (`client.ts`) and some tests that demonstrate how you can use the client (`client.spec.ts`).
53
+ There are a range of [examples](./examples) that you can look at to see a source smart contract (e.g. `{contract.py}`), the generated client (`client.ts`) and some tests that demonstrate how you can use the client (`client.spec.ts`).
52
54
 
53
55
  ## Contributing
54
56
 
package/cli.d.ts CHANGED
@@ -1 +1,7 @@
1
1
  export declare function cli(workingDirectory: string, args: string[]): void;
2
+ export declare function generateClientCommand({ application, output, preserveNames, workingDirectory, }: {
3
+ application: string;
4
+ output: string;
5
+ preserveNames: boolean;
6
+ workingDirectory: string;
7
+ }): Promise<void>;
package/cli.js CHANGED
@@ -35,23 +35,12 @@ function cli(workingDirectory, args) {
35
35
  .requiredOption('-o --output <path>', 'Specifies the output file path')
36
36
  .option('-pn --preserve-names', 'Preserve names from application.json spec instead of sanitizing them')
37
37
  .action(async ({ application, output, preserveNames }) => {
38
- const fs = await import('fs');
39
- const resolvedAppJsonPath = path__namespace.resolve(workingDirectory, application);
40
- const resolvedOutPath = path__namespace.resolve(workingDirectory, output);
41
- const resolvedOutDir = path__namespace.dirname(resolvedOutPath);
42
- colorConsole.colorConsole.info `Reading application.json file from path ${resolvedAppJsonPath}`;
43
- const spec = await load.loadApplicationJson(resolvedAppJsonPath);
44
- colorConsole.colorConsole.info `Generating TS client for ${spec.contract.name}`;
45
- const parts = generate.generate(spec, { preserveNames: Boolean(preserveNames) });
46
- if (!fs.existsSync(resolvedOutDir)) {
47
- colorConsole.colorConsole.warn `Output directory ${resolvedOutDir} does not exist and will be created.`;
48
- fs.mkdirSync(resolvedOutDir, { recursive: true });
49
- }
50
- colorConsole.colorConsole.info `Writing TS client to ${resolvedOutPath}`;
51
- const file = fs.createWriteStream(resolvedOutPath, {
52
- flags: 'w',
38
+ await generateClientCommand({
39
+ application,
40
+ output,
41
+ preserveNames: Boolean(preserveNames),
42
+ workingDirectory,
53
43
  });
54
- writer.writeDocumentPartsToStream(parts, file);
55
44
  colorConsole.colorConsole.success `Operation completed successfully`;
56
45
  })
57
46
  .configureOutput({
@@ -72,6 +61,48 @@ function cli(workingDirectory, args) {
72
61
  process.exit(-1);
73
62
  }
74
63
  }
64
+ async function generateClientCommand({ application, output, preserveNames, workingDirectory, }) {
65
+ const fs = await import('fs');
66
+ const resolvedAppJsonPath = path__namespace.resolve(workingDirectory, application);
67
+ const resolvedOutPath = path__namespace.resolve(workingDirectory, output);
68
+ const resolvedOutDir = path__namespace.dirname(resolvedOutPath);
69
+ colorConsole.colorConsole.info `Reading application.json file from path ${resolvedAppJsonPath}`;
70
+ const spec = await load.loadApplicationJson(resolvedAppJsonPath);
71
+ colorConsole.colorConsole.info `Generating TS client for ${spec.name}`;
72
+ const parts = generate.generate(spec, { preserveNames });
73
+ if (!fs.existsSync(resolvedOutDir)) {
74
+ colorConsole.colorConsole.warn `Output directory ${resolvedOutDir} does not exist and will be created.`;
75
+ fs.mkdirSync(resolvedOutDir, { recursive: true });
76
+ }
77
+ colorConsole.colorConsole.info `Writing TS client to ${resolvedOutPath}`;
78
+ const file = await createAwaitableWriteStream(resolvedOutPath);
79
+ writer.writeDocumentPartsToStream(parts, file);
80
+ await file.finish();
81
+ }
82
+ async function createAwaitableWriteStream(path) {
83
+ const fs = await import('fs');
84
+ const stream = fs.createWriteStream(path, {
85
+ flags: 'w',
86
+ });
87
+ const finish = new Promise((resolve, reject) => {
88
+ stream.on('error', (err) => {
89
+ reject(err);
90
+ });
91
+ stream.on('finish', () => {
92
+ resolve();
93
+ });
94
+ });
95
+ return {
96
+ write(chunk) {
97
+ stream.write(chunk);
98
+ },
99
+ finish() {
100
+ stream.end();
101
+ return finish;
102
+ },
103
+ };
104
+ }
75
105
 
76
106
  exports.cli = cli;
107
+ exports.generateClientCommand = generateClientCommand;
77
108
  //# sourceMappingURL=cli.js.map
package/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sources":["../src/cli.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { loadApplicationJson } from './schema/load'\nimport * as path from 'path'\nimport { generate } from './client/generate'\nimport { writeDocumentPartsToStream } from './output/writer'\nimport { colorConsole } from './util/color-console'\n\nexport function cli(workingDirectory: string, args: string[]) {\n const program = new Command()\n program\n .command('generate')\n .description('Generates a TypeScript client for the given application.json file')\n .requiredOption('-a --application <path>', 'Specifies the application.json file')\n .requiredOption('-o --output <path>', 'Specifies the output file path')\n .option('-pn --preserve-names', 'Preserve names from application.json spec instead of sanitizing them')\n .action(\n async ({ application, output, preserveNames }: { application: string; output: string; preserveNames?: boolean }): Promise<void> => {\n const fs = await import('fs')\n const resolvedAppJsonPath = path.resolve(workingDirectory, application)\n const resolvedOutPath = path.resolve(workingDirectory, output)\n const resolvedOutDir = path.dirname(resolvedOutPath)\n colorConsole.info`Reading application.json file from path ${resolvedAppJsonPath}`\n const spec = await loadApplicationJson(resolvedAppJsonPath)\n colorConsole.info`Generating TS client for ${spec.contract.name}`\n const parts = generate(spec, { preserveNames: Boolean(preserveNames) })\n if (!fs.existsSync(resolvedOutDir)) {\n colorConsole.warn`Output directory ${resolvedOutDir} does not exist and will be created.`\n fs.mkdirSync(resolvedOutDir, { recursive: true })\n }\n colorConsole.info`Writing TS client to ${resolvedOutPath}`\n const file = fs.createWriteStream(resolvedOutPath, {\n flags: 'w',\n })\n writeDocumentPartsToStream(parts, file)\n colorConsole.success`Operation completed successfully`\n },\n )\n .configureOutput({\n writeErr(str: string) {\n colorConsole.error`${str}`\n },\n })\n try {\n program.parse(args)\n } catch (err) {\n if (err instanceof Error) {\n colorConsole.error`Unhandled error: \\n\\n${err.stack}`\n } else {\n colorConsole.error`Unhandled error: \\n\\n${err}`\n }\n process.exit(-1)\n }\n}\n"],"names":["Command","path","colorConsole","loadApplicationJson","generate","writeDocumentPartsToStream"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOgB,SAAA,GAAG,CAAC,gBAAwB,EAAE,IAAc,EAAA;AAC1D,IAAA,MAAM,OAAO,GAAG,IAAIA,iBAAO,EAAE,CAAA;IAC7B,OAAO;SACJ,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,mEAAmE,CAAC;AAChF,SAAA,cAAc,CAAC,yBAAyB,EAAE,qCAAqC,CAAC;AAChF,SAAA,cAAc,CAAC,oBAAoB,EAAE,gCAAgC,CAAC;AACtE,SAAA,MAAM,CAAC,sBAAsB,EAAE,sEAAsE,CAAC;SACtG,MAAM,CACL,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAoE,KAAmB;AAChI,QAAA,MAAM,EAAE,GAAG,MAAM,OAAO,IAAI,CAAC,CAAA;QAC7B,MAAM,mBAAmB,GAAGC,eAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAA;QACvE,MAAM,eAAe,GAAGA,eAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAA;QAC9D,MAAM,cAAc,GAAGA,eAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAA;AACpD,QAAAC,yBAAY,CAAC,IAAI,CAAA,CAA2C,wCAAA,EAAA,mBAAmB,EAAE,CAAA;AACjF,QAAA,MAAM,IAAI,GAAG,MAAMC,wBAAmB,CAAC,mBAAmB,CAAC,CAAA;QAC3DD,yBAAY,CAAC,IAAI,CAAA,CAA4B,yBAAA,EAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAA,CAAE,CAAA;AACjE,QAAA,MAAM,KAAK,GAAGE,iBAAQ,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC,CAAA;QACvE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE;AAClC,YAAAF,yBAAY,CAAC,IAAI,CAAA,CAAoB,iBAAA,EAAA,cAAc,sCAAsC,CAAA;YACzF,EAAE,CAAC,SAAS,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;SAClD;AACD,QAAAA,yBAAY,CAAC,IAAI,CAAA,CAAwB,qBAAA,EAAA,eAAe,EAAE,CAAA;AAC1D,QAAA,MAAM,IAAI,GAAG,EAAE,CAAC,iBAAiB,CAAC,eAAe,EAAE;AACjD,YAAA,KAAK,EAAE,GAAG;AACX,SAAA,CAAC,CAAA;AACF,QAAAG,iCAA0B,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;AACvC,QAAAH,yBAAY,CAAC,OAAO,CAAA,CAAA,gCAAA,CAAkC,CAAA;AACxD,KAAC,CACF;AACA,SAAA,eAAe,CAAC;AACf,QAAA,QAAQ,CAAC,GAAW,EAAA;AAClB,YAAAA,yBAAY,CAAC,KAAK,CAAA,CAAG,EAAA,GAAG,EAAE,CAAA;SAC3B;AACF,KAAA,CAAC,CAAA;AACJ,IAAA,IAAI;AACF,QAAA,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;KACpB;IAAC,OAAO,GAAG,EAAE;AACZ,QAAA,IAAI,GAAG,YAAY,KAAK,EAAE;YACxBA,yBAAY,CAAC,KAAK,CAAA,CAAA,qBAAA,EAAwB,GAAG,CAAC,KAAK,EAAE,CAAA;SACtD;aAAM;AACL,YAAAA,yBAAY,CAAC,KAAK,CAAA,CAAwB,qBAAA,EAAA,GAAG,EAAE,CAAA;SAChD;AACD,QAAA,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;KACjB;AACH;;;;"}
1
+ {"version":3,"file":"cli.js","sources":["../src/cli.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { loadApplicationJson } from './schema/load'\nimport * as path from 'path'\nimport { generate } from './client/generate'\nimport { writeDocumentPartsToStream } from './output/writer'\nimport { colorConsole } from './util/color-console'\n\nexport function cli(workingDirectory: string, args: string[]) {\n const program = new Command()\n program\n .command('generate')\n .description('Generates a TypeScript client for the given application.json file')\n .requiredOption('-a --application <path>', 'Specifies the application.json file')\n .requiredOption('-o --output <path>', 'Specifies the output file path')\n .option('-pn --preserve-names', 'Preserve names from application.json spec instead of sanitizing them')\n .action(\n async ({ application, output, preserveNames }: { application: string; output: string; preserveNames?: boolean }): Promise<void> => {\n await generateClientCommand({\n application,\n output,\n preserveNames: Boolean(preserveNames),\n workingDirectory,\n })\n colorConsole.success`Operation completed successfully`\n },\n )\n .configureOutput({\n writeErr(str: string) {\n colorConsole.error`${str}`\n },\n })\n try {\n program.parse(args)\n } catch (err) {\n if (err instanceof Error) {\n colorConsole.error`Unhandled error: \\n\\n${err.stack}`\n } else {\n colorConsole.error`Unhandled error: \\n\\n${err}`\n }\n process.exit(-1)\n }\n}\n\nexport async function generateClientCommand({\n application,\n output,\n preserveNames,\n workingDirectory,\n}: {\n application: string\n output: string\n preserveNames: boolean\n workingDirectory: string\n}) {\n const fs = await import('fs')\n\n const resolvedAppJsonPath = path.resolve(workingDirectory, application)\n const resolvedOutPath = path.resolve(workingDirectory, output)\n const resolvedOutDir = path.dirname(resolvedOutPath)\n colorConsole.info`Reading application.json file from path ${resolvedAppJsonPath}`\n const spec = await loadApplicationJson(resolvedAppJsonPath)\n colorConsole.info`Generating TS client for ${spec.name}`\n const parts = generate(spec, { preserveNames })\n if (!fs.existsSync(resolvedOutDir)) {\n colorConsole.warn`Output directory ${resolvedOutDir} does not exist and will be created.`\n fs.mkdirSync(resolvedOutDir, { recursive: true })\n }\n colorConsole.info`Writing TS client to ${resolvedOutPath}`\n const file = await createAwaitableWriteStream(resolvedOutPath)\n writeDocumentPartsToStream(parts, file)\n await file.finish()\n}\n\nasync function createAwaitableWriteStream(path: string) {\n const fs = await import('fs')\n const stream = fs.createWriteStream(path, {\n flags: 'w',\n })\n const finish = new Promise<void>((resolve, reject) => {\n stream.on('error', (err) => {\n reject(err)\n })\n stream.on('finish', () => {\n resolve()\n })\n })\n return {\n write(chunk: string): void {\n stream.write(chunk)\n },\n finish() {\n stream.end()\n return finish\n },\n }\n}\n"],"names":["Command","colorConsole","path","loadApplicationJson","generate","writeDocumentPartsToStream"],"mappings":"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"}
package/cli.mjs CHANGED
@@ -14,23 +14,12 @@ function cli(workingDirectory, args) {
14
14
  .requiredOption('-o --output <path>', 'Specifies the output file path')
15
15
  .option('-pn --preserve-names', 'Preserve names from application.json spec instead of sanitizing them')
16
16
  .action(async ({ application, output, preserveNames }) => {
17
- const fs = await import('fs');
18
- const resolvedAppJsonPath = path.resolve(workingDirectory, application);
19
- const resolvedOutPath = path.resolve(workingDirectory, output);
20
- const resolvedOutDir = path.dirname(resolvedOutPath);
21
- colorConsole.info `Reading application.json file from path ${resolvedAppJsonPath}`;
22
- const spec = await loadApplicationJson(resolvedAppJsonPath);
23
- colorConsole.info `Generating TS client for ${spec.contract.name}`;
24
- const parts = generate(spec, { preserveNames: Boolean(preserveNames) });
25
- if (!fs.existsSync(resolvedOutDir)) {
26
- colorConsole.warn `Output directory ${resolvedOutDir} does not exist and will be created.`;
27
- fs.mkdirSync(resolvedOutDir, { recursive: true });
28
- }
29
- colorConsole.info `Writing TS client to ${resolvedOutPath}`;
30
- const file = fs.createWriteStream(resolvedOutPath, {
31
- flags: 'w',
17
+ await generateClientCommand({
18
+ application,
19
+ output,
20
+ preserveNames: Boolean(preserveNames),
21
+ workingDirectory,
32
22
  });
33
- writeDocumentPartsToStream(parts, file);
34
23
  colorConsole.success `Operation completed successfully`;
35
24
  })
36
25
  .configureOutput({
@@ -51,6 +40,47 @@ function cli(workingDirectory, args) {
51
40
  process.exit(-1);
52
41
  }
53
42
  }
43
+ async function generateClientCommand({ application, output, preserveNames, workingDirectory, }) {
44
+ const fs = await import('fs');
45
+ const resolvedAppJsonPath = path.resolve(workingDirectory, application);
46
+ const resolvedOutPath = path.resolve(workingDirectory, output);
47
+ const resolvedOutDir = path.dirname(resolvedOutPath);
48
+ colorConsole.info `Reading application.json file from path ${resolvedAppJsonPath}`;
49
+ const spec = await loadApplicationJson(resolvedAppJsonPath);
50
+ colorConsole.info `Generating TS client for ${spec.name}`;
51
+ const parts = generate(spec, { preserveNames });
52
+ if (!fs.existsSync(resolvedOutDir)) {
53
+ colorConsole.warn `Output directory ${resolvedOutDir} does not exist and will be created.`;
54
+ fs.mkdirSync(resolvedOutDir, { recursive: true });
55
+ }
56
+ colorConsole.info `Writing TS client to ${resolvedOutPath}`;
57
+ const file = await createAwaitableWriteStream(resolvedOutPath);
58
+ writeDocumentPartsToStream(parts, file);
59
+ await file.finish();
60
+ }
61
+ async function createAwaitableWriteStream(path) {
62
+ const fs = await import('fs');
63
+ const stream = fs.createWriteStream(path, {
64
+ flags: 'w',
65
+ });
66
+ const finish = new Promise((resolve, reject) => {
67
+ stream.on('error', (err) => {
68
+ reject(err);
69
+ });
70
+ stream.on('finish', () => {
71
+ resolve();
72
+ });
73
+ });
74
+ return {
75
+ write(chunk) {
76
+ stream.write(chunk);
77
+ },
78
+ finish() {
79
+ stream.end();
80
+ return finish;
81
+ },
82
+ };
83
+ }
54
84
 
55
- export { cli };
85
+ export { cli, generateClientCommand };
56
86
  //# sourceMappingURL=cli.mjs.map
package/cli.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","sources":["../src/cli.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { loadApplicationJson } from './schema/load'\nimport * as path from 'path'\nimport { generate } from './client/generate'\nimport { writeDocumentPartsToStream } from './output/writer'\nimport { colorConsole } from './util/color-console'\n\nexport function cli(workingDirectory: string, args: string[]) {\n const program = new Command()\n program\n .command('generate')\n .description('Generates a TypeScript client for the given application.json file')\n .requiredOption('-a --application <path>', 'Specifies the application.json file')\n .requiredOption('-o --output <path>', 'Specifies the output file path')\n .option('-pn --preserve-names', 'Preserve names from application.json spec instead of sanitizing them')\n .action(\n async ({ application, output, preserveNames }: { application: string; output: string; preserveNames?: boolean }): Promise<void> => {\n const fs = await import('fs')\n const resolvedAppJsonPath = path.resolve(workingDirectory, application)\n const resolvedOutPath = path.resolve(workingDirectory, output)\n const resolvedOutDir = path.dirname(resolvedOutPath)\n colorConsole.info`Reading application.json file from path ${resolvedAppJsonPath}`\n const spec = await loadApplicationJson(resolvedAppJsonPath)\n colorConsole.info`Generating TS client for ${spec.contract.name}`\n const parts = generate(spec, { preserveNames: Boolean(preserveNames) })\n if (!fs.existsSync(resolvedOutDir)) {\n colorConsole.warn`Output directory ${resolvedOutDir} does not exist and will be created.`\n fs.mkdirSync(resolvedOutDir, { recursive: true })\n }\n colorConsole.info`Writing TS client to ${resolvedOutPath}`\n const file = fs.createWriteStream(resolvedOutPath, {\n flags: 'w',\n })\n writeDocumentPartsToStream(parts, file)\n colorConsole.success`Operation completed successfully`\n },\n )\n .configureOutput({\n writeErr(str: string) {\n colorConsole.error`${str}`\n },\n })\n try {\n program.parse(args)\n } catch (err) {\n if (err instanceof Error) {\n colorConsole.error`Unhandled error: \\n\\n${err.stack}`\n } else {\n colorConsole.error`Unhandled error: \\n\\n${err}`\n }\n process.exit(-1)\n }\n}\n"],"names":[],"mappings":";;;;;;;AAOgB,SAAA,GAAG,CAAC,gBAAwB,EAAE,IAAc,EAAA;AAC1D,IAAA,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;IAC7B,OAAO;SACJ,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,mEAAmE,CAAC;AAChF,SAAA,cAAc,CAAC,yBAAyB,EAAE,qCAAqC,CAAC;AAChF,SAAA,cAAc,CAAC,oBAAoB,EAAE,gCAAgC,CAAC;AACtE,SAAA,MAAM,CAAC,sBAAsB,EAAE,sEAAsE,CAAC;SACtG,MAAM,CACL,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAoE,KAAmB;AAChI,QAAA,MAAM,EAAE,GAAG,MAAM,OAAO,IAAI,CAAC,CAAA;QAC7B,MAAM,mBAAmB,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAA;QACvE,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAA;QAC9D,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAA;AACpD,QAAA,YAAY,CAAC,IAAI,CAAA,CAA2C,wCAAA,EAAA,mBAAmB,EAAE,CAAA;AACjF,QAAA,MAAM,IAAI,GAAG,MAAM,mBAAmB,CAAC,mBAAmB,CAAC,CAAA;QAC3D,YAAY,CAAC,IAAI,CAAA,CAA4B,yBAAA,EAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAA,CAAE,CAAA;AACjE,QAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC,CAAA;QACvE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE;AAClC,YAAA,YAAY,CAAC,IAAI,CAAA,CAAoB,iBAAA,EAAA,cAAc,sCAAsC,CAAA;YACzF,EAAE,CAAC,SAAS,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;SAClD;AACD,QAAA,YAAY,CAAC,IAAI,CAAA,CAAwB,qBAAA,EAAA,eAAe,EAAE,CAAA;AAC1D,QAAA,MAAM,IAAI,GAAG,EAAE,CAAC,iBAAiB,CAAC,eAAe,EAAE;AACjD,YAAA,KAAK,EAAE,GAAG;AACX,SAAA,CAAC,CAAA;AACF,QAAA,0BAA0B,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;AACvC,QAAA,YAAY,CAAC,OAAO,CAAA,CAAA,gCAAA,CAAkC,CAAA;AACxD,KAAC,CACF;AACA,SAAA,eAAe,CAAC;AACf,QAAA,QAAQ,CAAC,GAAW,EAAA;AAClB,YAAA,YAAY,CAAC,KAAK,CAAA,CAAG,EAAA,GAAG,EAAE,CAAA;SAC3B;AACF,KAAA,CAAC,CAAA;AACJ,IAAA,IAAI;AACF,QAAA,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;KACpB;IAAC,OAAO,GAAG,EAAE;AACZ,QAAA,IAAI,GAAG,YAAY,KAAK,EAAE;YACxB,YAAY,CAAC,KAAK,CAAA,CAAA,qBAAA,EAAwB,GAAG,CAAC,KAAK,EAAE,CAAA;SACtD;aAAM;AACL,YAAA,YAAY,CAAC,KAAK,CAAA,CAAwB,qBAAA,EAAA,GAAG,EAAE,CAAA;SAChD;AACD,QAAA,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;KACjB;AACH;;;;"}
1
+ {"version":3,"file":"cli.mjs","sources":["../src/cli.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { loadApplicationJson } from './schema/load'\nimport * as path from 'path'\nimport { generate } from './client/generate'\nimport { writeDocumentPartsToStream } from './output/writer'\nimport { colorConsole } from './util/color-console'\n\nexport function cli(workingDirectory: string, args: string[]) {\n const program = new Command()\n program\n .command('generate')\n .description('Generates a TypeScript client for the given application.json file')\n .requiredOption('-a --application <path>', 'Specifies the application.json file')\n .requiredOption('-o --output <path>', 'Specifies the output file path')\n .option('-pn --preserve-names', 'Preserve names from application.json spec instead of sanitizing them')\n .action(\n async ({ application, output, preserveNames }: { application: string; output: string; preserveNames?: boolean }): Promise<void> => {\n await generateClientCommand({\n application,\n output,\n preserveNames: Boolean(preserveNames),\n workingDirectory,\n })\n colorConsole.success`Operation completed successfully`\n },\n )\n .configureOutput({\n writeErr(str: string) {\n colorConsole.error`${str}`\n },\n })\n try {\n program.parse(args)\n } catch (err) {\n if (err instanceof Error) {\n colorConsole.error`Unhandled error: \\n\\n${err.stack}`\n } else {\n colorConsole.error`Unhandled error: \\n\\n${err}`\n }\n process.exit(-1)\n }\n}\n\nexport async function generateClientCommand({\n application,\n output,\n preserveNames,\n workingDirectory,\n}: {\n application: string\n output: string\n preserveNames: boolean\n workingDirectory: string\n}) {\n const fs = await import('fs')\n\n const resolvedAppJsonPath = path.resolve(workingDirectory, application)\n const resolvedOutPath = path.resolve(workingDirectory, output)\n const resolvedOutDir = path.dirname(resolvedOutPath)\n colorConsole.info`Reading application.json file from path ${resolvedAppJsonPath}`\n const spec = await loadApplicationJson(resolvedAppJsonPath)\n colorConsole.info`Generating TS client for ${spec.name}`\n const parts = generate(spec, { preserveNames })\n if (!fs.existsSync(resolvedOutDir)) {\n colorConsole.warn`Output directory ${resolvedOutDir} does not exist and will be created.`\n fs.mkdirSync(resolvedOutDir, { recursive: true })\n }\n colorConsole.info`Writing TS client to ${resolvedOutPath}`\n const file = await createAwaitableWriteStream(resolvedOutPath)\n writeDocumentPartsToStream(parts, file)\n await file.finish()\n}\n\nasync function createAwaitableWriteStream(path: string) {\n const fs = await import('fs')\n const stream = fs.createWriteStream(path, {\n flags: 'w',\n })\n const finish = new Promise<void>((resolve, reject) => {\n stream.on('error', (err) => {\n reject(err)\n })\n stream.on('finish', () => {\n resolve()\n })\n })\n return {\n write(chunk: string): void {\n stream.write(chunk)\n },\n finish() {\n stream.end()\n return finish\n },\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1,3 +1,3 @@
1
1
  import { DocumentParts } from '../output/writer';
2
2
  import { GeneratorContext } from './generator-context';
3
- export declare function callFactory(ctx: GeneratorContext): DocumentParts;
3
+ export declare function appClient(ctx: GeneratorContext): DocumentParts;
@@ -0,0 +1,345 @@
1
+ 'use strict';
2
+
3
+ var writer = require('../output/writer.js');
4
+ var getCallConfigSummary = require('./helpers/get-call-config-summary.js');
5
+ var deployTypes = require('./deploy-types.js');
6
+ var callComposer = require('./call-composer.js');
7
+ var algosdk = require('algosdk');
8
+ var getEquivalentType = require('./helpers/get-equivalent-type.js');
9
+
10
+ function* appClient(ctx) {
11
+ const { app, name } = ctx;
12
+ yield* writer.jsDoc(`A client to make calls to the ${app.name} smart contract`);
13
+ yield `export class ${name}Client {`;
14
+ yield writer.IncIndent;
15
+ yield* writer.jsDoc(`The underlying \`AppClient\` for when you want to have more flexibility`);
16
+ yield 'public readonly appClient: AppClient';
17
+ yield writer.NewLine;
18
+ yield `
19
+ /**
20
+ * Creates a new instance of \`${name}Client\`
21
+ *
22
+ * @param appClient An \`AppClient\` instance which has been created with the ${name} app spec
23
+ */
24
+ constructor(appClient: AppClient)
25
+ /**
26
+ * Creates a new instance of \`${name}Client\`
27
+ *
28
+ * @param params The parameters to initialise the app client with
29
+ */
30
+ constructor(params: Omit<AppClientParams, 'appSpec'>)
31
+ constructor(appClientOrParams: AppClient | Omit<AppClientParams, 'appSpec'>) {
32
+ this.appClient = appClientOrParams instanceof AppClient ? appClientOrParams : new AppClient({
33
+ ...appClientOrParams,
34
+ appSpec: APP_SPEC,
35
+ })
36
+ }
37
+
38
+ /**
39
+ * Checks for decode errors on the given return value and maps the return value to the return type for the given method
40
+ * @returns The typed return value or undefined if there was no value
41
+ */
42
+ decodeReturnValue<TSignature extends ${name}NonVoidMethodSignatures>(method: TSignature, returnValue: ABIReturn | undefined) {
43
+ return returnValue !== undefined ? getArc56ReturnValue<MethodReturn<TSignature>>(returnValue, this.appClient.getABIMethod(method), APP_SPEC.structs) : undefined
44
+ }
45
+
46
+ /**
47
+ * Returns a new \`${name}Client\` client, resolving the app by creator address and name
48
+ * using AlgoKit app deployment semantics (i.e. looking for the app creation transaction note).
49
+ * @param params The parameters to create the app client
50
+ */
51
+ public static async fromCreatorAndName(params: Omit<ResolveAppClientByCreatorAndName, 'appSpec'>): Promise<${name}Client> {
52
+ return new ${name}Client(await AppClient.fromCreatorAndName({...params, appSpec: APP_SPEC}))
53
+ }
54
+
55
+ /**
56
+ * Returns an \`${name}Client\` instance for the current network based on
57
+ * pre-determined network-specific app IDs specified in the ARC-56 app spec.
58
+ *
59
+ * If no IDs are in the app spec or the network isn't recognised, an error is thrown.
60
+ * @param params The parameters to create the app client
61
+ */
62
+ static async fromNetwork(
63
+ params: Omit<ResolveAppClientByNetwork, 'appSpec'>
64
+ ): Promise<${name}Client> {
65
+ return new ${name}Client(await AppClient.fromNetwork({...params, appSpec: APP_SPEC}))
66
+ }
67
+
68
+ /** The ID of the app instance this client is linked to. */
69
+ public get appId() {
70
+ return this.appClient.appId
71
+ }
72
+
73
+ /** The app address of the app instance this client is linked to. */
74
+ public get appAddress() {
75
+ return this.appClient.appAddress
76
+ }
77
+
78
+ /** The name of the app. */
79
+ public get appName() {
80
+ return this.appClient.appName
81
+ }
82
+
83
+ /** The ARC-56 app spec being used */
84
+ public get appSpec() {
85
+ return this.appClient.appSpec
86
+ }
87
+
88
+ /** A reference to the underlying \`AlgorandClient\` this app client is using. */
89
+ public get algorand(): AlgorandClientInterface {
90
+ return this.appClient.algorand
91
+ }
92
+
93
+ `;
94
+ yield* params(ctx);
95
+ yield* createTransaction(ctx);
96
+ yield* send(ctx);
97
+ yield* cloneMethod(ctx);
98
+ yield* readonlyMethods(ctx);
99
+ yield* getStateMethods(ctx);
100
+ yield* callComposer.composeMethod(ctx);
101
+ yield writer.DecIndentAndCloseBlock;
102
+ }
103
+ function* params(ctx) {
104
+ yield* writer.jsDoc(`Get parameters to create transactions for the current app. A good mental model for this is that these parameters represent a deferred transaction creation.`);
105
+ yield `readonly params = {`;
106
+ yield writer.IncIndent;
107
+ yield* opMethods(ctx, 'params');
108
+ yield* clearState(ctx, 'params');
109
+ yield* call(ctx, 'params');
110
+ yield* noopMethods(ctx, 'params');
111
+ yield writer.DecIndentAndCloseBlock;
112
+ yield writer.NewLine;
113
+ }
114
+ function* createTransaction(ctx) {
115
+ yield* writer.jsDoc(`Create transactions for the current app`);
116
+ yield `readonly createTransaction = {`;
117
+ yield writer.IncIndent;
118
+ yield* opMethods(ctx, 'createTransaction');
119
+ yield* clearState(ctx, 'createTransaction');
120
+ yield* call(ctx, 'createTransaction');
121
+ yield* noopMethods(ctx, 'createTransaction');
122
+ yield writer.DecIndentAndCloseBlock;
123
+ yield writer.NewLine;
124
+ }
125
+ function* send(ctx) {
126
+ yield* writer.jsDoc(`Send calls to the current app`);
127
+ yield `readonly send = {`;
128
+ yield writer.IncIndent;
129
+ yield* opMethods(ctx, 'send');
130
+ yield* clearState(ctx, 'send');
131
+ yield* call(ctx, 'send');
132
+ yield* noopMethods(ctx, 'send');
133
+ yield writer.DecIndentAndCloseBlock;
134
+ yield writer.NewLine;
135
+ }
136
+ function* opMethods(ctx, type) {
137
+ const { app, callConfig } = ctx;
138
+ yield* operationMethods(ctx, `Updates an existing instance of the ${app.name} smart contract`, callConfig.updateMethods, 'update', type, true);
139
+ yield* operationMethods(ctx, `Deletes an existing instance of the ${app.name} smart contract`, callConfig.deleteMethods, 'delete', type);
140
+ yield* operationMethods(ctx, `Opts the user into an existing instance of the ${app.name} smart contract`, callConfig.optInMethods, 'optIn', type);
141
+ yield* operationMethods(ctx, `Makes a close out call to an existing instance of the ${app.name} smart contract`, callConfig.closeOutMethods, 'closeOut', type);
142
+ }
143
+ function* bareMethodCall({ generator: { app }, name, description, verb, type, includeCompilation, }) {
144
+ const onComplete = verb === 'create' ? deployTypes.getCreateOnCompleteOptions(getCallConfigSummary.BARE_CALL, app) : verb === 'call' ? deployTypes.getCallOnCompleteOptions(getCallConfigSummary.BARE_CALL, app) : undefined;
145
+ yield* writer.jsDoc({
146
+ description: `${description}.`,
147
+ params: {
148
+ params: `The params for the bare (raw) call`,
149
+ },
150
+ returns: `The ${verb} result`,
151
+ });
152
+ yield `${name}: (params?: Expand<AppClientBareCallParams${includeCompilation ? ' & AppClientCompilationParams' : ''}${verb === 'create' ? ' & CreateSchema' : ''}${type === 'send' ? ' & SendParams' : ''}${onComplete?.type ? ` & ${onComplete.type}` : ''}>) => {`;
153
+ yield* writer.indent(`return this.appClient.${type}.bare.${verb}(params)`);
154
+ yield '},';
155
+ }
156
+ function* abiMethodCall({ generator: { app, methodSignatureToUniqueName, name, sanitizer }, method, description, verb, type, includeCompilation, readonly, }) {
157
+ const methodSig = new algosdk.ABIMethod(method).getSignature();
158
+ const uniqueName = methodSignatureToUniqueName[methodSig];
159
+ const onComplete = verb === 'create'
160
+ ? deployTypes.getCreateOnCompleteOptions(methodSig, app)
161
+ : verb === 'call' && !readonly
162
+ ? deployTypes.getCallOnCompleteOptions(methodSig, app)
163
+ : undefined;
164
+ yield* writer.jsDoc({
165
+ description: verb === 'call' && method.readonly
166
+ ? [
167
+ `${description} using the \`${methodSig}\` ABI method.`,
168
+ '',
169
+ 'This method is a readonly method; calling it with onComplete of NoOp will result in a simulated transaction rather than a real transaction.',
170
+ ]
171
+ : `${description} using the \`${methodSig}\` ABI method.`,
172
+ abiDescription: method?.desc,
173
+ params: {
174
+ params: `The params for the smart contract call`,
175
+ },
176
+ returns: `The ${verb} ${type === 'params' ? 'params' : type === 'createTransaction' ? 'transaction' : 'result'}${method?.returns?.desc ? `: ${method.returns.desc}` : ''}`,
177
+ });
178
+ const methodName = sanitizer.makeSafeMethodIdentifier(uniqueName);
179
+ const methodNameAccessor = sanitizer.getSafeMemberAccessor(methodName);
180
+ const methodSigSafe = sanitizer.makeSafeStringTypeLiteral(methodSig);
181
+ yield `${!readonly ? `${methodName}: ` : ''}${type === 'send' ? 'async ' : ''}${readonly ? `${methodName}` : ''}(params: CallParams<${name}Args['obj']['${methodSigSafe}'] | ${name}Args['tuple']['${methodSigSafe}']>${includeCompilation ? ' &' + ' AppClientCompilationParams' : ''}${verb === 'create' ? ' & CreateSchema' : ''}${type === 'send' && !readonly ? ' & SendParams' : ''}${onComplete?.type && !readonly ? ` & ${onComplete.type}` : ''}${onComplete?.isOptional !== false && (method.args.length === 0 || !method.args.some((a) => !a.defaultValue)) ? ` = {args: [${method.args.map((_) => 'undefined').join(', ')}]}` : ''})${!readonly ? ' =>' : ''} {`;
182
+ if (type === 'send') {
183
+ yield* writer.indent(`const result = await this.appClient.${type}.${verb}(${name}ParamsFactory${verb !== 'call' ? `.${verb}` : ''}${methodNameAccessor}(params))`, readonly
184
+ ? `return result.return as ${name}Returns['${methodSigSafe}']`
185
+ : `return {...result, return: result.return as undefined | ${name}Returns['${methodSigSafe}']}`);
186
+ }
187
+ else {
188
+ yield* writer.indent(`return this.appClient.${type}.${verb}(${name}ParamsFactory${verb !== 'call' ? `.${verb}` : ''}${methodNameAccessor}(params))`);
189
+ }
190
+ yield `}${!readonly ? ',' : ''}`;
191
+ yield writer.NewLine;
192
+ }
193
+ function* operationMethods(generator, description, methods, verb, type, includeCompilation) {
194
+ if (methods.length) {
195
+ yield* writer.jsDoc(`Gets available ${verb} methods`);
196
+ yield `${verb}: {`;
197
+ yield writer.IncIndent;
198
+ for (const methodSig of methods) {
199
+ if (methodSig === getCallConfigSummary.BARE_CALL) {
200
+ yield* bareMethodCall({
201
+ generator,
202
+ name: 'bare',
203
+ description: `${description} using a bare call`,
204
+ verb,
205
+ type,
206
+ includeCompilation,
207
+ });
208
+ }
209
+ else {
210
+ const method = generator.app.methods.find((m) => new algosdk.ABIMethod(m).getSignature() === methodSig);
211
+ yield* abiMethodCall({
212
+ generator,
213
+ method,
214
+ description,
215
+ verb,
216
+ type,
217
+ includeCompilation,
218
+ });
219
+ }
220
+ }
221
+ yield writer.DecIndent;
222
+ yield '},';
223
+ yield writer.NewLine;
224
+ }
225
+ }
226
+ function* clearState(generator, type) {
227
+ yield* bareMethodCall({
228
+ generator,
229
+ name: 'clearState',
230
+ description: `Makes a clear_state call to an existing instance of the ${generator.app.name} smart contract`,
231
+ verb: 'clearState',
232
+ type,
233
+ });
234
+ yield writer.NewLine;
235
+ }
236
+ function* call(generator, type) {
237
+ if (generator.callConfig.callMethods.includes(getCallConfigSummary.BARE_CALL)) {
238
+ yield* bareMethodCall({
239
+ generator,
240
+ name: 'bare',
241
+ description: `Makes a call to the ${generator.app.name} smart contract using a bare call`,
242
+ verb: 'call',
243
+ type,
244
+ });
245
+ yield writer.NewLine;
246
+ }
247
+ }
248
+ function* readonlyMethods(generator) {
249
+ const { app, callConfig } = generator;
250
+ for (const method of app.methods) {
251
+ const methodSignature = new algosdk.ABIMethod(method).getSignature();
252
+ // Skip non readonly methods
253
+ if (!callConfig.callMethods.includes(methodSignature) || !method.readonly)
254
+ continue;
255
+ yield* abiMethodCall({
256
+ generator,
257
+ description: `Makes a readonly (simulated) call to the ${generator.app.name} smart contract`,
258
+ method,
259
+ verb: 'call',
260
+ type: 'send',
261
+ includeCompilation: false,
262
+ readonly: true,
263
+ });
264
+ }
265
+ }
266
+ function* noopMethods(generator, type) {
267
+ const { app, callConfig } = generator;
268
+ for (const method of app.methods) {
269
+ const methodSignature = new algosdk.ABIMethod(method).getSignature();
270
+ // Skip methods which don't support a no_op call config
271
+ if (!callConfig.callMethods.includes(methodSignature))
272
+ continue;
273
+ yield* abiMethodCall({
274
+ generator,
275
+ description: `Makes a call to the ${generator.app.name} smart contract`,
276
+ method,
277
+ verb: 'call',
278
+ type,
279
+ includeCompilation: false,
280
+ });
281
+ }
282
+ }
283
+ function* getStateMethods({ app, sanitizer }) {
284
+ if (Object.keys(app.state).length === 0)
285
+ return;
286
+ yield* writer.jsDoc(`Methods to access state for the current ${app.name} app`);
287
+ yield 'state = {';
288
+ yield writer.IncIndent;
289
+ const storageTypes = ['global', 'local', 'box'];
290
+ for (const storageType of storageTypes) {
291
+ const hasKeys = Object.keys(app.state.keys[storageType]).length > 0;
292
+ const hasMaps = Object.keys(app.state.maps[storageType]).length > 0;
293
+ if (!hasKeys && !hasMaps)
294
+ continue;
295
+ yield* writer.jsDoc(`Methods to access ${storageType} state for the current ${app.name} app`);
296
+ yield `${storageType}${storageType === 'local' ? ': (address: string | Address) => ({' : ': {'}`;
297
+ yield writer.IncIndent;
298
+ yield* writer.jsDoc(`Get all current keyed values from ${storageType} state`);
299
+ yield `getAll: async (): Promise<Partial<Expand<${storageType[0].toUpperCase()}${storageType.substring(1)}KeysState>>> => {`;
300
+ yield* writer.indent(`const result = await this.appClient.state.${storageType}${storageType === 'local' ? '(address)' : ''}.getAll()`, `return {`, ...Object.keys(app.state.keys[storageType]).map((n) => {
301
+ return ` ${sanitizer.makeSafePropertyIdentifier(n)}: ${app.state.keys[storageType][n].valueType === 'AVMBytes' ? `new BinaryStateValue(result${sanitizer.getSafeMemberAccessor(n)})` : `result${sanitizer.getSafeMemberAccessor(n)}`},`;
302
+ }), `}`);
303
+ yield `},`;
304
+ for (const n of Object.keys(app.state.keys[storageType])) {
305
+ const name = sanitizer.makeSafePropertyIdentifier(n);
306
+ const k = app.state.keys[storageType][n];
307
+ yield* writer.jsDoc(`Get the current value of the ${n} key in ${storageType} state`);
308
+ yield `${name}: async (): Promise<${k.valueType === 'AVMBytes' ? 'BinaryState' : `${getEquivalentType.getEquivalentType(k.valueType, 'output', { app, sanitizer })} | undefined`}> => { return ${k.valueType === 'AVMBytes' ? 'new BinaryStateValue(' : ''}(await this.appClient.state.${storageType}${storageType === 'local' ? '(address)' : ''}.getValue("${name}"))${k.valueType === 'AVMBytes' ? ' as Uint8Array | undefined)' : ` as ${getEquivalentType.getEquivalentType(k.valueType, 'output', { app, sanitizer })} | undefined`} },`;
309
+ }
310
+ for (const n of Object.keys(app.state.maps[storageType])) {
311
+ const name = sanitizer.makeSafePropertyIdentifier(app.state.keys[storageType][n] ? `${n}Map` : n);
312
+ const m = app.state.maps[storageType][n];
313
+ yield* writer.jsDoc(`Get values from the ${n} map in ${storageType} state`);
314
+ yield `${name}: {`;
315
+ yield writer.IncIndent;
316
+ yield* writer.jsDoc(`Get all current values of the ${n} map in ${storageType} state`);
317
+ yield `getMap: async (): Promise<Map<${getEquivalentType.getEquivalentType(m.keyType, 'output', { app, sanitizer })}, ${getEquivalentType.getEquivalentType(m.valueType, 'output', { app, sanitizer })}>> => { return (await this.appClient.state.${storageType}${storageType === 'local' ? '(address)' : ''}.getMap("${sanitizer.makeSafeStringTypeLiteral(n)}")) as Map<${getEquivalentType.getEquivalentType(m.keyType, 'output', { app, sanitizer })}, ${getEquivalentType.getEquivalentType(m.valueType, 'output', { app, sanitizer })}> },`;
318
+ yield* writer.jsDoc(`Get a current value of the ${n} map by key from ${storageType} state`);
319
+ yield `value: async (key: ${getEquivalentType.getEquivalentType(m.keyType, 'input', { app, sanitizer })}): Promise<${getEquivalentType.getEquivalentType(m.valueType, 'output', { app, sanitizer })} | undefined> => { return await this.appClient.state.${storageType}${storageType === 'local' ? '(address)' : ''}.getMapValue("${sanitizer.makeSafeStringTypeLiteral(n)}", key) as ${getEquivalentType.getEquivalentType(m.valueType, 'output', { app, sanitizer })} | undefined },`;
320
+ yield writer.DecIndent;
321
+ yield `},`;
322
+ }
323
+ yield writer.DecIndent;
324
+ yield `}${storageType === 'local' ? ')' : ''},`;
325
+ }
326
+ yield writer.DecIndentAndCloseBlock;
327
+ yield writer.NewLine;
328
+ }
329
+ function* cloneMethod({ name }) {
330
+ yield* writer.jsDoc({
331
+ description: 'Clone this app client with different params',
332
+ params: {
333
+ params: 'The params to use for the the cloned app client. Omit a param to keep the original value. Set a param to override the original value. Setting to undefined will clear the original value.',
334
+ },
335
+ returns: 'A new app client with the altered params',
336
+ });
337
+ yield `public clone(params: CloneAppClientParams) {`;
338
+ yield writer.IncIndent;
339
+ yield `return new ${name}Client(this.appClient.clone(params))`;
340
+ yield writer.DecIndentAndCloseBlock;
341
+ yield writer.NewLine;
342
+ }
343
+
344
+ exports.appClient = appClient;
345
+ //# sourceMappingURL=app-client.js.map