@dedot/codegen 0.4.1 → 0.5.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.
- package/chaintypes/generator/IndexGen.d.ts +3 -1
- package/chaintypes/generator/IndexGen.js +9 -3
- package/chaintypes/generator/JsonRpcGen.js +4 -2
- package/chaintypes/generator/TypesGen.js +2 -3
- package/chaintypes/index.d.ts +2 -1
- package/chaintypes/index.js +9 -10
- package/chaintypes/templates/index.hbs +1 -1
- package/chaintypes/templates/json-rpc.hbs +6 -1
- package/cjs/chaintypes/generator/IndexGen.js +8 -2
- package/cjs/chaintypes/generator/JsonRpcGen.js +4 -2
- package/cjs/chaintypes/generator/TypesGen.js +2 -3
- package/cjs/chaintypes/index.js +9 -10
- package/cjs/chaintypes/templates/index.hbs +1 -1
- package/cjs/chaintypes/templates/json-rpc.hbs +6 -1
- package/cjs/shared/BaseTypesGen.js +21 -10
- package/cjs/typink/generator/ConstructorQueryGen.js +2 -3
- package/cjs/typink/generator/ConstructorTxGen.js +3 -5
- package/cjs/typink/generator/EventsGen.js +0 -1
- package/cjs/typink/generator/IndexGen.js +9 -1
- package/cjs/typink/generator/QueryGen.js +8 -31
- package/cjs/typink/generator/TxGen.js +3 -5
- package/cjs/typink/generator/TypesGen.js +74 -4
- package/cjs/typink/index.js +1 -1
- package/cjs/typink/templates/index.hbs +1 -1
- package/package.json +10 -10
- package/shared/BaseTypesGen.d.ts +4 -2
- package/shared/BaseTypesGen.js +21 -10
- package/types.d.ts +1 -0
- package/typink/generator/ConstructorQueryGen.d.ts +1 -1
- package/typink/generator/ConstructorQueryGen.js +2 -3
- package/typink/generator/ConstructorTxGen.d.ts +1 -1
- package/typink/generator/ConstructorTxGen.js +3 -5
- package/typink/generator/EventsGen.js +0 -1
- package/typink/generator/IndexGen.js +10 -2
- package/typink/generator/QueryGen.d.ts +1 -2
- package/typink/generator/QueryGen.js +9 -32
- package/typink/generator/TxGen.d.ts +1 -1
- package/typink/generator/TxGen.js +3 -5
- package/typink/generator/TypesGen.d.ts +3 -0
- package/typink/generator/TypesGen.js +75 -5
- package/typink/index.js +1 -1
- package/typink/templates/index.hbs +1 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { SubstrateRuntimeVersion } from '@dedot/api';
|
|
1
2
|
export declare class IndexGen {
|
|
2
3
|
readonly interfaceName: string;
|
|
3
|
-
|
|
4
|
+
readonly runtimeVersion: SubstrateRuntimeVersion;
|
|
5
|
+
constructor(interfaceName: string, runtimeVersion: SubstrateRuntimeVersion);
|
|
4
6
|
generate(useSubPaths?: boolean): Promise<string>;
|
|
5
7
|
}
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
import { TypeImports } from '../../shared/index.js';
|
|
2
|
-
import { beautifySourceCode, compileTemplate } from '../../utils.js';
|
|
2
|
+
import { beautifySourceCode, commentBlock, compileTemplate } from '../../utils.js';
|
|
3
3
|
export class IndexGen {
|
|
4
4
|
interfaceName;
|
|
5
|
-
|
|
5
|
+
runtimeVersion;
|
|
6
|
+
constructor(interfaceName, runtimeVersion) {
|
|
6
7
|
this.interfaceName = interfaceName;
|
|
8
|
+
this.runtimeVersion = runtimeVersion;
|
|
7
9
|
}
|
|
8
10
|
async generate(useSubPaths = false) {
|
|
9
11
|
const interfaceName = this.interfaceName;
|
|
10
12
|
const typeImports = new TypeImports();
|
|
11
13
|
typeImports.addKnownType('GenericSubstrateApi', 'RpcLegacy', 'RpcV2', 'RpcVersion');
|
|
12
14
|
const importTypes = typeImports.toImports({ useSubPaths });
|
|
15
|
+
const interfaceDocs = commentBlock([
|
|
16
|
+
`@name: ${interfaceName}`, // prettier-end-here
|
|
17
|
+
`@specVersion: ${this.runtimeVersion.specVersion}`,
|
|
18
|
+
]);
|
|
13
19
|
const template = compileTemplate('chaintypes/templates/index.hbs');
|
|
14
|
-
return beautifySourceCode(template({
|
|
20
|
+
return beautifySourceCode(template({ interfaceName, interfaceDocs, importTypes }));
|
|
15
21
|
}
|
|
16
22
|
}
|
|
@@ -35,8 +35,10 @@ export class JsonRpcGen extends ApiGen {
|
|
|
35
35
|
super(typesGen);
|
|
36
36
|
this.typesGen = typesGen;
|
|
37
37
|
this.rpcMethods = rpcMethods;
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
if (rpcMethods.length > 0) {
|
|
39
|
+
HIDDEN_RPCS.filter((one) => !rpcMethods.includes(one)).forEach((one) => rpcMethods.push(one));
|
|
40
|
+
rpcMethods.sort();
|
|
41
|
+
}
|
|
40
42
|
}
|
|
41
43
|
generate(useSubPaths = false) {
|
|
42
44
|
this.typesGen.clearCache();
|
|
@@ -23,11 +23,10 @@ export class TypesGen extends BaseTypesGen {
|
|
|
23
23
|
metadata;
|
|
24
24
|
registry;
|
|
25
25
|
constructor(metadata) {
|
|
26
|
-
super(metadata.types);
|
|
26
|
+
super(metadata.types, SKIP_TYPES);
|
|
27
27
|
this.metadata = metadata;
|
|
28
|
-
this.skipTypes = SKIP_TYPES;
|
|
29
28
|
this.registry = new PortableRegistry(this.metadata);
|
|
30
|
-
this.includedTypes = this.
|
|
29
|
+
this.includedTypes = this.calculateIncludedTypes();
|
|
31
30
|
}
|
|
32
31
|
generate(useSubPaths = false) {
|
|
33
32
|
this.clearCache();
|
package/chaintypes/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
+
import { SubstrateRuntimeVersion } from '@dedot/api';
|
|
1
2
|
import { MetadataLatest } from '@dedot/codecs';
|
|
2
3
|
import { GeneratedResult } from '../types.js';
|
|
3
4
|
export declare function generateTypesFromEndpoint(chain: string, endpoint: string, outDir?: string, extension?: string, useSubPaths?: boolean): Promise<GeneratedResult>;
|
|
4
|
-
export declare function generateTypes(chain: string, metadata: MetadataLatest, rpcMethods: string[],
|
|
5
|
+
export declare function generateTypes(chain: string, metadata: MetadataLatest, rpcMethods: string[], runtimeVersion: SubstrateRuntimeVersion, outDir?: string, extension?: string, useSubPaths?: boolean): Promise<GeneratedResult>;
|
package/chaintypes/index.js
CHANGED
|
@@ -6,15 +6,14 @@ import * as path from 'path';
|
|
|
6
6
|
import { ConstsGen, ErrorsGen, EventsGen, IndexGen, JsonRpcGen, QueryGen, RuntimeApisGen, TxGen, TypesGen, } from './generator/index.js';
|
|
7
7
|
export async function generateTypesFromEndpoint(chain, endpoint, outDir, extension = 'd.ts', useSubPaths = false) {
|
|
8
8
|
// Immediately throw error if cannot connect to provider for the first time.
|
|
9
|
-
const
|
|
10
|
-
const { methods } = await
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
await api.disconnect();
|
|
9
|
+
const client = await LegacyClient.new(new WsProvider({ endpoint, retryDelayMs: 0, timeout: 0 }));
|
|
10
|
+
const { methods } = await client.rpc.rpc_methods();
|
|
11
|
+
chain = chain || client.runtimeVersion.specName || 'local';
|
|
12
|
+
const result = await generateTypes(chain, client.metadata.latest, methods, client.runtimeVersion, outDir, extension, useSubPaths);
|
|
13
|
+
await client.disconnect();
|
|
15
14
|
return result;
|
|
16
15
|
}
|
|
17
|
-
export async function generateTypes(chain, metadata, rpcMethods,
|
|
16
|
+
export async function generateTypes(chain, metadata, rpcMethods, runtimeVersion, outDir = '.', extension = 'd.ts', useSubPaths = false) {
|
|
18
17
|
const dirPath = path.resolve(outDir, stringDashCase(chain));
|
|
19
18
|
const defTypesFileName = path.join(dirPath, `types.${extension}`);
|
|
20
19
|
const constsTypesFileName = path.join(dirPath, `consts.${extension}`);
|
|
@@ -33,10 +32,10 @@ export async function generateTypes(chain, metadata, rpcMethods, runtimeApis, ou
|
|
|
33
32
|
const constsGen = new ConstsGen(typesGen);
|
|
34
33
|
const queryGen = new QueryGen(typesGen);
|
|
35
34
|
const jsonRpcGen = new JsonRpcGen(typesGen, rpcMethods);
|
|
36
|
-
const indexGen = new IndexGen(interfaceName);
|
|
35
|
+
const indexGen = new IndexGen(interfaceName, runtimeVersion);
|
|
37
36
|
const errorsGen = new ErrorsGen(typesGen);
|
|
38
37
|
const eventsGen = new EventsGen(typesGen);
|
|
39
|
-
const runtimeApisGen = new RuntimeApisGen(typesGen,
|
|
38
|
+
const runtimeApisGen = new RuntimeApisGen(typesGen, runtimeVersion.apis);
|
|
40
39
|
const txGen = new TxGen(typesGen);
|
|
41
40
|
fs.writeFileSync(defTypesFileName, await typesGen.generate(useSubPaths));
|
|
42
41
|
fs.writeFileSync(errorsFileName, await errorsGen.generate(useSubPaths));
|
|
@@ -47,5 +46,5 @@ export async function generateTypes(chain, metadata, rpcMethods, runtimeApis, ou
|
|
|
47
46
|
fs.writeFileSync(txFileName, await txGen.generate(useSubPaths));
|
|
48
47
|
fs.writeFileSync(indexFileName, await indexGen.generate(useSubPaths));
|
|
49
48
|
fs.writeFileSync(runtimeApisFileName, await runtimeApisGen.generate(useSubPaths));
|
|
50
|
-
return { interfaceName };
|
|
49
|
+
return { interfaceName, outputFolder: dirPath };
|
|
51
50
|
}
|
|
@@ -21,7 +21,7 @@ export interface Versioned{{{interfaceName}}}<Rv extends RpcVersion> extends Gen
|
|
|
21
21
|
tx: ChainTx<Rv>;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export interface {{{interfaceName}}} {
|
|
24
|
+
{{interfaceDocs}}export interface {{{interfaceName}}} {
|
|
25
25
|
legacy: Versioned{{{interfaceName}}}<RpcLegacy>;
|
|
26
26
|
v2: Versioned{{{interfaceName}}}<RpcV2>;
|
|
27
27
|
}
|
|
@@ -2,4 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
{{{ importTypes }}}
|
|
4
4
|
|
|
5
|
-
export type ChainJsonRpcApis<Rv extends RpcVersion> =
|
|
5
|
+
export type ChainJsonRpcApis<Rv extends RpcVersion> =
|
|
6
|
+
{{#if jsonRpcMethods.length}}
|
|
7
|
+
Pick<JsonRpcApis, {{{jsonRpcMethods}}}> & GenericJsonRpcApis<Rv>;
|
|
8
|
+
{{else}}
|
|
9
|
+
JsonRpcApis & GenericJsonRpcApis<Rv>;
|
|
10
|
+
{{/if}}
|
|
@@ -5,16 +5,22 @@ const index_js_1 = require("../../shared/index.js");
|
|
|
5
5
|
const utils_js_1 = require("../../utils.js");
|
|
6
6
|
class IndexGen {
|
|
7
7
|
interfaceName;
|
|
8
|
-
|
|
8
|
+
runtimeVersion;
|
|
9
|
+
constructor(interfaceName, runtimeVersion) {
|
|
9
10
|
this.interfaceName = interfaceName;
|
|
11
|
+
this.runtimeVersion = runtimeVersion;
|
|
10
12
|
}
|
|
11
13
|
async generate(useSubPaths = false) {
|
|
12
14
|
const interfaceName = this.interfaceName;
|
|
13
15
|
const typeImports = new index_js_1.TypeImports();
|
|
14
16
|
typeImports.addKnownType('GenericSubstrateApi', 'RpcLegacy', 'RpcV2', 'RpcVersion');
|
|
15
17
|
const importTypes = typeImports.toImports({ useSubPaths });
|
|
18
|
+
const interfaceDocs = (0, utils_js_1.commentBlock)([
|
|
19
|
+
`@name: ${interfaceName}`, // prettier-end-here
|
|
20
|
+
`@specVersion: ${this.runtimeVersion.specVersion}`,
|
|
21
|
+
]);
|
|
16
22
|
const template = (0, utils_js_1.compileTemplate)('chaintypes/templates/index.hbs');
|
|
17
|
-
return (0, utils_js_1.beautifySourceCode)(template({
|
|
23
|
+
return (0, utils_js_1.beautifySourceCode)(template({ interfaceName, interfaceDocs, importTypes }));
|
|
18
24
|
}
|
|
19
25
|
}
|
|
20
26
|
exports.IndexGen = IndexGen;
|
|
@@ -38,8 +38,10 @@ class JsonRpcGen extends ApiGen_js_1.ApiGen {
|
|
|
38
38
|
super(typesGen);
|
|
39
39
|
this.typesGen = typesGen;
|
|
40
40
|
this.rpcMethods = rpcMethods;
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
if (rpcMethods.length > 0) {
|
|
42
|
+
HIDDEN_RPCS.filter((one) => !rpcMethods.includes(one)).forEach((one) => rpcMethods.push(one));
|
|
43
|
+
rpcMethods.sort();
|
|
44
|
+
}
|
|
43
45
|
}
|
|
44
46
|
generate(useSubPaths = false) {
|
|
45
47
|
this.typesGen.clearCache();
|
|
@@ -26,11 +26,10 @@ class TypesGen extends index_js_1.BaseTypesGen {
|
|
|
26
26
|
metadata;
|
|
27
27
|
registry;
|
|
28
28
|
constructor(metadata) {
|
|
29
|
-
super(metadata.types);
|
|
29
|
+
super(metadata.types, SKIP_TYPES);
|
|
30
30
|
this.metadata = metadata;
|
|
31
|
-
this.skipTypes = SKIP_TYPES;
|
|
32
31
|
this.registry = new codecs_1.PortableRegistry(this.metadata);
|
|
33
|
-
this.includedTypes = this.
|
|
32
|
+
this.includedTypes = this.calculateIncludedTypes();
|
|
34
33
|
}
|
|
35
34
|
generate(useSubPaths = false) {
|
|
36
35
|
this.clearCache();
|
package/cjs/chaintypes/index.js
CHANGED
|
@@ -32,16 +32,15 @@ const path = __importStar(require("path"));
|
|
|
32
32
|
const index_js_1 = require("./generator/index.js");
|
|
33
33
|
async function generateTypesFromEndpoint(chain, endpoint, outDir, extension = 'd.ts', useSubPaths = false) {
|
|
34
34
|
// Immediately throw error if cannot connect to provider for the first time.
|
|
35
|
-
const
|
|
36
|
-
const { methods } = await
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
await api.disconnect();
|
|
35
|
+
const client = await api_1.LegacyClient.new(new providers_1.WsProvider({ endpoint, retryDelayMs: 0, timeout: 0 }));
|
|
36
|
+
const { methods } = await client.rpc.rpc_methods();
|
|
37
|
+
chain = chain || client.runtimeVersion.specName || 'local';
|
|
38
|
+
const result = await generateTypes(chain, client.metadata.latest, methods, client.runtimeVersion, outDir, extension, useSubPaths);
|
|
39
|
+
await client.disconnect();
|
|
41
40
|
return result;
|
|
42
41
|
}
|
|
43
42
|
exports.generateTypesFromEndpoint = generateTypesFromEndpoint;
|
|
44
|
-
async function generateTypes(chain, metadata, rpcMethods,
|
|
43
|
+
async function generateTypes(chain, metadata, rpcMethods, runtimeVersion, outDir = '.', extension = 'd.ts', useSubPaths = false) {
|
|
45
44
|
const dirPath = path.resolve(outDir, (0, utils_1.stringDashCase)(chain));
|
|
46
45
|
const defTypesFileName = path.join(dirPath, `types.${extension}`);
|
|
47
46
|
const constsTypesFileName = path.join(dirPath, `consts.${extension}`);
|
|
@@ -60,10 +59,10 @@ async function generateTypes(chain, metadata, rpcMethods, runtimeApis, outDir =
|
|
|
60
59
|
const constsGen = new index_js_1.ConstsGen(typesGen);
|
|
61
60
|
const queryGen = new index_js_1.QueryGen(typesGen);
|
|
62
61
|
const jsonRpcGen = new index_js_1.JsonRpcGen(typesGen, rpcMethods);
|
|
63
|
-
const indexGen = new index_js_1.IndexGen(interfaceName);
|
|
62
|
+
const indexGen = new index_js_1.IndexGen(interfaceName, runtimeVersion);
|
|
64
63
|
const errorsGen = new index_js_1.ErrorsGen(typesGen);
|
|
65
64
|
const eventsGen = new index_js_1.EventsGen(typesGen);
|
|
66
|
-
const runtimeApisGen = new index_js_1.RuntimeApisGen(typesGen,
|
|
65
|
+
const runtimeApisGen = new index_js_1.RuntimeApisGen(typesGen, runtimeVersion.apis);
|
|
67
66
|
const txGen = new index_js_1.TxGen(typesGen);
|
|
68
67
|
fs.writeFileSync(defTypesFileName, await typesGen.generate(useSubPaths));
|
|
69
68
|
fs.writeFileSync(errorsFileName, await errorsGen.generate(useSubPaths));
|
|
@@ -74,6 +73,6 @@ async function generateTypes(chain, metadata, rpcMethods, runtimeApis, outDir =
|
|
|
74
73
|
fs.writeFileSync(txFileName, await txGen.generate(useSubPaths));
|
|
75
74
|
fs.writeFileSync(indexFileName, await indexGen.generate(useSubPaths));
|
|
76
75
|
fs.writeFileSync(runtimeApisFileName, await runtimeApisGen.generate(useSubPaths));
|
|
77
|
-
return { interfaceName };
|
|
76
|
+
return { interfaceName, outputFolder: dirPath };
|
|
78
77
|
}
|
|
79
78
|
exports.generateTypes = generateTypes;
|
|
@@ -21,7 +21,7 @@ export interface Versioned{{{interfaceName}}}<Rv extends RpcVersion> extends Gen
|
|
|
21
21
|
tx: ChainTx<Rv>;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export interface {{{interfaceName}}} {
|
|
24
|
+
{{interfaceDocs}}export interface {{{interfaceName}}} {
|
|
25
25
|
legacy: Versioned{{{interfaceName}}}<RpcLegacy>;
|
|
26
26
|
v2: Versioned{{{interfaceName}}}<RpcV2>;
|
|
27
27
|
}
|
|
@@ -2,4 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
{{{ importTypes }}}
|
|
4
4
|
|
|
5
|
-
export type ChainJsonRpcApis<Rv extends RpcVersion> =
|
|
5
|
+
export type ChainJsonRpcApis<Rv extends RpcVersion> =
|
|
6
|
+
{{#if jsonRpcMethods.length}}
|
|
7
|
+
Pick<JsonRpcApis, {{{jsonRpcMethods}}}> & GenericJsonRpcApis<Rv>;
|
|
8
|
+
{{else}}
|
|
9
|
+
JsonRpcApis & GenericJsonRpcApis<Rv>;
|
|
10
|
+
{{/if}}
|
|
@@ -14,11 +14,13 @@ class BaseTypesGen {
|
|
|
14
14
|
includedTypes;
|
|
15
15
|
typeImports;
|
|
16
16
|
skipTypes;
|
|
17
|
-
|
|
17
|
+
knownTypes;
|
|
18
|
+
constructor(types, skipTypes = []) {
|
|
18
19
|
this.types = types;
|
|
19
|
-
this.
|
|
20
|
+
this.skipTypes = skipTypes;
|
|
20
21
|
this.typeImports = new TypeImports_js_1.TypeImports();
|
|
21
|
-
this.
|
|
22
|
+
this.knownTypes = this.calculateKnownTypes();
|
|
23
|
+
this.includedTypes = {};
|
|
22
24
|
}
|
|
23
25
|
shouldGenerateTypeIn(_id) {
|
|
24
26
|
return false;
|
|
@@ -28,7 +30,17 @@ class BaseTypesGen {
|
|
|
28
30
|
this.typeCache = {};
|
|
29
31
|
this.typeImports.clear();
|
|
30
32
|
}
|
|
31
|
-
|
|
33
|
+
calculateKnownTypes() {
|
|
34
|
+
const typesWithPath = this.types.filter((one) => one.path.length > 0);
|
|
35
|
+
return typesWithPath.reduce((o, type) => {
|
|
36
|
+
const { path, id } = type;
|
|
37
|
+
const [knownType, codecName] = (0, known_codecs_js_1.checkKnownCodecType)(path.join('::'));
|
|
38
|
+
if (!knownType)
|
|
39
|
+
return o;
|
|
40
|
+
return { ...o, [id]: codecName };
|
|
41
|
+
}, {});
|
|
42
|
+
}
|
|
43
|
+
calculateIncludedTypes() {
|
|
32
44
|
const pathsCount = new Map();
|
|
33
45
|
const typesWithPath = this.types.filter((one) => one.path.length > 0);
|
|
34
46
|
const skipIds = [];
|
|
@@ -60,14 +72,13 @@ class BaseTypesGen {
|
|
|
60
72
|
return o;
|
|
61
73
|
}
|
|
62
74
|
const suffix = typeSuffixes.get(id) || '';
|
|
63
|
-
let knownType = false;
|
|
64
75
|
let name, nameOut;
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
76
|
+
const knownCodecName = this.knownTypes[id];
|
|
77
|
+
const knownType = !!knownCodecName;
|
|
78
|
+
if (knownType) {
|
|
79
|
+
const codecType = (0, known_codecs_js_1.findKnownCodecType)(knownCodecName);
|
|
68
80
|
name = codecType.typeIn;
|
|
69
81
|
nameOut = codecType.typeOut;
|
|
70
|
-
knownType = true;
|
|
71
82
|
}
|
|
72
83
|
else if (PATH_RM_INDEX_1.includes(path[1])) {
|
|
73
84
|
const newPath = path.slice();
|
|
@@ -77,7 +88,7 @@ class BaseTypesGen {
|
|
|
77
88
|
else {
|
|
78
89
|
name = this.cleanPath(path);
|
|
79
90
|
}
|
|
80
|
-
if (this.shouldGenerateTypeIn(id)) {
|
|
91
|
+
if (!knownType && this.shouldGenerateTypeIn(id)) {
|
|
81
92
|
nameOut = name;
|
|
82
93
|
name = name.endsWith('Like') ? name : `${name}Like`;
|
|
83
94
|
}
|
|
@@ -14,14 +14,13 @@ class ConstructorQueryGen extends QueryGen_js_1.QueryGen {
|
|
|
14
14
|
const template = (0, utils_js_1.compileTemplate)('typink/templates/constructor-query.hbs');
|
|
15
15
|
return (0, utils_js_1.beautifySourceCode)(template({ importTypes, constructorsOut }));
|
|
16
16
|
}
|
|
17
|
-
generateMethodDef(def) {
|
|
17
|
+
generateMethodDef(def, optionsParamName = 'options') {
|
|
18
18
|
const { args, returnType } = def;
|
|
19
|
-
args.forEach(({ type: { type } }) => this.importType(type));
|
|
20
19
|
const paramsOut = this.generateParamsOut(args);
|
|
21
20
|
const typeOutRaw = this.typesGen.generateType(returnType.type, 0, true);
|
|
22
21
|
// Unwrap langError result
|
|
23
22
|
const typeOut = typeOutRaw.match(/^(\w+)<(.*), (.*)>$/).at(2);
|
|
24
|
-
return `GenericConstructorQueryCall<ChainApi, (${paramsOut && `${paramsOut},`}
|
|
23
|
+
return `GenericConstructorQueryCall<ChainApi, (${paramsOut && `${paramsOut},`} ${optionsParamName}: ConstructorCallOptions) => Promise<GenericConstructorCallResult<${typeOut}, ContractInstantiateResult<ChainApi>>>>`;
|
|
25
24
|
}
|
|
26
25
|
}
|
|
27
26
|
exports.ConstructorQueryGen = ConstructorQueryGen;
|
|
@@ -14,11 +14,9 @@ class ConstructorTxGen extends QueryGen_js_1.QueryGen {
|
|
|
14
14
|
const template = (0, utils_js_1.compileTemplate)('typink/templates/constructor-tx.hbs');
|
|
15
15
|
return (0, utils_js_1.beautifySourceCode)(template({ importTypes, constructorsOut }));
|
|
16
16
|
}
|
|
17
|
-
generateMethodDef(def) {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
const paramsOut = this.generateParamsOut(args);
|
|
21
|
-
return `GenericConstructorTxCall<ChainApi, (${paramsOut && `${paramsOut},`} options: ConstructorTxOptions) => GenericInstantiateSubmittableExtrinsic<ChainApi>>`;
|
|
17
|
+
generateMethodDef(def, optionsParamName = 'options') {
|
|
18
|
+
const paramsOut = this.generateParamsOut(def.args);
|
|
19
|
+
return `GenericConstructorTxCall<ChainApi, (${paramsOut && `${paramsOut},`} ${optionsParamName}: ConstructorTxOptions) => GenericInstantiateSubmittableExtrinsic<ChainApi>>`;
|
|
22
20
|
}
|
|
23
21
|
}
|
|
24
22
|
exports.ConstructorTxGen = ConstructorTxGen;
|
|
@@ -23,7 +23,6 @@ class EventsGen extends QueryGen_js_1.QueryGen {
|
|
|
23
23
|
}
|
|
24
24
|
#generateEventDef(event) {
|
|
25
25
|
const { args, label } = event;
|
|
26
|
-
args.forEach(({ type: { type } }) => this.importType(type));
|
|
27
26
|
const paramsOut = this.generateParamsOut(args);
|
|
28
27
|
return `GenericContractEvent<'${(0, utils_1.stringPascalCase)(label)}', {${paramsOut}}>`;
|
|
29
28
|
}
|
|
@@ -21,9 +21,17 @@ class IndexGen {
|
|
|
21
21
|
typeImports.addContractType('GenericContractApi');
|
|
22
22
|
typeImports.addChainType('SubstrateApi');
|
|
23
23
|
typeImports.addPortableType(langErrorName);
|
|
24
|
+
const { contract: { name = '', version = '', authors = [] }, source: { language = '' }, } = this.contractMetadata;
|
|
25
|
+
const interfaceDocs = (0, utils_js_1.commentBlock)([
|
|
26
|
+
`@name: ${interfaceName}`, // prettier-end-here
|
|
27
|
+
`@contractName: ${name}`,
|
|
28
|
+
`@contractVersion: ${version}`,
|
|
29
|
+
`@authors: ${authors.join(', ')}`,
|
|
30
|
+
`@language: ${language}`,
|
|
31
|
+
]);
|
|
24
32
|
const importTypes = typeImports.toImports({ useSubPaths });
|
|
25
33
|
const template = (0, utils_js_1.compileTemplate)('typink/templates/index.hbs');
|
|
26
|
-
return (0, utils_js_1.beautifySourceCode)(template({ interfaceName, langErrorName, importTypes }));
|
|
34
|
+
return (0, utils_js_1.beautifySourceCode)(template({ interfaceName, interfaceDocs, langErrorName, importTypes }));
|
|
27
35
|
}
|
|
28
36
|
}
|
|
29
37
|
exports.IndexGen = IndexGen;
|
|
@@ -25,50 +25,27 @@ class QueryGen {
|
|
|
25
25
|
let callsOut = '';
|
|
26
26
|
messages.forEach((messageDef) => {
|
|
27
27
|
const { label, docs, selector, args } = messageDef;
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
// In case there is an arg has label `options`,
|
|
29
|
+
// we use the name `_options` for the last options param
|
|
30
|
+
// This is just and edge case, so this approach works for now
|
|
31
|
+
const optionsParamName = args.some(({ label }) => label === 'options') ? '_options' : 'options';
|
|
32
|
+
callsOut += `${(0, utils_js_1.commentBlock)(docs, '\n', args.map((arg) => `@param {${this.typesGen.generateType(arg.type.type, 1)}} ${(0, utils_1.stringCamelCase)(arg.label)}`), optionsTypeName ? `@param {${optionsTypeName}} ${optionsParamName}` : '', '\n', `@selector ${selector}`)}`;
|
|
33
|
+
callsOut += `${(0, contracts_1.normalizeLabel)(label)}: ${this.generateMethodDef(messageDef, optionsParamName)};\n\n`;
|
|
30
34
|
});
|
|
31
35
|
return callsOut;
|
|
32
36
|
}
|
|
33
|
-
generateMethodDef(def) {
|
|
37
|
+
generateMethodDef(def, optionsParamName = 'options') {
|
|
34
38
|
const { args, returnType } = def;
|
|
35
|
-
this.importType(returnType.type);
|
|
36
|
-
args.forEach(({ type: { type } }) => this.importType(type));
|
|
37
39
|
const paramsOut = this.generateParamsOut(args);
|
|
38
40
|
const typeOutRaw = this.typesGen.generateType(returnType.type, 0, true);
|
|
39
41
|
// Unwrap langError result
|
|
40
42
|
const typeOut = typeOutRaw.match(/^(\w+)<(.*), (.*)>$/).at(2);
|
|
41
|
-
return `GenericContractQueryCall<ChainApi, (${paramsOut && `${paramsOut},`}
|
|
43
|
+
return `GenericContractQueryCall<ChainApi, (${paramsOut && `${paramsOut},`} ${optionsParamName}: ContractCallOptions) => Promise<GenericContractCallResult<${typeOut}, ContractCallResult<ChainApi>>>>`;
|
|
42
44
|
}
|
|
43
45
|
generateParamsOut(args) {
|
|
44
46
|
return args
|
|
45
47
|
.map(({ type: { type }, label }) => `${(0, utils_1.stringCamelCase)(label)}: ${this.typesGen.generateType(type, 1)}`)
|
|
46
48
|
.join(', ');
|
|
47
49
|
}
|
|
48
|
-
importType(typeId) {
|
|
49
|
-
const contractType = this.contractMetadata.types[typeId];
|
|
50
|
-
const typeDef = (0, contracts_1.normalizeContractTypeDef)(this.contractMetadata.types[typeId].type.def);
|
|
51
|
-
if (this.typesGen.includedTypes[contractType.id]) {
|
|
52
|
-
this.typesGen.addTypeImport(this.typesGen.includedTypes[contractType.id].name);
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
const { type, value } = typeDef;
|
|
56
|
-
switch (type) {
|
|
57
|
-
case 'Compact':
|
|
58
|
-
case 'Primitive':
|
|
59
|
-
case 'BitSequence':
|
|
60
|
-
return;
|
|
61
|
-
case 'Struct':
|
|
62
|
-
return value.fields.forEach(({ typeId }) => this.importType(typeId));
|
|
63
|
-
case 'Enum':
|
|
64
|
-
return value.members.forEach(({ fields }) => fields.map(({ typeId }) => this.importType(typeId)).flat());
|
|
65
|
-
case 'Tuple':
|
|
66
|
-
return value.fields.forEach((typeId) => this.importType(typeId));
|
|
67
|
-
case 'SizedVec':
|
|
68
|
-
return this.importType(value.typeParam);
|
|
69
|
-
case 'Sequence':
|
|
70
|
-
return this.importType(value.typeParam);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
50
|
}
|
|
74
51
|
exports.QueryGen = QueryGen;
|
|
@@ -15,11 +15,9 @@ class TxGen extends QueryGen_js_1.QueryGen {
|
|
|
15
15
|
const template = (0, utils_js_1.compileTemplate)('typink/templates/tx.hbs');
|
|
16
16
|
return (0, utils_js_1.beautifySourceCode)(template({ importTypes, txCallsOut }));
|
|
17
17
|
}
|
|
18
|
-
generateMethodDef(def) {
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
const paramsOut = this.generateParamsOut(args);
|
|
22
|
-
return `GenericContractTxCall<ChainApi, (${paramsOut && `${paramsOut},`} options: ContractTxOptions) => ContractSubmittableExtrinsic<ChainApi>>`;
|
|
18
|
+
generateMethodDef(def, optionsParamName = 'options') {
|
|
19
|
+
const paramsOut = this.generateParamsOut(def.args);
|
|
20
|
+
return `GenericContractTxCall<ChainApi, (${paramsOut && `${paramsOut},`} ${optionsParamName}: ContractTxOptions) => ContractSubmittableExtrinsic<ChainApi>>`;
|
|
23
21
|
}
|
|
24
22
|
}
|
|
25
23
|
exports.TxGen = TxGen;
|
|
@@ -8,21 +8,91 @@ const SKIP_TYPES = ['Result', 'Option'];
|
|
|
8
8
|
class TypesGen extends index_js_1.BaseTypesGen {
|
|
9
9
|
contractMetadata;
|
|
10
10
|
constructor(contractMetadata) {
|
|
11
|
-
super((0, contracts_1.extractContractTypes)(contractMetadata));
|
|
11
|
+
super((0, contracts_1.extractContractTypes)(contractMetadata), SKIP_TYPES);
|
|
12
12
|
this.contractMetadata = contractMetadata;
|
|
13
|
-
this.
|
|
14
|
-
this.includedTypes = this.includeTypes();
|
|
13
|
+
this.includedTypes = this.calculateIncludedTypes();
|
|
15
14
|
}
|
|
16
15
|
generate(useSubPaths = false) {
|
|
17
16
|
let defTypeOut = '';
|
|
18
17
|
Object.values(this.includedTypes)
|
|
19
18
|
.filter(({ skip, knownType }) => !(skip || knownType))
|
|
20
|
-
.forEach(({ nameOut, id }) => {
|
|
19
|
+
.forEach(({ nameOut, name, id }) => {
|
|
21
20
|
defTypeOut += `export type ${nameOut} = ${this.generateType(id, 0, true)};\n\n`;
|
|
21
|
+
if (this.shouldGenerateTypeIn(id)) {
|
|
22
|
+
defTypeOut += `export type ${name} = ${this.generateType(id, 0)};\n\n`;
|
|
23
|
+
}
|
|
22
24
|
});
|
|
23
25
|
const importTypes = this.typeImports.toImports({ excludeModules: ['./types'], useSubPaths });
|
|
24
26
|
const template = (0, utils_js_1.compileTemplate)('typink/templates/types.hbs');
|
|
25
27
|
return (0, utils_js_1.beautifySourceCode)(template({ importTypes, defTypeOut }));
|
|
26
28
|
}
|
|
29
|
+
shouldGenerateTypeIn(id) {
|
|
30
|
+
const { messages, constructors } = this.contractMetadata.spec;
|
|
31
|
+
return ((this.#idInParameters(id, messages) || this.#idInParameters(id, constructors)) && this.#includeKnownTypes(id));
|
|
32
|
+
}
|
|
33
|
+
#idInParameters(id, messages) {
|
|
34
|
+
for (let message of messages) {
|
|
35
|
+
// prettier-ignore
|
|
36
|
+
const isIn = message.args.reduce((a, { type: { type: typeId } }) => a || this.#typeDependOn(typeId, id), false);
|
|
37
|
+
if (isIn)
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
// Find out does type depends on known types
|
|
43
|
+
// Example: `type TypeA = Struct { field: AccountId }` => includeKnownTypes(TypeA) === true
|
|
44
|
+
#includeKnownTypes(typeId) {
|
|
45
|
+
if (this.knownTypes[typeId])
|
|
46
|
+
return true;
|
|
47
|
+
const { types } = this.contractMetadata;
|
|
48
|
+
const defA = (0, contracts_1.normalizeContractTypeDef)(types[typeId].type.def);
|
|
49
|
+
const { type, value } = defA;
|
|
50
|
+
switch (type) {
|
|
51
|
+
case 'Struct':
|
|
52
|
+
return value.fields.some(({ typeId }) => this.#includeKnownTypes(typeId));
|
|
53
|
+
case 'Enum':
|
|
54
|
+
return value.members.some(({ fields }) => fields.some(({ typeId }) => this.#includeKnownTypes(typeId)));
|
|
55
|
+
case 'Tuple':
|
|
56
|
+
return value.fields.some((typeId) => this.#includeKnownTypes(typeId));
|
|
57
|
+
case 'Sequence':
|
|
58
|
+
case 'SizedVec':
|
|
59
|
+
const $innerType = this.types[value.typeParam].typeDef;
|
|
60
|
+
if ($innerType.type === 'Primitive' && $innerType.value.kind === 'u8') {
|
|
61
|
+
return true; // ByteLikes
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
return this.#includeKnownTypes(value.typeParam);
|
|
65
|
+
}
|
|
66
|
+
case 'Primitive':
|
|
67
|
+
case 'Compact':
|
|
68
|
+
case 'BitSequence':
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Find out does typeA depends on typeB
|
|
73
|
+
// Example: `type TypeA = Struct { field: TypeB }` => typeDependOn(TypeA, TypeB) === true
|
|
74
|
+
#typeDependOn(typeA, typeB) {
|
|
75
|
+
if (typeA === typeB)
|
|
76
|
+
return true;
|
|
77
|
+
const { types } = this.contractMetadata;
|
|
78
|
+
const defA = (0, contracts_1.normalizeContractTypeDef)(types[typeA].type.def);
|
|
79
|
+
const { type, value } = defA;
|
|
80
|
+
// prettier-ignore
|
|
81
|
+
switch (type) {
|
|
82
|
+
case 'Struct':
|
|
83
|
+
return value.fields.reduce((a, { typeId }) => a || this.#typeDependOn(typeId, typeB), false);
|
|
84
|
+
case 'Enum':
|
|
85
|
+
return value.members.reduce((a, { fields }) => a || fields.reduce((a, { typeId }) => a || this.#typeDependOn(typeId, typeB), false), false);
|
|
86
|
+
case 'Tuple':
|
|
87
|
+
return value.fields.reduce((a, typeId) => a || this.#typeDependOn(typeId, typeB), false);
|
|
88
|
+
case 'Sequence':
|
|
89
|
+
case 'SizedVec':
|
|
90
|
+
return this.#typeDependOn(value.typeParam, typeB);
|
|
91
|
+
case 'Primitive':
|
|
92
|
+
case 'Compact':
|
|
93
|
+
case 'BitSequence':
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
27
97
|
}
|
|
28
98
|
exports.TypesGen = TypesGen;
|
package/cjs/typink/index.js
CHANGED
|
@@ -38,6 +38,6 @@ async function generateContractTypes(metadata, contract, outDir = '.', extension
|
|
|
38
38
|
fs_1.default.writeFileSync(constructorTxTypesFileName, await constructorTxGen.generate(useSubPaths));
|
|
39
39
|
fs_1.default.writeFileSync(eventsTypesFile, await eventsGen.generate(useSubPaths));
|
|
40
40
|
fs_1.default.writeFileSync(indexTypesFileName, await indexGen.generate(useSubPaths));
|
|
41
|
-
return { interfaceName };
|
|
41
|
+
return { interfaceName, outputFolder: dirPath };
|
|
42
42
|
}
|
|
43
43
|
exports.generateContractTypes = generateContractTypes;
|
|
@@ -9,7 +9,7 @@ import { ContractEvents } from './events';
|
|
|
9
9
|
|
|
10
10
|
export * from './types';
|
|
11
11
|
|
|
12
|
-
export interface {{{interfaceName}}}<Rv extends RpcVersion =
|
|
12
|
+
{{{interfaceDocs}}}export interface {{{interfaceName}}}<Rv extends RpcVersion = RpcVersion, ChainApi extends VersionedGenericSubstrateApi = SubstrateApi> extends GenericContractApi<Rv, ChainApi> {
|
|
13
13
|
query: ContractQuery<ChainApi[Rv]>;
|
|
14
14
|
tx: ContractTx<ChainApi[Rv]>;
|
|
15
15
|
constructorQuery: ConstructorQuery<ChainApi[Rv]>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dedot/codegen",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Generate types",
|
|
5
5
|
"author": "Thang X. Vu <thang@coongcrafts.io>",
|
|
6
6
|
"homepage": "https://github.com/dedotdev/dedot/tree/main/packages/codegen",
|
|
@@ -18,14 +18,14 @@
|
|
|
18
18
|
"copy": "cp -R ./src/chaintypes/templates ./dist/chaintypes && cp -R ./src/chaintypes/templates ./dist/cjs/chaintypes && cp -R ./src/typink/templates ./dist/typink && cp -R ./src/typink/templates ./dist/cjs/typink"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@dedot/api": "0.
|
|
22
|
-
"@dedot/codecs": "0.
|
|
23
|
-
"@dedot/contracts": "0.
|
|
24
|
-
"@dedot/providers": "0.
|
|
25
|
-
"@dedot/runtime-specs": "0.
|
|
26
|
-
"@dedot/shape": "0.
|
|
27
|
-
"@dedot/types": "0.
|
|
28
|
-
"@dedot/utils": "0.
|
|
21
|
+
"@dedot/api": "0.5.0",
|
|
22
|
+
"@dedot/codecs": "0.5.0",
|
|
23
|
+
"@dedot/contracts": "0.5.0",
|
|
24
|
+
"@dedot/providers": "0.5.0",
|
|
25
|
+
"@dedot/runtime-specs": "0.5.0",
|
|
26
|
+
"@dedot/shape": "0.5.0",
|
|
27
|
+
"@dedot/types": "0.5.0",
|
|
28
|
+
"@dedot/utils": "0.5.0",
|
|
29
29
|
"handlebars": "^4.7.8",
|
|
30
30
|
"prettier": "^3.3.3"
|
|
31
31
|
},
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"directory": "dist"
|
|
35
35
|
},
|
|
36
36
|
"license": "Apache-2.0",
|
|
37
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "968148ade63e07644094fc033be719b320e18a18",
|
|
38
38
|
"module": "./index.js",
|
|
39
39
|
"types": "./index.d.ts",
|
|
40
40
|
"exports": {
|
package/shared/BaseTypesGen.d.ts
CHANGED
|
@@ -15,11 +15,13 @@ export declare abstract class BaseTypesGen {
|
|
|
15
15
|
includedTypes: Record<TypeId, NamedType>;
|
|
16
16
|
typeImports: TypeImports;
|
|
17
17
|
skipTypes: string[];
|
|
18
|
-
|
|
18
|
+
knownTypes: Record<TypeId, string>;
|
|
19
|
+
protected constructor(types: PortableType[], skipTypes?: string[]);
|
|
19
20
|
shouldGenerateTypeIn(_id: TypeId): boolean;
|
|
20
21
|
typeCache: Record<string, string>;
|
|
21
22
|
clearCache(): void;
|
|
22
|
-
|
|
23
|
+
protected calculateKnownTypes(): Record<TypeId, string>;
|
|
24
|
+
protected calculateIncludedTypes(): Record<TypeId, NamedType>;
|
|
23
25
|
generateType(typeId: TypeId, nestedLevel?: number, typeOut?: boolean): string;
|
|
24
26
|
generateObjectType(fields: Field[], nestedLevel?: number, typeOut?: boolean): string;
|
|
25
27
|
cleanPath(path: string[]): string;
|
package/shared/BaseTypesGen.js
CHANGED
|
@@ -11,11 +11,13 @@ export class BaseTypesGen {
|
|
|
11
11
|
includedTypes;
|
|
12
12
|
typeImports;
|
|
13
13
|
skipTypes;
|
|
14
|
-
|
|
14
|
+
knownTypes;
|
|
15
|
+
constructor(types, skipTypes = []) {
|
|
15
16
|
this.types = types;
|
|
16
|
-
this.
|
|
17
|
+
this.skipTypes = skipTypes;
|
|
17
18
|
this.typeImports = new TypeImports();
|
|
18
|
-
this.
|
|
19
|
+
this.knownTypes = this.calculateKnownTypes();
|
|
20
|
+
this.includedTypes = {};
|
|
19
21
|
}
|
|
20
22
|
shouldGenerateTypeIn(_id) {
|
|
21
23
|
return false;
|
|
@@ -25,7 +27,17 @@ export class BaseTypesGen {
|
|
|
25
27
|
this.typeCache = {};
|
|
26
28
|
this.typeImports.clear();
|
|
27
29
|
}
|
|
28
|
-
|
|
30
|
+
calculateKnownTypes() {
|
|
31
|
+
const typesWithPath = this.types.filter((one) => one.path.length > 0);
|
|
32
|
+
return typesWithPath.reduce((o, type) => {
|
|
33
|
+
const { path, id } = type;
|
|
34
|
+
const [knownType, codecName] = checkKnownCodecType(path.join('::'));
|
|
35
|
+
if (!knownType)
|
|
36
|
+
return o;
|
|
37
|
+
return { ...o, [id]: codecName };
|
|
38
|
+
}, {});
|
|
39
|
+
}
|
|
40
|
+
calculateIncludedTypes() {
|
|
29
41
|
const pathsCount = new Map();
|
|
30
42
|
const typesWithPath = this.types.filter((one) => one.path.length > 0);
|
|
31
43
|
const skipIds = [];
|
|
@@ -57,14 +69,13 @@ export class BaseTypesGen {
|
|
|
57
69
|
return o;
|
|
58
70
|
}
|
|
59
71
|
const suffix = typeSuffixes.get(id) || '';
|
|
60
|
-
let knownType = false;
|
|
61
72
|
let name, nameOut;
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
73
|
+
const knownCodecName = this.knownTypes[id];
|
|
74
|
+
const knownType = !!knownCodecName;
|
|
75
|
+
if (knownType) {
|
|
76
|
+
const codecType = findKnownCodecType(knownCodecName);
|
|
65
77
|
name = codecType.typeIn;
|
|
66
78
|
nameOut = codecType.typeOut;
|
|
67
|
-
knownType = true;
|
|
68
79
|
}
|
|
69
80
|
else if (PATH_RM_INDEX_1.includes(path[1])) {
|
|
70
81
|
const newPath = path.slice();
|
|
@@ -74,7 +85,7 @@ export class BaseTypesGen {
|
|
|
74
85
|
else {
|
|
75
86
|
name = this.cleanPath(path);
|
|
76
87
|
}
|
|
77
|
-
if (this.shouldGenerateTypeIn(id)) {
|
|
88
|
+
if (!knownType && this.shouldGenerateTypeIn(id)) {
|
|
78
89
|
nameOut = name;
|
|
79
90
|
name = name.endsWith('Like') ? name : `${name}Like`;
|
|
80
91
|
}
|
package/types.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ import { ContractConstructorMessage } from '@dedot/contracts';
|
|
|
2
2
|
import { QueryGen } from './QueryGen.js';
|
|
3
3
|
export declare class ConstructorQueryGen extends QueryGen {
|
|
4
4
|
generate(useSubPaths?: boolean): Promise<string>;
|
|
5
|
-
generateMethodDef(def: ContractConstructorMessage): string;
|
|
5
|
+
generateMethodDef(def: ContractConstructorMessage, optionsParamName?: string): string;
|
|
6
6
|
}
|
|
@@ -11,13 +11,12 @@ export class ConstructorQueryGen extends QueryGen {
|
|
|
11
11
|
const template = compileTemplate('typink/templates/constructor-query.hbs');
|
|
12
12
|
return beautifySourceCode(template({ importTypes, constructorsOut }));
|
|
13
13
|
}
|
|
14
|
-
generateMethodDef(def) {
|
|
14
|
+
generateMethodDef(def, optionsParamName = 'options') {
|
|
15
15
|
const { args, returnType } = def;
|
|
16
|
-
args.forEach(({ type: { type } }) => this.importType(type));
|
|
17
16
|
const paramsOut = this.generateParamsOut(args);
|
|
18
17
|
const typeOutRaw = this.typesGen.generateType(returnType.type, 0, true);
|
|
19
18
|
// Unwrap langError result
|
|
20
19
|
const typeOut = typeOutRaw.match(/^(\w+)<(.*), (.*)>$/).at(2);
|
|
21
|
-
return `GenericConstructorQueryCall<ChainApi, (${paramsOut && `${paramsOut},`}
|
|
20
|
+
return `GenericConstructorQueryCall<ChainApi, (${paramsOut && `${paramsOut},`} ${optionsParamName}: ConstructorCallOptions) => Promise<GenericConstructorCallResult<${typeOut}, ContractInstantiateResult<ChainApi>>>>`;
|
|
22
21
|
}
|
|
23
22
|
}
|
|
@@ -2,5 +2,5 @@ import { ContractConstructorMessage } from '@dedot/contracts';
|
|
|
2
2
|
import { QueryGen } from './QueryGen.js';
|
|
3
3
|
export declare class ConstructorTxGen extends QueryGen {
|
|
4
4
|
generate(useSubPaths?: boolean): Promise<string>;
|
|
5
|
-
generateMethodDef(def: ContractConstructorMessage): string;
|
|
5
|
+
generateMethodDef(def: ContractConstructorMessage, optionsParamName?: string): string;
|
|
6
6
|
}
|
|
@@ -11,10 +11,8 @@ export class ConstructorTxGen extends QueryGen {
|
|
|
11
11
|
const template = compileTemplate('typink/templates/constructor-tx.hbs');
|
|
12
12
|
return beautifySourceCode(template({ importTypes, constructorsOut }));
|
|
13
13
|
}
|
|
14
|
-
generateMethodDef(def) {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
const paramsOut = this.generateParamsOut(args);
|
|
18
|
-
return `GenericConstructorTxCall<ChainApi, (${paramsOut && `${paramsOut},`} options: ConstructorTxOptions) => GenericInstantiateSubmittableExtrinsic<ChainApi>>`;
|
|
14
|
+
generateMethodDef(def, optionsParamName = 'options') {
|
|
15
|
+
const paramsOut = this.generateParamsOut(def.args);
|
|
16
|
+
return `GenericConstructorTxCall<ChainApi, (${paramsOut && `${paramsOut},`} ${optionsParamName}: ConstructorTxOptions) => GenericInstantiateSubmittableExtrinsic<ChainApi>>`;
|
|
19
17
|
}
|
|
20
18
|
}
|
|
@@ -20,7 +20,6 @@ export class EventsGen extends QueryGen {
|
|
|
20
20
|
}
|
|
21
21
|
#generateEventDef(event) {
|
|
22
22
|
const { args, label } = event;
|
|
23
|
-
args.forEach(({ type: { type } }) => this.importType(type));
|
|
24
23
|
const paramsOut = this.generateParamsOut(args);
|
|
25
24
|
return `GenericContractEvent<'${stringPascalCase(label)}', {${paramsOut}}>`;
|
|
26
25
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TypeImports } from '../../shared/index.js';
|
|
2
|
-
import { beautifySourceCode, compileTemplate } from '../../utils.js';
|
|
2
|
+
import { beautifySourceCode, commentBlock, compileTemplate } from '../../utils.js';
|
|
3
3
|
export class IndexGen {
|
|
4
4
|
interfaceName;
|
|
5
5
|
contractMetadata;
|
|
@@ -18,8 +18,16 @@ export class IndexGen {
|
|
|
18
18
|
typeImports.addContractType('GenericContractApi');
|
|
19
19
|
typeImports.addChainType('SubstrateApi');
|
|
20
20
|
typeImports.addPortableType(langErrorName);
|
|
21
|
+
const { contract: { name = '', version = '', authors = [] }, source: { language = '' }, } = this.contractMetadata;
|
|
22
|
+
const interfaceDocs = commentBlock([
|
|
23
|
+
`@name: ${interfaceName}`, // prettier-end-here
|
|
24
|
+
`@contractName: ${name}`,
|
|
25
|
+
`@contractVersion: ${version}`,
|
|
26
|
+
`@authors: ${authors.join(', ')}`,
|
|
27
|
+
`@language: ${language}`,
|
|
28
|
+
]);
|
|
21
29
|
const importTypes = typeImports.toImports({ useSubPaths });
|
|
22
30
|
const template = compileTemplate('typink/templates/index.hbs');
|
|
23
|
-
return beautifySourceCode(template({ interfaceName, langErrorName, importTypes }));
|
|
31
|
+
return beautifySourceCode(template({ interfaceName, interfaceDocs, langErrorName, importTypes }));
|
|
24
32
|
}
|
|
25
33
|
}
|
|
@@ -6,7 +6,6 @@ export declare class QueryGen {
|
|
|
6
6
|
constructor(contractMetadata: ContractMetadata, typeGen: TypesGen);
|
|
7
7
|
generate(useSubPaths?: boolean): Promise<string>;
|
|
8
8
|
doGenerate(messages: ContractMessage[], optionsTypeName?: string): string;
|
|
9
|
-
generateMethodDef(def: ContractMessage): string;
|
|
9
|
+
generateMethodDef(def: ContractMessage, optionsParamName?: string): string;
|
|
10
10
|
generateParamsOut(args: ContractMessageArg[]): string;
|
|
11
|
-
importType(typeId: number): any;
|
|
12
11
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizeLabel } from '@dedot/contracts';
|
|
2
2
|
import { stringCamelCase } from '@dedot/utils';
|
|
3
3
|
import { beautifySourceCode, commentBlock, compileTemplate } from '../../utils.js';
|
|
4
4
|
export class QueryGen {
|
|
@@ -22,49 +22,26 @@ export class QueryGen {
|
|
|
22
22
|
let callsOut = '';
|
|
23
23
|
messages.forEach((messageDef) => {
|
|
24
24
|
const { label, docs, selector, args } = messageDef;
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
// In case there is an arg has label `options`,
|
|
26
|
+
// we use the name `_options` for the last options param
|
|
27
|
+
// This is just and edge case, so this approach works for now
|
|
28
|
+
const optionsParamName = args.some(({ label }) => label === 'options') ? '_options' : 'options';
|
|
29
|
+
callsOut += `${commentBlock(docs, '\n', args.map((arg) => `@param {${this.typesGen.generateType(arg.type.type, 1)}} ${stringCamelCase(arg.label)}`), optionsTypeName ? `@param {${optionsTypeName}} ${optionsParamName}` : '', '\n', `@selector ${selector}`)}`;
|
|
30
|
+
callsOut += `${normalizeLabel(label)}: ${this.generateMethodDef(messageDef, optionsParamName)};\n\n`;
|
|
27
31
|
});
|
|
28
32
|
return callsOut;
|
|
29
33
|
}
|
|
30
|
-
generateMethodDef(def) {
|
|
34
|
+
generateMethodDef(def, optionsParamName = 'options') {
|
|
31
35
|
const { args, returnType } = def;
|
|
32
|
-
this.importType(returnType.type);
|
|
33
|
-
args.forEach(({ type: { type } }) => this.importType(type));
|
|
34
36
|
const paramsOut = this.generateParamsOut(args);
|
|
35
37
|
const typeOutRaw = this.typesGen.generateType(returnType.type, 0, true);
|
|
36
38
|
// Unwrap langError result
|
|
37
39
|
const typeOut = typeOutRaw.match(/^(\w+)<(.*), (.*)>$/).at(2);
|
|
38
|
-
return `GenericContractQueryCall<ChainApi, (${paramsOut && `${paramsOut},`}
|
|
40
|
+
return `GenericContractQueryCall<ChainApi, (${paramsOut && `${paramsOut},`} ${optionsParamName}: ContractCallOptions) => Promise<GenericContractCallResult<${typeOut}, ContractCallResult<ChainApi>>>>`;
|
|
39
41
|
}
|
|
40
42
|
generateParamsOut(args) {
|
|
41
43
|
return args
|
|
42
44
|
.map(({ type: { type }, label }) => `${stringCamelCase(label)}: ${this.typesGen.generateType(type, 1)}`)
|
|
43
45
|
.join(', ');
|
|
44
46
|
}
|
|
45
|
-
importType(typeId) {
|
|
46
|
-
const contractType = this.contractMetadata.types[typeId];
|
|
47
|
-
const typeDef = normalizeContractTypeDef(this.contractMetadata.types[typeId].type.def);
|
|
48
|
-
if (this.typesGen.includedTypes[contractType.id]) {
|
|
49
|
-
this.typesGen.addTypeImport(this.typesGen.includedTypes[contractType.id].name);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
const { type, value } = typeDef;
|
|
53
|
-
switch (type) {
|
|
54
|
-
case 'Compact':
|
|
55
|
-
case 'Primitive':
|
|
56
|
-
case 'BitSequence':
|
|
57
|
-
return;
|
|
58
|
-
case 'Struct':
|
|
59
|
-
return value.fields.forEach(({ typeId }) => this.importType(typeId));
|
|
60
|
-
case 'Enum':
|
|
61
|
-
return value.members.forEach(({ fields }) => fields.map(({ typeId }) => this.importType(typeId)).flat());
|
|
62
|
-
case 'Tuple':
|
|
63
|
-
return value.fields.forEach((typeId) => this.importType(typeId));
|
|
64
|
-
case 'SizedVec':
|
|
65
|
-
return this.importType(value.typeParam);
|
|
66
|
-
case 'Sequence':
|
|
67
|
-
return this.importType(value.typeParam);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
47
|
}
|
|
@@ -2,5 +2,5 @@ import { ContractMessage } from '@dedot/contracts';
|
|
|
2
2
|
import { QueryGen } from './QueryGen.js';
|
|
3
3
|
export declare class TxGen extends QueryGen {
|
|
4
4
|
generate(useSubPaths?: boolean): Promise<string>;
|
|
5
|
-
generateMethodDef(def: ContractMessage): string;
|
|
5
|
+
generateMethodDef(def: ContractMessage, optionsParamName?: string): string;
|
|
6
6
|
}
|
|
@@ -12,10 +12,8 @@ export class TxGen extends QueryGen {
|
|
|
12
12
|
const template = compileTemplate('typink/templates/tx.hbs');
|
|
13
13
|
return beautifySourceCode(template({ importTypes, txCallsOut }));
|
|
14
14
|
}
|
|
15
|
-
generateMethodDef(def) {
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
const paramsOut = this.generateParamsOut(args);
|
|
19
|
-
return `GenericContractTxCall<ChainApi, (${paramsOut && `${paramsOut},`} options: ContractTxOptions) => ContractSubmittableExtrinsic<ChainApi>>`;
|
|
15
|
+
generateMethodDef(def, optionsParamName = 'options') {
|
|
16
|
+
const paramsOut = this.generateParamsOut(def.args);
|
|
17
|
+
return `GenericContractTxCall<ChainApi, (${paramsOut && `${paramsOut},`} ${optionsParamName}: ContractTxOptions) => ContractSubmittableExtrinsic<ChainApi>>`;
|
|
20
18
|
}
|
|
21
19
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { TypeId } from '@dedot/codecs';
|
|
1
2
|
import { ContractMetadata } from '@dedot/contracts';
|
|
2
3
|
import { BaseTypesGen } from '../../shared/index.js';
|
|
3
4
|
export declare class TypesGen extends BaseTypesGen {
|
|
5
|
+
#private;
|
|
4
6
|
contractMetadata: ContractMetadata;
|
|
5
7
|
constructor(contractMetadata: ContractMetadata);
|
|
6
8
|
generate(useSubPaths?: boolean): Promise<string>;
|
|
9
|
+
shouldGenerateTypeIn(id: TypeId): boolean;
|
|
7
10
|
}
|
|
@@ -1,24 +1,94 @@
|
|
|
1
|
-
import { extractContractTypes } from '@dedot/contracts';
|
|
1
|
+
import { extractContractTypes, normalizeContractTypeDef } from '@dedot/contracts';
|
|
2
2
|
import { BaseTypesGen } from '../../shared/index.js';
|
|
3
3
|
import { beautifySourceCode, compileTemplate } from '../../utils.js';
|
|
4
4
|
const SKIP_TYPES = ['Result', 'Option'];
|
|
5
5
|
export class TypesGen extends BaseTypesGen {
|
|
6
6
|
contractMetadata;
|
|
7
7
|
constructor(contractMetadata) {
|
|
8
|
-
super(extractContractTypes(contractMetadata));
|
|
8
|
+
super(extractContractTypes(contractMetadata), SKIP_TYPES);
|
|
9
9
|
this.contractMetadata = contractMetadata;
|
|
10
|
-
this.
|
|
11
|
-
this.includedTypes = this.includeTypes();
|
|
10
|
+
this.includedTypes = this.calculateIncludedTypes();
|
|
12
11
|
}
|
|
13
12
|
generate(useSubPaths = false) {
|
|
14
13
|
let defTypeOut = '';
|
|
15
14
|
Object.values(this.includedTypes)
|
|
16
15
|
.filter(({ skip, knownType }) => !(skip || knownType))
|
|
17
|
-
.forEach(({ nameOut, id }) => {
|
|
16
|
+
.forEach(({ nameOut, name, id }) => {
|
|
18
17
|
defTypeOut += `export type ${nameOut} = ${this.generateType(id, 0, true)};\n\n`;
|
|
18
|
+
if (this.shouldGenerateTypeIn(id)) {
|
|
19
|
+
defTypeOut += `export type ${name} = ${this.generateType(id, 0)};\n\n`;
|
|
20
|
+
}
|
|
19
21
|
});
|
|
20
22
|
const importTypes = this.typeImports.toImports({ excludeModules: ['./types'], useSubPaths });
|
|
21
23
|
const template = compileTemplate('typink/templates/types.hbs');
|
|
22
24
|
return beautifySourceCode(template({ importTypes, defTypeOut }));
|
|
23
25
|
}
|
|
26
|
+
shouldGenerateTypeIn(id) {
|
|
27
|
+
const { messages, constructors } = this.contractMetadata.spec;
|
|
28
|
+
return ((this.#idInParameters(id, messages) || this.#idInParameters(id, constructors)) && this.#includeKnownTypes(id));
|
|
29
|
+
}
|
|
30
|
+
#idInParameters(id, messages) {
|
|
31
|
+
for (let message of messages) {
|
|
32
|
+
// prettier-ignore
|
|
33
|
+
const isIn = message.args.reduce((a, { type: { type: typeId } }) => a || this.#typeDependOn(typeId, id), false);
|
|
34
|
+
if (isIn)
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
// Find out does type depends on known types
|
|
40
|
+
// Example: `type TypeA = Struct { field: AccountId }` => includeKnownTypes(TypeA) === true
|
|
41
|
+
#includeKnownTypes(typeId) {
|
|
42
|
+
if (this.knownTypes[typeId])
|
|
43
|
+
return true;
|
|
44
|
+
const { types } = this.contractMetadata;
|
|
45
|
+
const defA = normalizeContractTypeDef(types[typeId].type.def);
|
|
46
|
+
const { type, value } = defA;
|
|
47
|
+
switch (type) {
|
|
48
|
+
case 'Struct':
|
|
49
|
+
return value.fields.some(({ typeId }) => this.#includeKnownTypes(typeId));
|
|
50
|
+
case 'Enum':
|
|
51
|
+
return value.members.some(({ fields }) => fields.some(({ typeId }) => this.#includeKnownTypes(typeId)));
|
|
52
|
+
case 'Tuple':
|
|
53
|
+
return value.fields.some((typeId) => this.#includeKnownTypes(typeId));
|
|
54
|
+
case 'Sequence':
|
|
55
|
+
case 'SizedVec':
|
|
56
|
+
const $innerType = this.types[value.typeParam].typeDef;
|
|
57
|
+
if ($innerType.type === 'Primitive' && $innerType.value.kind === 'u8') {
|
|
58
|
+
return true; // ByteLikes
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
return this.#includeKnownTypes(value.typeParam);
|
|
62
|
+
}
|
|
63
|
+
case 'Primitive':
|
|
64
|
+
case 'Compact':
|
|
65
|
+
case 'BitSequence':
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Find out does typeA depends on typeB
|
|
70
|
+
// Example: `type TypeA = Struct { field: TypeB }` => typeDependOn(TypeA, TypeB) === true
|
|
71
|
+
#typeDependOn(typeA, typeB) {
|
|
72
|
+
if (typeA === typeB)
|
|
73
|
+
return true;
|
|
74
|
+
const { types } = this.contractMetadata;
|
|
75
|
+
const defA = normalizeContractTypeDef(types[typeA].type.def);
|
|
76
|
+
const { type, value } = defA;
|
|
77
|
+
// prettier-ignore
|
|
78
|
+
switch (type) {
|
|
79
|
+
case 'Struct':
|
|
80
|
+
return value.fields.reduce((a, { typeId }) => a || this.#typeDependOn(typeId, typeB), false);
|
|
81
|
+
case 'Enum':
|
|
82
|
+
return value.members.reduce((a, { fields }) => a || fields.reduce((a, { typeId }) => a || this.#typeDependOn(typeId, typeB), false), false);
|
|
83
|
+
case 'Tuple':
|
|
84
|
+
return value.fields.reduce((a, typeId) => a || this.#typeDependOn(typeId, typeB), false);
|
|
85
|
+
case 'Sequence':
|
|
86
|
+
case 'SizedVec':
|
|
87
|
+
return this.#typeDependOn(value.typeParam, typeB);
|
|
88
|
+
case 'Primitive':
|
|
89
|
+
case 'Compact':
|
|
90
|
+
case 'BitSequence':
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
24
94
|
}
|
package/typink/index.js
CHANGED
|
@@ -32,5 +32,5 @@ export async function generateContractTypes(metadata, contract, outDir = '.', ex
|
|
|
32
32
|
fs.writeFileSync(constructorTxTypesFileName, await constructorTxGen.generate(useSubPaths));
|
|
33
33
|
fs.writeFileSync(eventsTypesFile, await eventsGen.generate(useSubPaths));
|
|
34
34
|
fs.writeFileSync(indexTypesFileName, await indexGen.generate(useSubPaths));
|
|
35
|
-
return { interfaceName };
|
|
35
|
+
return { interfaceName, outputFolder: dirPath };
|
|
36
36
|
}
|
|
@@ -9,7 +9,7 @@ import { ContractEvents } from './events';
|
|
|
9
9
|
|
|
10
10
|
export * from './types';
|
|
11
11
|
|
|
12
|
-
export interface {{{interfaceName}}}<Rv extends RpcVersion =
|
|
12
|
+
{{{interfaceDocs}}}export interface {{{interfaceName}}}<Rv extends RpcVersion = RpcVersion, ChainApi extends VersionedGenericSubstrateApi = SubstrateApi> extends GenericContractApi<Rv, ChainApi> {
|
|
13
13
|
query: ContractQuery<ChainApi[Rv]>;
|
|
14
14
|
tx: ContractTx<ChainApi[Rv]>;
|
|
15
15
|
constructorQuery: ConstructorQuery<ChainApi[Rv]>;
|