@cosmwasm/ts-codegen 0.16.5 → 0.18.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.
@@ -92,7 +92,7 @@ var _default = /*#__PURE__*/function () {
92
92
  type: 'checkbox',
93
93
  name: 'pkg',
94
94
  message: 'which chain contracts do you want to support?',
95
- choices: ['stargaze-claim', 'stargaze-ics721', 'stargaze-minter', 'stargaze-royalty-group', 'stargaze-sg721', 'stargaze-whitelist', 'wasmswap'].map(function (name) {
95
+ choices: ['stargaze-base-factory', 'stargaze-base-minter', 'stargaze-sg721-base', 'stargaze-sg721-metdata-onchain', 'stargaze-sg721-nt', 'stargaze-splits', 'stargaze-vending-factory', 'stargaze-vending-minter', 'stargaze-whitelist', 'wasmswap'].map(function (name) {
96
96
  return {
97
97
  name: name,
98
98
  value: "@cosmjson/".concat(name)
@@ -50,7 +50,7 @@ export default (async argv => {
50
50
  type: 'checkbox',
51
51
  name: 'pkg',
52
52
  message: 'which chain contracts do you want to support?',
53
- choices: ['stargaze-claim', 'stargaze-ics721', 'stargaze-minter', 'stargaze-royalty-group', 'stargaze-sg721', 'stargaze-whitelist', 'wasmswap'].map(name => {
53
+ choices: ['stargaze-base-factory', 'stargaze-base-minter', 'stargaze-sg721-base', 'stargaze-sg721-metdata-onchain', 'stargaze-sg721-nt', 'stargaze-splits', 'stargaze-vending-factory', 'stargaze-vending-minter', 'stargaze-whitelist', 'wasmswap'].map(name => {
54
54
  return {
55
55
  name,
56
56
  value: `@cosmjson/${name}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmwasm/ts-codegen",
3
- "version": "0.16.5",
3
+ "version": "0.18.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",
@@ -18,13 +18,15 @@
18
18
  "files": [
19
19
  "types",
20
20
  "main",
21
+ "src",
21
22
  "module"
22
23
  ],
23
24
  "scripts": {
24
25
  "build:main": "cross-env BABEL_ENV=production babel src --out-dir main --delete-dir-on-start --extensions \".tsx,.ts,.js\"",
25
26
  "build:module": "cross-env MODULE=true babel src --out-dir module --delete-dir-on-start --extensions \".tsx,.ts,.js\"",
26
- "build": "npm run build:module && npm run build:main",
27
27
  "build:ts": "tsc --project ./tsconfig.json",
28
+ "build": "npm run build:module && npm run build:main",
29
+ "buidl": "npm run build && npm run build:ts",
28
30
  "prepare": "npm run build",
29
31
  "dev": "cross-env NODE_ENV=development babel-node src/ts-codegen --extensions \".tsx,.ts,.js\"",
30
32
  "watch": "cross-env NODE_ENV=development babel-watch src/ts-codegen --extensions \".tsx,.ts,.js\"",
@@ -94,7 +96,7 @@
94
96
  "parse-package-name": "1.0.0",
95
97
  "rimraf": "3.0.2",
96
98
  "shelljs": "0.8.5",
97
- "wasm-ast-types": "^0.11.3"
99
+ "wasm-ast-types": "^0.12.0"
98
100
  },
99
- "gitHead": "d5c403bd9db776c23428a53db346accb111b3098"
101
+ "gitHead": "59dcc054d241c6bf43d5a617b31c3cd5c4ecff6e"
100
102
  }
@@ -0,0 +1,194 @@
1
+ import { RenderOptions, defaultOptions } from "wasm-ast-types";
2
+
3
+ import { header } from '../utils/header';
4
+ import { join } from "path";
5
+ import { writeFileSync } from 'fs';
6
+ import { sync as mkdirp } from "mkdirp";
7
+
8
+ import generateMessageComposer from '../generators/message-composer';
9
+ import generateTypes from '../generators/types';
10
+ import generateReactQuery from '../generators/react-query';
11
+ import generateRecoil from '../generators/recoil';
12
+ import generateClient from '../generators/client';
13
+
14
+ import { basename } from 'path';
15
+ import { readSchemas } from '../utils';
16
+
17
+ import deepmerge from 'deepmerge';
18
+ import { pascal } from "case";
19
+ import { createFileBundle, recursiveModuleBundle } from "../bundler";
20
+
21
+ import generate from '@babel/generator';
22
+ import * as t from '@babel/types';
23
+
24
+ const defaultOpts: TSBuilderOptions = {
25
+ bundle: {
26
+ enabled: true,
27
+ scope: 'contracts',
28
+ bundleFile: 'bundle.ts'
29
+ }
30
+ }
31
+
32
+ export interface TSBuilderInput {
33
+ contracts: Array<ContractFile | string>;
34
+ outPath: string;
35
+ options?: TSBuilderOptions;
36
+ };
37
+
38
+ export interface BundleOptions {
39
+ enabled?: boolean;
40
+ scope?: string;
41
+ bundleFile?: string;
42
+ };
43
+
44
+ export type TSBuilderOptions = {
45
+ bundle?: BundleOptions;
46
+ } & RenderOptions;
47
+
48
+ export interface BuilderFile {
49
+ type: 'type' | 'client' | 'recoil' | 'react-query' | 'message-composer';
50
+ contract: string;
51
+ localname: string;
52
+ filename: string;
53
+ };
54
+
55
+ export interface ContractFile {
56
+ name: string;
57
+ dir: string;
58
+ }
59
+ export class TSBuilder {
60
+ contracts: Array<ContractFile | string>;
61
+ outPath: string;
62
+ options?: TSBuilderOptions;
63
+
64
+ protected files: BuilderFile[] = [];
65
+
66
+ constructor({ contracts, outPath, options }: TSBuilderInput) {
67
+ this.contracts = contracts;
68
+ this.outPath = outPath;
69
+ this.options = deepmerge(
70
+ deepmerge(
71
+ defaultOptions,
72
+ defaultOpts
73
+ ),
74
+ options ?? {}
75
+ );
76
+ }
77
+
78
+ getContracts(): ContractFile[] {
79
+ return this.contracts.map(contractOpt => {
80
+ if (typeof contractOpt === 'string') {
81
+ const name = basename(contractOpt);
82
+ const contractName = pascal(name);
83
+ return {
84
+ name: contractName,
85
+ dir: contractOpt
86
+ }
87
+ }
88
+ return {
89
+ name: pascal(contractOpt.name),
90
+ dir: contractOpt.dir
91
+ };
92
+ });
93
+ }
94
+
95
+ async renderTypes(contract: ContractFile) {
96
+ const { enabled, ...options } = this.options.types;
97
+ if (!enabled) return;
98
+ const contractInfo = await readSchemas({
99
+ schemaDir: contract.dir
100
+ });
101
+ const files = await generateTypes(contract.name, contractInfo, this.outPath, options);
102
+ [].push.apply(this.files, files);
103
+ }
104
+
105
+ async renderClient(contract: ContractFile) {
106
+ const { enabled, ...options } = this.options.client;
107
+ if (!enabled) return;
108
+ const contractInfo = await readSchemas({
109
+ schemaDir: contract.dir
110
+ });
111
+ const files = await generateClient(contract.name, contractInfo, this.outPath, options);
112
+ [].push.apply(this.files, files);
113
+ }
114
+
115
+ async renderRecoil(contract: ContractFile) {
116
+ const { enabled, ...options } = this.options.recoil;
117
+ if (!enabled) return;
118
+ const contractInfo = await readSchemas({
119
+ schemaDir: contract.dir
120
+ });
121
+ const files = await generateRecoil(contract.name, contractInfo, this.outPath, options);
122
+ [].push.apply(this.files, files);
123
+ }
124
+
125
+ async renderReactQuery(contract: ContractFile) {
126
+ const { enabled, ...options } = this.options.reactQuery;
127
+ if (!enabled) return;
128
+ const contractInfo = await readSchemas({
129
+ schemaDir: contract.dir
130
+ });
131
+ const files = await generateReactQuery(contract.name, contractInfo, this.outPath, options);
132
+ [].push.apply(this.files, files);
133
+ }
134
+
135
+ async renderMessageComposer(contract: ContractFile) {
136
+ const { enabled, ...options } = this.options.messageComposer;
137
+ if (!enabled) return;
138
+ const contractInfo = await readSchemas({
139
+ schemaDir: contract.dir
140
+ });
141
+ const files = await generateMessageComposer(contract.name, contractInfo, this.outPath, options);
142
+ [].push.apply(this.files, files);
143
+ }
144
+
145
+ async build() {
146
+ const contracts = this.getContracts();
147
+ for (let c = 0; c < contracts.length; c++) {
148
+ const contract = contracts[c];
149
+ await this.renderTypes(contract);
150
+ await this.renderClient(contract);
151
+ await this.renderMessageComposer(contract);
152
+ await this.renderReactQuery(contract);
153
+ await this.renderRecoil(contract);
154
+ }
155
+ if (this.options.bundle.enabled) {
156
+ this.bundle();
157
+ }
158
+ }
159
+
160
+ async bundle() {
161
+
162
+ const allFiles = this.files;
163
+
164
+ const bundleFile = this.options.bundle.bundleFile;
165
+ const bundleVariables = {};
166
+ const importPaths = [];
167
+
168
+ allFiles.forEach(file => {
169
+ createFileBundle(
170
+ `${this.options.bundle.scope}.${file.contract}`,
171
+ file.localname,
172
+ bundleFile,
173
+ importPaths,
174
+ bundleVariables
175
+ );
176
+
177
+ });
178
+
179
+ const ast = recursiveModuleBundle(bundleVariables);
180
+ let code = generate(t.program(
181
+ [
182
+ ...importPaths,
183
+ ...ast
184
+ ]
185
+ )).code;
186
+
187
+ mkdirp(this.outPath);
188
+
189
+ if (code.trim() === '') code = 'export {};'
190
+
191
+ writeFileSync(join(this.outPath, bundleFile), header + code);
192
+
193
+ }
194
+ }
@@ -0,0 +1 @@
1
+ export * from './builder';
@@ -0,0 +1,67 @@
1
+ import * as t from '@babel/types';
2
+ import * as dotty from 'dotty';
3
+ import {
4
+ relative, dirname, extname
5
+ } from 'path';
6
+
7
+ export const recursiveModuleBundle = (obj) => {
8
+ return Object.keys(obj).map(key => {
9
+ if (obj[key]?.__export) {
10
+ // e.g. abci
11
+ // 1. create variable for abci
12
+ // 2. splat ALL _0, parms into abci
13
+ // 3. export that variable
14
+
15
+ const nmspc = t.variableDeclaration('const',
16
+ [t.variableDeclarator(
17
+ t.identifier(key),
18
+ t.objectExpression(
19
+ Object.keys(obj[key])
20
+ .filter(a => a !== '__export')
21
+ .filter(a => a.startsWith('_'))
22
+ .map(a => t.spreadElement(t.identifier(a)))
23
+ )
24
+ )]
25
+ );
26
+
27
+ const others = Object.keys(obj[key])
28
+ .filter(a => a !== '__export')
29
+ .filter(a => !a.startsWith('_'));
30
+ if (others.length) {
31
+ throw new Error('namespace and package not supported, yet.')
32
+ }
33
+
34
+ // return nmspc;
35
+ return t.exportNamedDeclaration(nmspc, []);
36
+
37
+
38
+
39
+ } else {
40
+ // you can make a namespace for obj[key]
41
+ // e.g. libs
42
+ return t.exportNamedDeclaration(
43
+ t.tsModuleDeclaration(
44
+ t.identifier(key),
45
+ t.tsModuleBlock(recursiveModuleBundle(obj[key]))
46
+ )
47
+ )
48
+ }
49
+ });
50
+ };
51
+
52
+ export const importNamespace = (ident: string, path: string) => t.importDeclaration(
53
+ [
54
+ t.importNamespaceSpecifier(t.identifier(ident))
55
+ ],
56
+ t.stringLiteral(path.replace(extname(path), ''))
57
+ );
58
+
59
+ let counter = 0;
60
+ export const createFileBundle = (pkg, filename, bundleFile, importPaths, bundleVariables) => {
61
+ let rel = relative(dirname(bundleFile), filename);
62
+ if (!rel.startsWith('.')) rel = `./${rel}`;
63
+ const variable = `_${counter++}`;
64
+ importPaths.push(importNamespace(variable, rel));
65
+ dotty.put(bundleVariables, pkg + '.__export', true);
66
+ dotty.put(bundleVariables, pkg + '.' + variable, true);
67
+ }
@@ -0,0 +1 @@
1
+ export * from './bundler';
package/src/cli.js ADDED
@@ -0,0 +1,21 @@
1
+ import { prompt } from './utils/prompt';
2
+ import { Commands as commands } from './cmds';
3
+
4
+ const question = [
5
+ {
6
+ _: true,
7
+ type: 'fuzzy',
8
+ name: 'cmd',
9
+ message: 'what do you want to do?',
10
+ choices: Object.keys(commands)
11
+ }
12
+ ];
13
+
14
+ export const cli = async (argv) => {
15
+ var { cmd } = await prompt(question, argv);
16
+ if (typeof commands[cmd] === 'function') {
17
+ await commands[cmd](argv);
18
+ } else {
19
+ console.log('command not found.');
20
+ }
21
+ };
package/src/cmds.js ADDED
@@ -0,0 +1,12 @@
1
+
2
+ import _create_boilerplate from './commands/create-boilerplate';
3
+ import _generate from './commands/generate';
4
+ import _install from './commands/install';
5
+ const Commands = {};
6
+ Commands['create-boilerplate'] = _create_boilerplate;
7
+ Commands['generate'] = _generate;
8
+ Commands['install'] = _install;
9
+
10
+ export { Commands };
11
+
12
+
@@ -0,0 +1,139 @@
1
+ import * as shell from 'shelljs';
2
+ import { prompt } from '../utils/prompt';
3
+ import dargs from 'dargs';
4
+ const glob = require('glob').sync;
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+
8
+ const repo = 'https://github.com/pyramation/tmpl-cosmwasm-module.git';
9
+ export default async argv => {
10
+ if (!shell.which('git')) {
11
+ shell.echo('Sorry, this script requires git');
12
+ return shell.exit(1);
13
+ }
14
+
15
+ const { name } = await prompt([
16
+ {
17
+ type: 'string',
18
+ name: 'name',
19
+ message: 'Enter your new module name',
20
+ }
21
+ ], argv);
22
+
23
+ shell.exec(`git clone ${repo} ${name}`);
24
+ shell.cd(name);
25
+
26
+ const questions = JSON.parse(fs.readFileSync(`.questions.json`));
27
+
28
+ const fullname = shell
29
+ .exec('git config --global user.name', { silent: true })
30
+ .trim();
31
+ const email = shell
32
+ .exec('git config --global user.email', { silent: true })
33
+ .trim();
34
+
35
+ // @__USERNAME__/__MODULENAME__
36
+ // __PACKAGE_IDENTIFIER__
37
+ const args = dargs(
38
+ {
39
+ _: [],
40
+ ...argv,
41
+ __MODULENAME__: name,
42
+ __USERFULLNAME__: fullname,
43
+ __USEREMAIL__: email,
44
+ },
45
+ { allowCamelCase: true }
46
+ );
47
+
48
+ const results = await prompt(questions, args);
49
+ let scopedResults;
50
+
51
+ const license = await prompt(
52
+ [
53
+ {
54
+ name: '__LICENSE__',
55
+ message: 'Which license?',
56
+ choices: ['MIT', 'closed'],
57
+ type: 'list',
58
+ required: true,
59
+ },
60
+ ],
61
+ []
62
+ );
63
+
64
+ if (results.__ACCESS__ === 'public') {
65
+ scopedResults = await prompt(
66
+ [
67
+ {
68
+ type: 'confirm',
69
+ name: 'scoped',
70
+ message: 'use npm scopes?',
71
+ required: true,
72
+ },
73
+ ],
74
+ []
75
+ );
76
+ }
77
+
78
+ const files = []
79
+ .concat(glob(process.cwd() + '/**/.*'))
80
+ .concat(glob(process.cwd() + '/**/*'));
81
+
82
+ for (let i = 0; i < files.length; i++) {
83
+ const templateFile = files[i];
84
+ if (fs.lstatSync(templateFile).isDirectory()) continue;
85
+
86
+ let content = fs.readFileSync(templateFile).toString();
87
+ if (
88
+ path.basename(templateFile) === 'LICENSE' &&
89
+ license.__LICENSE__ === 'closed'
90
+ ) {
91
+ content = `Copyright (c) 2022 __USERFULLNAME__ <__USEREMAIL__> - All Rights Reserved
92
+ Unauthorized copying via any medium is strictly prohibited
93
+ Proprietary and confidential`;
94
+ }
95
+
96
+ Object.keys(results).forEach(key => {
97
+ if (/^__/.test(key)) {
98
+ content = content.replace(new RegExp(key, 'g'), results[key]);
99
+ }
100
+ });
101
+
102
+ if (results.__ACCESS__ === 'public') {
103
+ if (scopedResults.scoped) {
104
+ content = content.replace(
105
+ /__PACKAGE_IDENTIFIER__/g,
106
+ `@${results.__USERNAME__}/${results.__MODULENAME__}`
107
+ );
108
+ } else {
109
+ content = content.replace(
110
+ /__PACKAGE_IDENTIFIER__/g,
111
+ `${results.__MODULENAME__}`
112
+ );
113
+ }
114
+ } else {
115
+ content = content.replace(
116
+ /__PACKAGE_IDENTIFIER__/g,
117
+ `@${results.__USERNAME__}/${results.__MODULENAME__}`
118
+ );
119
+ }
120
+
121
+ if (path.basename(templateFile) === 'README.md') {
122
+ content = `# ${results.__MODULENAME__}`;
123
+ }
124
+
125
+ fs.writeFileSync(templateFile, content);
126
+ }
127
+
128
+ shell.rm('-rf', '.git');
129
+ shell.rm('-rf', '.questions.json');
130
+
131
+ console.log(`
132
+
133
+ |||
134
+ (o o)
135
+ ooO--(_)--Ooo-
136
+
137
+ ✨ Great work!
138
+ `);
139
+ };
@@ -0,0 +1,156 @@
1
+ import { prompt } from '../utils/prompt';
2
+ import codegen from '../index';
3
+ import { TSBuilderOptions } from '../builder';
4
+
5
+ export default async (argv) => {
6
+ const questions = [
7
+ {
8
+ _: true,
9
+ type: 'path',
10
+ name: 'schema',
11
+ message: 'which directory contains the the Rust contracts?',
12
+ default: './schema'
13
+ },
14
+ {
15
+ _: true,
16
+ type: 'path',
17
+ name: 'out',
18
+ message: 'where is the output directory?',
19
+ default: './ts'
20
+ },
21
+ {
22
+ _: true,
23
+ type: 'string',
24
+ name: 'name',
25
+ message: 'contract name?'
26
+ },
27
+ {
28
+ type: 'checkbox',
29
+ name: 'plugin',
30
+ message: 'which plugins?',
31
+ choices: [
32
+ 'client',
33
+ 'recoil',
34
+ 'react-query',
35
+ 'message-composer'
36
+ ]
37
+ },
38
+ {
39
+ type: 'confirm',
40
+ name: 'bundle',
41
+ message: 'enable bundle?',
42
+ default: true
43
+ }
44
+ ];
45
+
46
+ if (argv.typesOnly) {
47
+ argv.plugin = 'types';
48
+ }
49
+
50
+ let { schema, out, name, plugin, bundle } = await prompt(questions, argv);
51
+ if (!Array.isArray(plugin)) plugin = [plugin];
52
+
53
+ ///////// REACT QUERY
54
+ const questions2 = [];
55
+ if (plugin.includes('react-query')) {
56
+ [].push.apply(questions2, [
57
+ {
58
+ type: 'confirm',
59
+ name: 'optionalClient',
60
+ message: 'optionalClient?',
61
+ default: false
62
+ },
63
+ {
64
+ type: 'list',
65
+ name: 'version',
66
+ message: 'which react-query version?',
67
+ default: 'v3',
68
+ choices: ['v3', 'v4']
69
+ },
70
+ {
71
+ type: 'confirm',
72
+ name: 'queryKeys',
73
+ message: 'queryKeys?',
74
+ default: false
75
+ },
76
+ ])
77
+ };
78
+ const { optionalClient, version, queryKeys } = await prompt(questions2, argv);
79
+ const questions3 = [];
80
+ if (version === 'v4') {
81
+ [].push.apply(questions3, [
82
+ // currently we only support v4 for useMutation
83
+ {
84
+ type: 'confirm',
85
+ name: 'mutations',
86
+ message: 'Generate useMutation hooks?',
87
+ default: false
88
+ }
89
+
90
+ ])
91
+ };
92
+ const { mutations } = await prompt(questions3, argv);
93
+ ///////// END REACT QUERY
94
+
95
+ ///////// BUNDLE
96
+ const questions4 = [];
97
+ if (bundle) {
98
+ [].push.apply(questions4, [
99
+ {
100
+ type: 'string',
101
+ name: 'bundleFile',
102
+ message: 'bundleFile?',
103
+ default: 'index.ts'
104
+ },
105
+ {
106
+ type: 'string',
107
+ name: 'bundleScope',
108
+ message: 'bundleScope?',
109
+ default: 'contracts'
110
+ }
111
+ ])
112
+ };
113
+ const { bundleFile, bundleScope } = await prompt(questions4, argv);
114
+ ///////// END BUNDLE
115
+
116
+ const options: TSBuilderOptions = {
117
+ types: {
118
+ enabled: true
119
+ },
120
+ client: {
121
+ enabled:
122
+ plugin.includes('client') ||
123
+ plugin.includes('recoil') ||
124
+ plugin.includes('react-query')
125
+ },
126
+ reactQuery: {
127
+ enabled: plugin.includes('react-query'),
128
+ optionalClient,
129
+ queryKeys,
130
+ version,
131
+ mutations
132
+ },
133
+ recoil: {
134
+ enabled: plugin.includes('recoil'),
135
+ },
136
+ messageComposer: {
137
+ enabled: plugin.includes('message-composer')
138
+ },
139
+ bundle: {
140
+ enabled: bundle,
141
+ scope: bundleScope,
142
+ bundleFile
143
+ }
144
+ };
145
+
146
+ await codegen({
147
+ contracts: [
148
+ {
149
+ name,
150
+ dir: schema
151
+ }
152
+ ],
153
+ outPath: out,
154
+ options
155
+ })
156
+ };