@cosmwasm/ts-codegen 0.30.0 → 0.31.0

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 (66) hide show
  1. package/README.md +5 -2
  2. package/main/builder/builder.js +41 -4
  3. package/main/generators/create-helpers.js +38 -0
  4. package/main/helpers/contractContextBase.js +8 -0
  5. package/main/helpers/contractsContextTSX.js +8 -0
  6. package/main/helpers/index.js +31 -0
  7. package/main/plugins/client.js +11 -6
  8. package/main/plugins/message-composer.js +10 -6
  9. package/main/plugins/msg-builder.js +1 -1
  10. package/main/plugins/plugin-base.js +9 -2
  11. package/main/plugins/provider-bundle.js +146 -0
  12. package/main/plugins/provider.js +170 -0
  13. package/main/plugins/react-query.js +1 -1
  14. package/main/plugins/recoil.js +1 -1
  15. package/main/plugins/types.js +1 -1
  16. package/main/utils/files.js +77 -0
  17. package/main/utils/schemas.js +1 -2
  18. package/main/utils/unused.js +68 -0
  19. package/module/builder/builder.js +28 -2
  20. package/module/generators/create-helpers.js +25 -0
  21. package/module/helpers/contractContextBase.js +92 -0
  22. package/module/helpers/contractsContextTSX.js +73 -0
  23. package/module/helpers/index.js +2 -0
  24. package/module/plugins/client.js +13 -10
  25. package/module/plugins/message-composer.js +12 -10
  26. package/module/plugins/msg-builder.js +1 -1
  27. package/module/plugins/plugin-base.js +15 -8
  28. package/module/plugins/provider-bundle.js +65 -0
  29. package/module/plugins/provider.js +81 -0
  30. package/module/plugins/react-query.js +1 -1
  31. package/module/plugins/recoil.js +1 -1
  32. package/module/plugins/types.js +1 -1
  33. package/module/utils/files.js +44 -0
  34. package/module/utils/schemas.js +1 -2
  35. package/module/utils/unused.js +45 -0
  36. package/package.json +3 -3
  37. package/src/builder/builder.ts +36 -1
  38. package/src/generators/create-helpers.ts +28 -0
  39. package/src/helpers/contractContextBase.ts +92 -0
  40. package/src/helpers/contractsContextTSX.ts +73 -0
  41. package/src/helpers/index.ts +2 -0
  42. package/src/plugins/client.ts +30 -14
  43. package/src/plugins/message-composer.ts +23 -14
  44. package/src/plugins/msg-builder.ts +1 -1
  45. package/src/plugins/plugin-base.ts +30 -20
  46. package/src/plugins/provider-bundle.ts +97 -0
  47. package/src/plugins/provider.ts +114 -0
  48. package/src/plugins/react-query.ts +1 -1
  49. package/src/plugins/recoil.ts +1 -1
  50. package/src/plugins/types.ts +1 -1
  51. package/src/utils/files.ts +73 -0
  52. package/src/utils/schemas.ts +1 -3
  53. package/src/utils/unused.ts +52 -0
  54. package/types/src/builder/builder.d.ts +7 -1
  55. package/types/src/generators/create-helpers.d.ts +3 -0
  56. package/types/src/helpers/contractContextBase.d.ts +1 -0
  57. package/types/src/helpers/contractsContextTSX.d.ts +1 -0
  58. package/types/src/helpers/index.d.ts +2 -0
  59. package/types/src/plugins/client.d.ts +4 -3
  60. package/types/src/plugins/message-composer.d.ts +4 -3
  61. package/types/src/plugins/plugin-base.d.ts +7 -3
  62. package/types/src/plugins/provider-bundle.d.ts +13 -0
  63. package/types/src/plugins/provider.d.ts +15 -0
  64. package/types/src/plugins/use-contracts.d.ts +12 -0
  65. package/types/src/utils/files.d.ts +3 -0
  66. package/types/src/utils/unused.d.ts +5 -0
@@ -1,11 +1,12 @@
1
- import { pascal } from 'case';
2
- import * as w from 'wasm-ast-types';
3
- import { findExecuteMsg, findAndParseTypes, findQueryMsg } from '../utils';
4
- import { RenderContext, getMessageProperties } from 'wasm-ast-types';
5
- import { BuilderPluginBase } from './plugin-base';
1
+ import { pascal } from "case";
2
+ import * as w from "wasm-ast-types";
3
+ import { findExecuteMsg, findAndParseTypes, findQueryMsg } from "../utils";
4
+ import { RenderContext, getMessageProperties } from "wasm-ast-types";
5
+ import { BuilderPluginBase } from "./plugin-base";
6
+ export const TYPE = "client";
6
7
  export class ClientPlugin extends BuilderPluginBase {
7
8
  initContext(contract, options) {
8
- return new RenderContext(contract, options);
9
+ return new RenderContext(contract, options, this.builder.builderContext);
9
10
  }
10
11
 
11
12
  async doRender(name, context) {
@@ -20,8 +21,8 @@ export class ClientPlugin extends BuilderPluginBase {
20
21
  const {
21
22
  schemas
22
23
  } = context.contract;
23
- const localname = pascal(name) + '.client.ts';
24
- const TypesFile = pascal(name) + '.types';
24
+ const localname = pascal(name) + ".client.ts";
25
+ const TypesFile = pascal(name) + ".types";
25
26
  const QueryMsg = findQueryMsg(schemas);
26
27
  const ExecuteMsg = findExecuteMsg(schemas);
27
28
  const typeHash = await findAndParseTypes(schemas);
@@ -37,6 +38,7 @@ export class ClientPlugin extends BuilderPluginBase {
37
38
  ReadOnlyInstance = pascal(`${name}ReadOnlyInterface`);
38
39
  body.push(w.createQueryInterface(context, ReadOnlyInstance, QueryMsg));
39
40
  body.push(w.createQueryClass(context, QueryClient, ReadOnlyInstance, QueryMsg));
41
+ context.addProviderInfo(name, w.PROVIDER_TYPES.QUERY_CLIENT_TYPE, QueryClient, localname);
40
42
  } // execute messages
41
43
 
42
44
 
@@ -48,16 +50,17 @@ export class ClientPlugin extends BuilderPluginBase {
48
50
  Instance = pascal(`${name}Interface`);
49
51
  body.push(w.createExecuteInterface(context, Instance, this.option.client.execExtendsQuery ? ReadOnlyInstance : null, ExecuteMsg));
50
52
  body.push(w.createExecuteClass(context, Client, Instance, this.option.client.execExtendsQuery ? QueryClient : null, ExecuteMsg));
53
+ context.addProviderInfo(name, w.PROVIDER_TYPES.SIGNING_CLIENT_TYPE, Client, localname);
51
54
  }
52
55
  }
53
56
 
54
- if (typeHash.hasOwnProperty('Coin')) {
57
+ if (typeHash.hasOwnProperty("Coin")) {
55
58
  // @ts-ignore
56
59
  delete context.utils.Coin;
57
60
  }
58
61
 
59
62
  return [{
60
- type: 'client',
63
+ type: TYPE,
61
64
  localname,
62
65
  body
63
66
  }];
@@ -1,11 +1,12 @@
1
- import { pascal } from 'case';
2
- import * as w from 'wasm-ast-types';
3
- import { findAndParseTypes, findExecuteMsg } from '../utils';
4
- import { getMessageProperties, RenderContext } from 'wasm-ast-types';
5
- import { BuilderPluginBase } from './plugin-base';
1
+ import { pascal } from "case";
2
+ import * as w from "wasm-ast-types";
3
+ import { findAndParseTypes, findExecuteMsg } from "../utils";
4
+ import { getMessageProperties, RenderContext } from "wasm-ast-types";
5
+ import { BuilderPluginBase } from "./plugin-base";
6
+ export const TYPE = "message-composer";
6
7
  export class MessageComposerPlugin extends BuilderPluginBase {
7
8
  initContext(contract, options) {
8
- return new RenderContext(contract, options);
9
+ return new RenderContext(contract, options, this.builder.builderContext);
9
10
  }
10
11
 
11
12
  async doRender(name, context) {
@@ -20,8 +21,8 @@ export class MessageComposerPlugin extends BuilderPluginBase {
20
21
  const {
21
22
  schemas
22
23
  } = context.contract;
23
- const localname = pascal(name) + '.message-composer.ts';
24
- const TypesFile = pascal(name) + '.types';
24
+ const localname = pascal(name) + ".message-composer.ts";
25
+ const TypesFile = pascal(name) + ".types";
25
26
  const ExecuteMsg = findExecuteMsg(schemas);
26
27
  const typeHash = await findAndParseTypes(schemas);
27
28
  const body = [];
@@ -35,16 +36,17 @@ export class MessageComposerPlugin extends BuilderPluginBase {
35
36
  const Interface = pascal(`${name}Message`);
36
37
  body.push(w.createMessageComposerInterface(context, Interface, ExecuteMsg));
37
38
  body.push(w.createMessageComposerClass(context, TheClass, Interface, ExecuteMsg));
39
+ context.addProviderInfo(name, w.PROVIDER_TYPES.MESSAGE_COMPOSER_TYPE, TheClass, localname);
38
40
  }
39
41
  }
40
42
 
41
- if (typeHash.hasOwnProperty('Coin')) {
43
+ if (typeHash.hasOwnProperty("Coin")) {
42
44
  // @ts-ignore
43
45
  delete context.utils.Coin;
44
46
  }
45
47
 
46
48
  return [{
47
- type: 'message-composer',
49
+ type: TYPE,
48
50
  localname,
49
51
  body
50
52
  }];
@@ -5,7 +5,7 @@ import { getMessageProperties, RenderContext } from 'wasm-ast-types';
5
5
  import { BuilderPluginBase } from './plugin-base';
6
6
  export class MsgBuilderPlugin extends BuilderPluginBase {
7
7
  initContext(contract, options) {
8
- return new RenderContext(contract, options);
8
+ return new RenderContext(contract, options, this.builder.builderContext);
9
9
  }
10
10
 
11
11
  async doRender(name, context) {
@@ -1,21 +1,28 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
2
- import { sync as mkdirp } from 'mkdirp';
3
- import { join } from 'path';
4
- import { writeFileSync } from 'fs';
5
- import { header } from '../utils/header';
6
- import generate from '@babel/generator';
7
- import * as t from '@babel/types';
2
+ import { sync as mkdirp } from "mkdirp";
3
+ import { join } from "path";
4
+ import { writeFileSync } from "fs";
5
+ import { header } from "../utils/header";
6
+ import generate from "@babel/generator";
7
+ import * as t from "@babel/types";
8
8
 
9
9
  /**
10
10
  * BuilderPluginBase enable ts-codegen users implement their own plugins by only implement a few functions.
11
11
  */
12
12
  export class BuilderPluginBase {
13
- constructor(opt) {
13
+ constructor(opt, builder) {
14
+ _defineProperty(this, "builder", void 0);
15
+
14
16
  _defineProperty(this, "option", void 0);
15
17
 
16
18
  _defineProperty(this, "utils", void 0);
17
19
 
18
20
  this.option = opt;
21
+ this.builder = builder;
22
+ }
23
+
24
+ setBuilder(builder) {
25
+ this.builder = builder;
19
26
  }
20
27
 
21
28
  async render(name, contractInfo, outPath) {
@@ -35,7 +42,7 @@ export class BuilderPluginBase {
35
42
  }
36
43
 
37
44
  return results.map(result => {
38
- const imports = context.getImports(this.utils);
45
+ const imports = context.getImports(this.utils, result.localname);
39
46
  const code = header + generate(t.program([...imports, ...result.body])).code;
40
47
  mkdirp(outPath);
41
48
  const filename = join(outPath, result.localname);
@@ -0,0 +1,65 @@
1
+ import { pascal } from "case";
2
+ import * as w from "wasm-ast-types";
3
+ import { RenderContext } from "wasm-ast-types";
4
+ import { BuilderPluginBase } from "./plugin-base";
5
+ import { GetLocalBaseNameByContractName } from "./provider";
6
+ export class ContractsProviderBundlePlugin extends BuilderPluginBase {
7
+ constructor(opt) {
8
+ super(opt);
9
+ this.utils = {
10
+ CosmWasmClient: "@cosmjs/cosmwasm-stargate",
11
+ SigningCosmWasmClient: "@cosmjs/cosmwasm-stargate",
12
+ IQueryClientProvider: "__contractContextBase__",
13
+ ISigningClientProvider: "__contractContextBase__",
14
+ IMessageComposerProvider: "__contractContextBase__"
15
+ };
16
+ }
17
+
18
+ initContext(contract, options) {
19
+ return new RenderContext(contract, options, this.builder.builderContext);
20
+ }
21
+
22
+ async doRender(name, context) {
23
+ if (!this.option?.useContracts?.enabled) {
24
+ return;
25
+ }
26
+
27
+ const providerInfos = context.getProviderInfos();
28
+
29
+ if (!Object.keys(providerInfos)?.length) {
30
+ return;
31
+ }
32
+
33
+ const localname = "contractContextProviders.ts";
34
+ const body = [];
35
+ context.addUtil("CosmWasmClient");
36
+ context.addUtil("SigningCosmWasmClient");
37
+ context.addUtil("IQueryClientProvider");
38
+ context.addUtil("ISigningClientProvider");
39
+ context.addUtil("IMessageComposerProvider");
40
+
41
+ for (const name in providerInfos) {
42
+ if (Object.prototype.hasOwnProperty.call(providerInfos, name)) {
43
+ const providerInfo = providerInfos[name];
44
+
45
+ for (const key in providerInfo) {
46
+ if (Object.prototype.hasOwnProperty.call(providerInfo, key)) {
47
+ const info = providerInfo[key];
48
+ body.push(w.importStmt([info.classname], `./${info.basename}`));
49
+ }
50
+ }
51
+
52
+ body.push(w.importStmt([pascal(name)], `./${GetLocalBaseNameByContractName(name)}`));
53
+ }
54
+ }
55
+
56
+ body.push(w.createIContractsContext(providerInfos));
57
+ body.push(w.createGettingProviders(providerInfos));
58
+ return [{
59
+ type: "plugin",
60
+ localname,
61
+ body
62
+ }];
63
+ }
64
+
65
+ }
@@ -0,0 +1,81 @@
1
+ import { pascal } from "case";
2
+ import * as w from "wasm-ast-types";
3
+ import { RenderContext } from "wasm-ast-types";
4
+ import { BuilderPluginBase } from "./plugin-base";
5
+ export const GetLocalNameByContractName = name => `${pascal(name)}.provider.ts`;
6
+ export const GetLocalBaseNameByContractName = name => `${pascal(name)}.provider`;
7
+ export class ContractsContextProviderPlugin extends BuilderPluginBase {
8
+ constructor(opt) {
9
+ super(opt);
10
+ this.utils = {
11
+ ContractBase: "__contractContextBase__",
12
+ IContractConstructor: "__contractContextBase__",
13
+ IEmptyClient: "__contractContextBase__"
14
+ };
15
+ }
16
+
17
+ initContext(contract, options) {
18
+ return new RenderContext(contract, options, this.builder.builderContext);
19
+ }
20
+
21
+ async doRender(name, context) {
22
+ if (!this.option?.useContracts?.enabled) {
23
+ return;
24
+ }
25
+
26
+ const providerInfo = context.getProviderInfos()[name];
27
+
28
+ if (!Object.keys(providerInfo)?.length) {
29
+ return;
30
+ }
31
+
32
+ context.addUtil("ContractBase");
33
+ context.addUtil("IContractConstructor");
34
+ const localname = GetLocalNameByContractName(name);
35
+ let needEmptyClientType = false;
36
+ let clientFile = null;
37
+ let clientClasses = [];
38
+ const body = [];
39
+ const signClientProviderInfo = providerInfo[w.PROVIDER_TYPES.SIGNING_CLIENT_TYPE];
40
+
41
+ if (signClientProviderInfo) {
42
+ clientFile = `./${signClientProviderInfo.basename}`;
43
+ clientClasses.push(signClientProviderInfo.classname);
44
+ } else {
45
+ needEmptyClientType = true;
46
+ }
47
+
48
+ const queryClientProviderInfo = providerInfo[w.PROVIDER_TYPES.QUERY_CLIENT_TYPE];
49
+
50
+ if (queryClientProviderInfo) {
51
+ clientFile = `./${queryClientProviderInfo.basename}`;
52
+ clientClasses.push(queryClientProviderInfo.classname);
53
+ } else {
54
+ needEmptyClientType = true;
55
+ }
56
+
57
+ if (clientFile) {
58
+ body.push(w.importStmt(clientClasses, clientFile));
59
+ }
60
+
61
+ const messageComposerProviderInfo = providerInfo[w.PROVIDER_TYPES.MESSAGE_COMPOSER_TYPE];
62
+
63
+ if (messageComposerProviderInfo) {
64
+ body.push(w.importStmt([messageComposerProviderInfo.classname], `./${messageComposerProviderInfo.basename}`));
65
+ } else {
66
+ needEmptyClientType = true;
67
+ }
68
+
69
+ if (needEmptyClientType) {
70
+ context.addUtil("IEmptyClient");
71
+ }
72
+
73
+ body.push(w.createProvider(name, providerInfo));
74
+ return [{
75
+ type: "plugin",
76
+ localname,
77
+ body
78
+ }];
79
+ }
80
+
81
+ }
@@ -5,7 +5,7 @@ import { getMessageProperties, RenderContext } from 'wasm-ast-types';
5
5
  import { BuilderPluginBase } from './plugin-base';
6
6
  export class ReactQueryPlugin extends BuilderPluginBase {
7
7
  initContext(contract, options) {
8
- return new RenderContext(contract, options);
8
+ return new RenderContext(contract, options, this.builder.builderContext);
9
9
  }
10
10
 
11
11
  async doRender(name, context) {
@@ -14,7 +14,7 @@ export class RecoilPlugin extends BuilderPluginBase {
14
14
  }
15
15
 
16
16
  initContext(contract, options) {
17
- return new RenderContext(contract, options);
17
+ return new RenderContext(contract, options, this.builder.builderContext);
18
18
  }
19
19
 
20
20
  async doRender(name, context) {
@@ -6,7 +6,7 @@ import { RenderContext } from 'wasm-ast-types';
6
6
  import { BuilderPluginBase } from './plugin-base';
7
7
  export class TypesPlugin extends BuilderPluginBase {
8
8
  initContext(contract, options) {
9
- return new RenderContext(contract, options);
9
+ return new RenderContext(contract, options, this.builder.builderContext);
10
10
  }
11
11
 
12
12
  async doRender(name, context) {
@@ -0,0 +1,44 @@
1
+ import * as t from "@babel/types";
2
+ import { parse } from "@babel/parser";
3
+ import { sync as mkdirp } from "mkdirp";
4
+ import { writeFileSync } from "fs";
5
+ import { dirname } from "path";
6
+ import generate from "@babel/generator";
7
+ import { unused } from "./unused";
8
+ import traverse from "@babel/traverse";
9
+ export const writeAstToFile = (outPath, program, filename, removeUnusedImports = false, isTsDisable = false, isEslintDisable = false) => {
10
+ const ast = t.program(program);
11
+ const content = generate(ast).code;
12
+
13
+ if (removeUnusedImports) {
14
+ const plugins = ["typescript"];
15
+ const newAst = parse(content, {
16
+ sourceType: "module",
17
+ plugins
18
+ });
19
+ traverse(newAst, unused);
20
+ const content2 = generate(newAst).code;
21
+ writeContentToFile(outPath, content2, filename, isTsDisable, isEslintDisable);
22
+ } else {
23
+ writeContentToFile(outPath, content, filename, isTsDisable, isEslintDisable);
24
+ }
25
+ };
26
+ export const writeContentToFile = (outPath, content, filename, isTsDisable = false, isEslintDisable = false) => {
27
+ let esLintPrefix = "";
28
+ let tsLintPrefix = "";
29
+ let nameWithoutPath = filename.replace(outPath, ""); // strip off leading slash
30
+
31
+ if (nameWithoutPath.startsWith("/")) nameWithoutPath = nameWithoutPath.replace(/^\//, "");
32
+
33
+ if (isTsDisable) {
34
+ tsLintPrefix = `//@ts-nocheck\n`;
35
+ }
36
+
37
+ if (isEslintDisable) {
38
+ esLintPrefix = `/* eslint-disable */\n`;
39
+ }
40
+
41
+ const text = tsLintPrefix + esLintPrefix + content;
42
+ mkdirp(dirname(filename));
43
+ writeFileSync(filename, text);
44
+ };
@@ -72,8 +72,7 @@ export const findQueryMsg = schemas => {
72
72
  return QueryMsg;
73
73
  };
74
74
  export const findExecuteMsg = schemas => {
75
- const ExecuteMsg = schemas.find(schema => schema.title === 'ExecuteMsg' || schema.title === 'ExecuteMsg_for_Empty' || // if cleanse is used, this is never
76
- schema.title === 'ExecuteMsgForEmpty');
75
+ const ExecuteMsg = schemas.find(schema => schema.title.startsWith('ExecuteMsg'));
77
76
  return ExecuteMsg;
78
77
  };
79
78
  export const findAndParseTypes = async schemas => {
@@ -0,0 +1,45 @@
1
+ //@ts-nocheck
2
+ import * as t from '@babel/types'; // https://github.com/chuyik/babel-plugin-danger-remove-unused-import
3
+ // https://github.com/chuyik/babel-plugin-danger-remove-unused-import/blob/c5454c21e94698a2464a12baa5590761932a71a8/License#L1
4
+
5
+ export const unused = {
6
+ Program: {
7
+ exit: path => {
8
+ const UnRefBindings = new Map();
9
+
10
+ for (const [name, binding] of Object.entries(path.scope.bindings)) {
11
+ if (!binding.path.parentPath || binding.kind !== 'module') continue;
12
+ const source = binding.path.parentPath.get('source');
13
+ const importName = source.node.value;
14
+ if (!t.isStringLiteral(source)) continue;
15
+ const key = `${importName}(${source.node.loc && source.node.loc.start.line})`;
16
+
17
+ if (!UnRefBindings.has(key)) {
18
+ UnRefBindings.set(key, binding);
19
+ }
20
+
21
+ if (binding.referenced) {
22
+ UnRefBindings.set(key, null);
23
+ } else {
24
+ const nodeType = binding.path.node.type;
25
+
26
+ if (nodeType === 'ImportSpecifier') {
27
+ binding.path.remove();
28
+ } else if (nodeType === 'ImportDefaultSpecifier') {
29
+ binding.path.remove();
30
+ } else if (nodeType === 'ImportNamespaceSpecifier') {
31
+ binding.path.remove();
32
+ } else if (binding.path.parentPath) {
33
+ binding.path.parentPath.remove();
34
+ }
35
+ }
36
+ }
37
+
38
+ UnRefBindings.forEach((binding, key) => {
39
+ if (binding && binding.path.parentPath) {
40
+ binding.path.parentPath.remove();
41
+ }
42
+ });
43
+ }
44
+ }
45
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmwasm/ts-codegen",
3
- "version": "0.30.0",
3
+ "version": "0.31.0",
4
4
  "description": "@cosmwasm/ts-codegen converts your CosmWasm smart contracts into dev-friendly TypeScript classes so you can focus on shipping code.",
5
5
  "author": "Dan Lynch <pyramation@gmail.com>",
6
6
  "homepage": "https://github.com/cosmwasm/ts-codegen",
@@ -96,7 +96,7 @@
96
96
  "parse-package-name": "1.0.0",
97
97
  "rimraf": "3.0.2",
98
98
  "shelljs": "0.8.5",
99
- "wasm-ast-types": "^0.23.0"
99
+ "wasm-ast-types": "^0.24.0"
100
100
  },
101
- "gitHead": "9979ae4b7209f920fe1b822ede2ba80ee0f2eade"
101
+ "gitHead": "4553eb80cd89969583df6164d1c764ab5b289c63"
102
102
  }
@@ -1,4 +1,4 @@
1
- import { RenderOptions, defaultOptions, RenderContext, ContractInfo, MessageComposerOptions} from "wasm-ast-types";
1
+ import { RenderOptions, defaultOptions, RenderContext, ContractInfo, MessageComposerOptions, BuilderContext} from "wasm-ast-types";
2
2
 
3
3
  import { header } from '../utils/header';
4
4
  import { join } from "path";
@@ -21,6 +21,9 @@ import { MsgBuilderPlugin } from "../plugins/msg-builder";
21
21
  import { MessageComposerPlugin } from "../plugins/message-composer";
22
22
  import { ClientPlugin } from "../plugins/client";
23
23
  import { TypesPlugin } from "../plugins/types";
24
+ import { ContractsContextProviderPlugin } from "../plugins/provider";
25
+ import { createHelpers } from "../generators/create-helpers";
26
+ import { ContractsProviderBundlePlugin } from "../plugins/provider-bundle";
24
27
 
25
28
  const defaultOpts: TSBuilderOptions = {
26
29
  bundle: {
@@ -44,8 +47,14 @@ export interface BundleOptions {
44
47
  bundlePath?: string;
45
48
  };
46
49
 
50
+ export interface UseContractsOptions {
51
+ enabled?: boolean;
52
+ filename?: string;
53
+ };
54
+
47
55
  export type TSBuilderOptions = {
48
56
  bundle?: BundleOptions;
57
+ useContracts?: UseContractsOptions;
49
58
  } & RenderOptions;
50
59
 
51
60
  export type BuilderFileType = 'type' | 'client' | 'recoil' | 'react-query' | 'message-composer' | 'msg-builder' | 'plugin';
@@ -83,6 +92,7 @@ export class TSBuilder {
83
92
  outPath: string;
84
93
  options?: TSBuilderOptions;
85
94
  plugins: IBuilderPlugin[] = [];
95
+ builderContext: BuilderContext = new BuilderContext();
86
96
 
87
97
  protected files: BuilderFile[] = [];
88
98
 
@@ -94,6 +104,7 @@ export class TSBuilder {
94
104
  new ReactQueryPlugin(this.options),
95
105
  new RecoilPlugin(this.options),
96
106
  new MsgBuilderPlugin(this.options),
107
+ new ContractsContextProviderPlugin(this.options),
97
108
  ]);
98
109
  }
99
110
 
@@ -113,6 +124,8 @@ export class TSBuilder {
113
124
  if (plugins && plugins.length) {
114
125
  [].push.apply(this.plugins, plugins);
115
126
  }
127
+
128
+ this.plugins.forEach(plugin=> plugin.setBuilder(this))
116
129
  }
117
130
 
118
131
  async build() {
@@ -147,6 +160,28 @@ export class TSBuilder {
147
160
  if (this.options.bundle.enabled) {
148
161
  this.bundle();
149
162
  }
163
+
164
+ //create useContracts bundle file
165
+ const contractsProviderBundlePlugin = new ContractsProviderBundlePlugin(this.options);
166
+ contractsProviderBundlePlugin.setBuilder(this);
167
+
168
+ let files = await contractsProviderBundlePlugin.render(
169
+ "",
170
+ {
171
+ schemas: [],
172
+ },
173
+ this.outPath
174
+ );
175
+ if(files && files.length){
176
+ [].push.apply(this.files, files);
177
+ }
178
+
179
+ createHelpers({
180
+ outPath: this.outPath,
181
+ contracts: this.contracts,
182
+ options: this.options,
183
+ plugins: this.plugins,
184
+ }, this.builderContext);
150
185
  }
151
186
 
152
187
  async bundle() {
@@ -0,0 +1,28 @@
1
+ import { join, dirname } from "path";
2
+ import { sync as mkdirp } from "mkdirp";
3
+ import pkg from "../../package.json";
4
+ import { writeContentToFile } from "../utils/files";
5
+ import { TSBuilderInput } from "../builder";
6
+ import { contractContextBase, contractsContextTSX } from "../helpers";
7
+ import { BuilderContext } from "wasm-ast-types";
8
+
9
+ const version = process.env.NODE_ENV === "test" ? "latest" : pkg.version;
10
+ const header = `/**
11
+ * This file and any referenced files were automatically generated by ${pkg.name}@${version}
12
+ * DO NOT MODIFY BY HAND. Instead, download the latest proto files for your chain
13
+ * and run the transpile command or yarn proto command to regenerate this bundle.
14
+ */
15
+ \n`;
16
+
17
+ const write = (outPath: string, file: string, content: string) => {
18
+ const outFile = join(outPath, file);
19
+ mkdirp(dirname(outFile));
20
+ writeContentToFile(outPath, header + content, outFile);
21
+ };
22
+
23
+ export const createHelpers = (input: TSBuilderInput, builderContext: BuilderContext) => {
24
+ if (input.options?.useContracts?.enabled && Object.keys(builderContext.providers)?.length) {
25
+ write(input.outPath, "contractContextBase.ts", contractContextBase);
26
+ write(input.outPath, "contracts-context.tsx", contractsContextTSX);
27
+ }
28
+ };
@@ -0,0 +1,92 @@
1
+ export const contractContextBase = `
2
+ import {
3
+ CosmWasmClient,
4
+ SigningCosmWasmClient,
5
+ } from '@cosmjs/cosmwasm-stargate';
6
+
7
+ export interface IContractConstructor {
8
+ address: string | undefined;
9
+ cosmWasmClient: CosmWasmClient | undefined;
10
+ signingCosmWasmClient: SigningCosmWasmClient | undefined;
11
+ }
12
+
13
+ export const NO_SINGING_ERROR_MESSAGE = 'signingCosmWasmClient not connected';
14
+
15
+ export const NO_COSMWASW_CLIENT_ERROR_MESSAGE = 'cosmWasmClient not connected';
16
+
17
+ export const NO_ADDRESS_ERROR_MESSAGE = "address doesn't exist";
18
+
19
+ export const NO_SIGNING_CLIENT_ERROR_MESSAGE =
20
+ 'Signing client is not generated. Please check ts-codegen config';
21
+
22
+ export const NO_QUERY_CLIENT_ERROR_MESSAGE =
23
+ 'Query client is not generated. Please check ts-codegen config';
24
+
25
+ export const NO_MESSAGE_COMPOSER_ERROR_MESSAGE =
26
+ 'Message composer client is not generated. Please check ts-codegen config';
27
+
28
+ /**
29
+ * a placeholder for non-generated classes
30
+ */
31
+ export interface IEmptyClient {}
32
+
33
+ export interface ISigningClientProvider<T> {
34
+ getSigningClient(contractAddr: string): T;
35
+ }
36
+
37
+ export interface IQueryClientProvider<T> {
38
+ getQueryClient(contractAddr: string): T;
39
+ }
40
+
41
+ export interface IMessageComposerProvider<T> {
42
+ getMessageComposer(contractAddr: string): T;
43
+ }
44
+
45
+ export class ContractBase<
46
+ TSign = IEmptyClient,
47
+ TQuery = IEmptyClient,
48
+ TMsgComposer = IEmptyClient
49
+ > {
50
+ constructor(
51
+ protected address: string | undefined,
52
+ protected cosmWasmClient: CosmWasmClient | undefined,
53
+ protected signingCosmWasmClient: SigningCosmWasmClient | undefined,
54
+ private TSign?: new (
55
+ client: SigningCosmWasmClient,
56
+ sender: string,
57
+ contractAddress: string
58
+ ) => TSign,
59
+ private TQuery?: new (
60
+ client: CosmWasmClient,
61
+ contractAddress: string
62
+ ) => TQuery,
63
+ private TMsgComposer?: new (
64
+ sender: string,
65
+ contractAddress: string
66
+ ) => TMsgComposer
67
+ ) {}
68
+
69
+ public getSigningClient(contractAddr: string): TSign {
70
+ if (!this.signingCosmWasmClient) throw new Error(NO_SINGING_ERROR_MESSAGE);
71
+ if (!this.address) throw new Error(NO_ADDRESS_ERROR_MESSAGE);
72
+ if (!this.TSign) throw new Error(NO_SIGNING_CLIENT_ERROR_MESSAGE);
73
+ return new this.TSign(
74
+ this.signingCosmWasmClient,
75
+ this.address,
76
+ contractAddr
77
+ );
78
+ }
79
+
80
+ public getQueryClient(contractAddr: string): TQuery {
81
+ if (!this.cosmWasmClient) throw new Error(NO_COSMWASW_CLIENT_ERROR_MESSAGE);
82
+ if (!this.TQuery) throw new Error(NO_QUERY_CLIENT_ERROR_MESSAGE);
83
+ return new this.TQuery(this.cosmWasmClient, contractAddr);
84
+ }
85
+
86
+ public getMessageComposer(contractAddr: string): TMsgComposer {
87
+ if (!this.address) throw new Error(NO_ADDRESS_ERROR_MESSAGE);
88
+ if (!this.TMsgComposer) throw new Error(NO_MESSAGE_COMPOSER_ERROR_MESSAGE);
89
+ return new this.TMsgComposer(this.address, contractAddr);
90
+ }
91
+ }
92
+ `;