@dedot/codegen 0.0.1-alpha.11

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 (76) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +3 -0
  3. package/cjs/genSupportedChainTypes.js +79 -0
  4. package/cjs/generator/ApiGen.js +16 -0
  5. package/cjs/generator/ConstsGen.js +32 -0
  6. package/cjs/generator/ErrorsGen.js +41 -0
  7. package/cjs/generator/EventsGen.js +68 -0
  8. package/cjs/generator/IndexGen.js +18 -0
  9. package/cjs/generator/QueryGen.js +59 -0
  10. package/cjs/generator/RpcGen.js +175 -0
  11. package/cjs/generator/RuntimeApisGen.js +120 -0
  12. package/cjs/generator/TxGen.js +90 -0
  13. package/cjs/generator/TypeImports.js +56 -0
  14. package/cjs/generator/TypesGen.js +436 -0
  15. package/cjs/generator/dirname.js +5 -0
  16. package/cjs/generator/index.js +26 -0
  17. package/cjs/generator/utils.js +68 -0
  18. package/cjs/index.js +76 -0
  19. package/cjs/package.json +1 -0
  20. package/cjs/packageInfo.js +5 -0
  21. package/cjs/templates/consts.hbs +7 -0
  22. package/cjs/templates/errors.hbs +7 -0
  23. package/cjs/templates/events.hbs +7 -0
  24. package/cjs/templates/index.hbs +22 -0
  25. package/cjs/templates/query.hbs +7 -0
  26. package/cjs/templates/rpc.hbs +7 -0
  27. package/cjs/templates/runtime.hbs +8 -0
  28. package/cjs/templates/tx.hbs +9 -0
  29. package/cjs/templates/types.hbs +5 -0
  30. package/cjs/types.js +2 -0
  31. package/genSupportedChainTypes.d.ts +1 -0
  32. package/genSupportedChainTypes.js +74 -0
  33. package/generator/ApiGen.d.ts +138 -0
  34. package/generator/ApiGen.js +12 -0
  35. package/generator/ConstsGen.d.ts +4 -0
  36. package/generator/ConstsGen.js +28 -0
  37. package/generator/ErrorsGen.d.ts +5 -0
  38. package/generator/ErrorsGen.js +37 -0
  39. package/generator/EventsGen.d.ts +5 -0
  40. package/generator/EventsGen.js +64 -0
  41. package/generator/IndexGen.d.ts +6 -0
  42. package/generator/IndexGen.js +14 -0
  43. package/generator/QueryGen.d.ts +5 -0
  44. package/generator/QueryGen.js +55 -0
  45. package/generator/RpcGen.d.ts +10 -0
  46. package/generator/RpcGen.js +171 -0
  47. package/generator/RuntimeApisGen.d.ts +9 -0
  48. package/generator/RuntimeApisGen.js +116 -0
  49. package/generator/TxGen.d.ts +5 -0
  50. package/generator/TxGen.js +86 -0
  51. package/generator/TypeImports.d.ts +14 -0
  52. package/generator/TypeImports.js +52 -0
  53. package/generator/TypesGen.d.ts +30 -0
  54. package/generator/TypesGen.js +432 -0
  55. package/generator/dirname.d.ts +1 -0
  56. package/generator/dirname.js +6 -0
  57. package/generator/index.d.ts +10 -0
  58. package/generator/index.js +10 -0
  59. package/generator/utils.d.ts +10 -0
  60. package/generator/utils.js +35 -0
  61. package/index.d.ts +4 -0
  62. package/index.js +48 -0
  63. package/package.json +49 -0
  64. package/packageInfo.d.ts +4 -0
  65. package/packageInfo.js +2 -0
  66. package/templates/consts.hbs +7 -0
  67. package/templates/errors.hbs +7 -0
  68. package/templates/events.hbs +7 -0
  69. package/templates/index.hbs +22 -0
  70. package/templates/query.hbs +7 -0
  71. package/templates/rpc.hbs +7 -0
  72. package/templates/runtime.hbs +8 -0
  73. package/templates/tx.hbs +9 -0
  74. package/templates/types.hbs +5 -0
  75. package/types.d.ts +6 -0
  76. package/types.js +1 -0
@@ -0,0 +1,432 @@
1
+ import { stringPascalCase } from '@polkadot/util';
2
+ import { CodecRegistry } from '@dedot/codecs';
3
+ import { isNativeType, normalizeName } from '@dedot/utils';
4
+ import { beautifySourceCode, commentBlock, compileTemplate } from './utils';
5
+ import { registry } from '@dedot/types';
6
+ import { TypeImports } from './TypeImports';
7
+ // Skip generate types for these
8
+ // as we do have native types for them
9
+ const SKIP_TYPES = [
10
+ 'BoundedBTreeMap',
11
+ 'BoundedBTreeSet',
12
+ 'BoundedVec',
13
+ 'Box',
14
+ 'BTreeMap',
15
+ 'BTreeSet',
16
+ 'Cow',
17
+ 'Option',
18
+ 'Range',
19
+ 'RangeInclusive',
20
+ 'Result',
21
+ 'WeakBoundedVec',
22
+ 'WrapperKeepOpaque',
23
+ 'WrapperOpaque',
24
+ ];
25
+ // These are common & generic types, so we'll remove these from all paths at index 1
26
+ // This helps make the type name shorter
27
+ const PATH_RM_INDEX_1 = ['generic', 'misc', 'pallet', 'traits', 'types'];
28
+ export const BASIC_KNOWN_TYPES = ['BitSequence', 'Bytes', 'BytesLike', 'FixedBytes', 'FixedArray', 'Result'];
29
+ const WRAPPER_TYPE_REGEX = /^(\w+)(<.*>)$/g;
30
+ export class TypesGen {
31
+ metadata;
32
+ /**
33
+ * Types will be generated its definition out.
34
+ */
35
+ includedTypes;
36
+ registry;
37
+ typeImports;
38
+ constructor(metadata) {
39
+ this.metadata = metadata;
40
+ this.registry = new CodecRegistry(this.metadata);
41
+ this.includedTypes = this.#includedTypes();
42
+ this.typeImports = new TypeImports();
43
+ }
44
+ generate() {
45
+ this.clearCache();
46
+ let defTypeOut = '';
47
+ Object.values(this.includedTypes)
48
+ .filter(({ skip, knownType }) => !(skip || knownType))
49
+ .forEach(({ name, nameOut, id, docs }) => {
50
+ defTypeOut += `${commentBlock(docs)}export type ${nameOut} = ${this.generateType(id, 0, true)};\n\n`;
51
+ if (this.#shouldGenerateTypeIn(id)) {
52
+ defTypeOut += `export type ${name} = ${this.generateType(id)};\n\n`;
53
+ }
54
+ });
55
+ const importTypes = this.typeImports.toImports('./types');
56
+ const template = compileTemplate('types.hbs');
57
+ return beautifySourceCode(template({ importTypes, defTypeOut }));
58
+ }
59
+ typeCache = {};
60
+ clearCache() {
61
+ this.typeCache = {};
62
+ this.typeImports.clear();
63
+ }
64
+ generateType(typeId, nestedLevel = 0, typeOut = false) {
65
+ if (nestedLevel > 0) {
66
+ const includedDef = this.includedTypes[typeId];
67
+ // If current typeId has its definition generated,
68
+ // we can just use its name, no need to generate its type again
69
+ if (includedDef) {
70
+ const { name, nameOut } = includedDef;
71
+ if (typeOut) {
72
+ this.addTypeImport(nameOut);
73
+ return nameOut;
74
+ }
75
+ else {
76
+ this.addTypeImport(name);
77
+ return name;
78
+ }
79
+ }
80
+ }
81
+ const typeCacheKey = `${typeId}/${typeOut ? 'typeOut' : 'typeIn'}`;
82
+ if (this.typeCache[typeCacheKey]) {
83
+ return this.typeCache[typeCacheKey];
84
+ }
85
+ const type = this.#generateType(typeId, nestedLevel, typeOut);
86
+ this.typeCache[typeCacheKey] = type;
87
+ const baseType = this.#removeGenericPart(type);
88
+ if (BASIC_KNOWN_TYPES.includes(baseType)) {
89
+ this.addTypeImport(baseType);
90
+ }
91
+ return type;
92
+ }
93
+ #generateType(typeId, nestedLevel = 0, typeOut = false) {
94
+ const def = this.metadata.types[typeId];
95
+ if (!def) {
96
+ throw new Error(`Type def not found ${JSON.stringify(def)}`);
97
+ }
98
+ const { type, path, docs } = def;
99
+ const { tag, value } = type;
100
+ switch (tag) {
101
+ case 'Primitive':
102
+ const $codec = this.registry.findCodec(value.kind);
103
+ if ($codec.nativeType) {
104
+ return $codec.nativeType;
105
+ }
106
+ else if (value.kind === 'char') {
107
+ return 'string';
108
+ }
109
+ else {
110
+ throw new Error(`Invalid primitive type: ${value.kind}`);
111
+ }
112
+ case 'Struct': {
113
+ const { fields } = value;
114
+ if (fields.length === 0) {
115
+ return '{}';
116
+ }
117
+ else if (!fields[0].name) {
118
+ if (fields.length === 1) {
119
+ return this.generateType(fields[0].typeId, nestedLevel + 1, typeOut);
120
+ }
121
+ else {
122
+ return `[${fields.map((f) => this.generateType(f.typeId, nestedLevel + 1, typeOut)).join(', ')}]`;
123
+ }
124
+ }
125
+ else {
126
+ return this.generateObjectType(fields, nestedLevel + 1, typeOut);
127
+ }
128
+ }
129
+ case 'Enum': {
130
+ const { members } = value;
131
+ if (path.join('::') === 'Option') {
132
+ const some = members.find((one) => one.name === 'Some');
133
+ if (some) {
134
+ return `${this.generateType(some.fields[0].typeId, nestedLevel + 1, typeOut)} | undefined`;
135
+ }
136
+ }
137
+ else if (path.join('::') === 'Result') {
138
+ const ok = members.find((one) => one.name === 'Ok');
139
+ const err = members.find((one) => one.name === 'Err');
140
+ if (ok && err) {
141
+ const OkType = this.generateType(ok.fields[0].typeId, nestedLevel + 1, typeOut);
142
+ const ErrType = this.generateType(err.fields[0].typeId, nestedLevel + 1, typeOut);
143
+ return `Result<${OkType}, ${ErrType}>`;
144
+ }
145
+ }
146
+ if (members.length === 0) {
147
+ return 'null';
148
+ }
149
+ else if (members.every((x) => x.fields.length === 0)) {
150
+ return members.map(({ name, docs }) => `${commentBlock(docs)}'${stringPascalCase(name)}'`).join(' | ');
151
+ }
152
+ else {
153
+ const membersType = [];
154
+ for (const { fields, name, docs } of members) {
155
+ const keyName = stringPascalCase(name);
156
+ if (fields.length === 0) {
157
+ membersType.push([keyName, null, docs]);
158
+ }
159
+ else if (fields[0].name === undefined) {
160
+ const valueType = fields.length === 1
161
+ ? this.generateType(fields[0].typeId, nestedLevel + 1, typeOut)
162
+ : `[${fields
163
+ .map(({ typeId, docs }) => `${commentBlock(docs)}${this.generateType(typeId, nestedLevel + 1, typeOut)}`)
164
+ .join(', ')}]`;
165
+ membersType.push([keyName, valueType, docs]);
166
+ }
167
+ else {
168
+ membersType.push([keyName, this.generateObjectType(fields, nestedLevel + 1, typeOut), docs]);
169
+ }
170
+ }
171
+ const { tagKey, valueKey } = this.registry.portableRegistry.getEnumOptions(typeId);
172
+ return membersType
173
+ .map(([keyName, valueType, docs]) => ({
174
+ tag: `${tagKey}: '${keyName}'`,
175
+ value: valueType ? `, ${valueKey}${this.#isOptionalType(valueType) ? '?' : ''}: ${valueType} ` : '',
176
+ docs,
177
+ }))
178
+ .map(({ tag, value, docs }) => `${commentBlock(docs)}{ ${tag}${value} }`)
179
+ .join(' | ');
180
+ }
181
+ }
182
+ case 'Tuple': {
183
+ const { fields } = value;
184
+ if (fields.length === 0) {
185
+ return '[]';
186
+ }
187
+ else if (fields.length === 1) {
188
+ return this.generateType(fields[0], nestedLevel + 1, typeOut);
189
+ }
190
+ else {
191
+ return `[${fields.map((x) => this.generateType(x, nestedLevel + 1, typeOut)).join(', ')}]`;
192
+ }
193
+ }
194
+ case 'BitSequence':
195
+ return 'BitSequence';
196
+ case 'Compact':
197
+ return this.generateType(value.typeParam, nestedLevel + 1, typeOut);
198
+ case 'Sequence':
199
+ case 'SizedVec': {
200
+ const fixedSize = tag === 'SizedVec' ? `${value.len}` : null;
201
+ const $innerType = this.metadata.types[value.typeParam].type;
202
+ if ($innerType.tag === 'Primitive' && $innerType.value.kind === 'u8') {
203
+ return fixedSize ? `FixedBytes<${fixedSize}>` : typeOut ? 'Bytes' : 'BytesLike';
204
+ }
205
+ else {
206
+ const innerType = this.generateType(value.typeParam, nestedLevel + 1, typeOut);
207
+ return fixedSize ? `FixedArray<${innerType}, ${fixedSize}>` : `Array<${innerType}>`;
208
+ }
209
+ }
210
+ default:
211
+ throw new Error(`Invalid type! ${tag}`);
212
+ }
213
+ }
214
+ generateObjectType(fields, nestedLevel = 0, typeOut = false) {
215
+ const props = fields.map(({ typeId, name, docs }) => {
216
+ const type = this.generateType(typeId, nestedLevel + 1, typeOut);
217
+ return {
218
+ name: normalizeName(name),
219
+ type,
220
+ optional: this.#isOptionalType(type),
221
+ docs,
222
+ };
223
+ });
224
+ return `{${props
225
+ .map(({ name, type, optional, docs }) => `${commentBlock(docs)}${name}${optional ? '?' : ''}: ${type}`)
226
+ .join(',\n')}}`;
227
+ }
228
+ #isOptionalType(type) {
229
+ return type.endsWith('| undefined');
230
+ }
231
+ #includedTypes() {
232
+ const { types } = this.metadata;
233
+ const pathsCount = new Map();
234
+ const typesWithPath = types.filter((one) => one.path.length > 0);
235
+ const skipIds = [];
236
+ const typeSuffixes = new Map();
237
+ typesWithPath.forEach(({ path, id }) => {
238
+ const joinedPath = path.join('::');
239
+ if (pathsCount.has(joinedPath)) {
240
+ // We compare 2 types with the same path here,
241
+ // if they are the same type -> skip the current one, keep the first occurrence
242
+ // if they are not the same type but has the same path -> we'll try to calculate & add a suffix for the current type name
243
+ const firstOccurrenceTypeId = pathsCount.get(joinedPath)[0];
244
+ const sameType = this.typeEql(firstOccurrenceTypeId, id);
245
+ if (sameType) {
246
+ skipIds.push(id);
247
+ }
248
+ else {
249
+ pathsCount.get(joinedPath).push(id);
250
+ typeSuffixes.set(id, this.#extractDupTypeSuffix(id, firstOccurrenceTypeId, pathsCount.get(joinedPath).length));
251
+ }
252
+ }
253
+ else {
254
+ pathsCount.set(joinedPath, [id]);
255
+ }
256
+ });
257
+ return typesWithPath.reduce((o, type) => {
258
+ const { path, id } = type;
259
+ const joinedPath = path.join('::');
260
+ if (SKIP_TYPES.includes(joinedPath) || SKIP_TYPES.includes(path.at(-1))) {
261
+ return o;
262
+ }
263
+ const suffix = typeSuffixes.get(id) || '';
264
+ let knownType = false;
265
+ let name, nameOut;
266
+ if (this.registry.isKnownType(joinedPath)) {
267
+ const codecType = this.registry.findCodecType(path.at(-1));
268
+ name = codecType.typeIn;
269
+ nameOut = codecType.typeOut;
270
+ knownType = true;
271
+ }
272
+ else if (PATH_RM_INDEX_1.includes(path[1])) {
273
+ const newPath = path.slice();
274
+ newPath.splice(1, 1);
275
+ name = this.#cleanPath(newPath);
276
+ }
277
+ else {
278
+ name = this.#cleanPath(path);
279
+ }
280
+ if (this.#shouldGenerateTypeIn(id)) {
281
+ nameOut = name;
282
+ name = name.endsWith('Like') ? name : `${name}Like`;
283
+ }
284
+ o[id] = {
285
+ name: `${name}${suffix}`,
286
+ nameOut: nameOut ? `${nameOut}${suffix}` : `${name}${suffix}`,
287
+ knownType,
288
+ skip: skipIds.includes(id),
289
+ ...type,
290
+ };
291
+ return o;
292
+ }, {});
293
+ }
294
+ #removeGenericPart(typeName) {
295
+ if (typeName.match(WRAPPER_TYPE_REGEX)) {
296
+ return typeName.replace(WRAPPER_TYPE_REGEX, (_, $1) => $1);
297
+ }
298
+ else {
299
+ return typeName;
300
+ }
301
+ }
302
+ /**
303
+ * @description Remove duplicated part of the path
304
+ *
305
+ * Example:
306
+ * ["pallet_staking", "pallet", "pallet", "Event"]
307
+ * => ["pallet_staking", "pallet", "Event"]
308
+ *
309
+ * @param path
310
+ * @private
311
+ */
312
+ #cleanPath(path) {
313
+ return path
314
+ .map((one) => stringPascalCase(one))
315
+ .filter((one, idx, currentPath) => idx === 0 || one !== currentPath[idx - 1])
316
+ .join('');
317
+ }
318
+ #shouldGenerateTypeIn(id) {
319
+ const { callTypeId } = this.metadata.extrinsic;
320
+ const palletCallTypeIds = this.registry.portableRegistry.getPalletCallTypeIds();
321
+ return callTypeId === id || palletCallTypeIds.includes(id);
322
+ }
323
+ eqlCache = new Map();
324
+ typeEql(idA, idB, level = 0) {
325
+ const cacheKey = `${idA}==${idB}`;
326
+ if (!this.eqlCache.has(cacheKey)) {
327
+ this.eqlCache.set(cacheKey, true);
328
+ this.eqlCache.set(cacheKey, this.#typeEql(idA, idB, level));
329
+ }
330
+ return this.eqlCache.get(cacheKey);
331
+ }
332
+ #typeEql(idA, idB, lvl = 0) {
333
+ if (idA === idB)
334
+ return true;
335
+ const { types } = this.metadata;
336
+ const typeA = types[idA];
337
+ const typeB = types[idB];
338
+ if (typeA.path.join('::') !== typeB.path.join('::'))
339
+ return false;
340
+ const { type: defA, params: paramsA } = typeA;
341
+ const { type: defB, params: paramsB } = typeB;
342
+ if (!this.#eqlArray(paramsA, paramsB, (valA, valB) => this.#eqlTypeParam(valA, valB))) {
343
+ return false;
344
+ }
345
+ if (defA.tag !== defB.tag)
346
+ return false;
347
+ if (defA.tag === 'BitSequence')
348
+ return true;
349
+ if (defA.tag === 'Primitive' && defB.tag === 'Primitive') {
350
+ return defA.value.kind === defB.value.kind;
351
+ }
352
+ if ((defA.tag === 'Compact' && defB.tag === 'Compact') || (defA.tag === 'Sequence' && defB.tag === 'Sequence')) {
353
+ return this.typeEql(defA.value.typeParam, defB.value.typeParam, lvl + 1);
354
+ }
355
+ if (defA.tag === 'SizedVec' && defB.tag === 'SizedVec') {
356
+ return defA.value.len === defB.value.len && this.typeEql(defA.value.typeParam, defB.value.typeParam, lvl + 1);
357
+ }
358
+ if (defA.tag === 'Tuple' && defB.tag === 'Tuple') {
359
+ return this.#eqlArray(defA.value.fields, defB.value.fields, (val1, val2) => this.typeEql(val1, val2, lvl + 1));
360
+ }
361
+ if (defA.tag === 'Struct' && defB.tag === 'Struct') {
362
+ return this.#eqlFields(defA.value.fields, defB.value.fields, lvl);
363
+ }
364
+ if (defA.tag === 'Enum' && defB.tag === 'Enum') {
365
+ return this.#eqlArray(defA.value.members, defB.value.members, (val1, val2) => val1.name === val2.name && val1.index === val2.index && this.#eqlFields(val1.fields, val2.fields, lvl));
366
+ }
367
+ return false;
368
+ }
369
+ #eqlArray(arr1, arr2, eqlVal) {
370
+ return arr1.length === arr2.length && arr1.every((e1, idx) => eqlVal(e1, arr2[idx]));
371
+ }
372
+ #eqlFields(arr1, arr2, lvl) {
373
+ return this.#eqlArray(arr1, arr2, (val1, val2) => val1.name === val2.name && val1.typeName === val2.typeName && this.#typeEql(val1.typeId, val2.typeId));
374
+ }
375
+ #eqlTypeParam(param1, param2) {
376
+ return (param1.name === param2.name &&
377
+ (param1.typeId === undefined) === (param2.typeId === undefined) &&
378
+ (param1.typeId === undefined || this.#typeEql(param1.typeId, param2.typeId)));
379
+ }
380
+ #extractDupTypeSuffix(dupTypeId, originalTypeId, dupCount) {
381
+ const { types } = this.metadata;
382
+ const originalTypeParams = types[originalTypeId].params;
383
+ const dupTypeParams = types[dupTypeId].params;
384
+ const diffParam = dupTypeParams.find((one, idx) => !this.#eqlTypeParam(one, originalTypeParams[idx]));
385
+ // TODO make sure these suffix is unique if a type is duplicated more than 2 times
386
+ if (diffParam?.typeId) {
387
+ const diffType = types[diffParam.typeId];
388
+ if (diffType.path.length > 0) {
389
+ return stringPascalCase(diffType.path.at(-1));
390
+ }
391
+ else if (diffType.type.tag === 'Primitive') {
392
+ return stringPascalCase(diffType.type.value.kind);
393
+ }
394
+ }
395
+ // Last resort!
396
+ return dupCount.toString().padStart(3, '0');
397
+ }
398
+ addTypeImport(typeName) {
399
+ if (Array.isArray(typeName)) {
400
+ typeName.forEach((one) => this.addTypeImport(one));
401
+ return;
402
+ }
403
+ if (isNativeType(typeName)) {
404
+ return;
405
+ }
406
+ for (let type of Object.values(this.includedTypes)) {
407
+ if (type.skip) {
408
+ continue;
409
+ }
410
+ const { name, nameOut, knownType } = type;
411
+ if (name === typeName || nameOut === typeName) {
412
+ if (knownType) {
413
+ this.typeImports.addCodecType(typeName);
414
+ }
415
+ else {
416
+ this.typeImports.addPortableType(typeName);
417
+ }
418
+ return;
419
+ }
420
+ }
421
+ if (BASIC_KNOWN_TYPES.includes(typeName)) {
422
+ this.typeImports.addCodecType(typeName);
423
+ return;
424
+ }
425
+ if (registry.has(typeName)) {
426
+ this.typeImports.addKnownType(typeName);
427
+ }
428
+ else {
429
+ this.typeImports.addOutType(typeName);
430
+ }
431
+ }
432
+ }
@@ -0,0 +1 @@
1
+ export function currentDirname(): string;
@@ -0,0 +1,6 @@
1
+ import { dirname } from 'path';
2
+ import { fileURLToPath } from 'url';
3
+ export const currentDirname = () => {
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ return dirname(__filename);
6
+ };
@@ -0,0 +1,10 @@
1
+ export * from './TypesGen';
2
+ export * from './ApiGen';
3
+ export * from './ConstsGen';
4
+ export * from './QueryGen';
5
+ export * from './RpcGen';
6
+ export * from './IndexGen';
7
+ export * from './ErrorsGen';
8
+ export * from './EventsGen';
9
+ export * from './TxGen';
10
+ export * from './RuntimeApisGen';
@@ -0,0 +1,10 @@
1
+ export * from './TypesGen';
2
+ export * from './ApiGen';
3
+ export * from './ConstsGen';
4
+ export * from './QueryGen';
5
+ export * from './RpcGen';
6
+ export * from './IndexGen';
7
+ export * from './ErrorsGen';
8
+ export * from './EventsGen';
9
+ export * from './TxGen';
10
+ export * from './RuntimeApisGen';
@@ -0,0 +1,10 @@
1
+ export declare const WRAPPER_TYPE_REGEX: RegExp;
2
+ export declare const TUPLE_TYPE_REGEX: RegExp;
3
+ export declare const commentBlock: (...docs: (string | string[])[]) => string;
4
+ export declare const beautifySourceCode: (source: string) => Promise<string>;
5
+ export declare const compileTemplate: (templateFileName: string) => HandlebarsTemplateDelegate<any>;
6
+ /**
7
+ * Check if a word is TypeScript/JavaScript reserved
8
+ * @param word
9
+ */
10
+ export declare const isReservedWord: (word: string) => boolean;
@@ -0,0 +1,35 @@
1
+ import * as fs from 'fs';
2
+ import handlebars from 'handlebars';
3
+ import * as path from 'path';
4
+ import * as prettier from 'prettier';
5
+ import { currentDirname } from './dirname';
6
+ export const WRAPPER_TYPE_REGEX = /^(\w+)<(.*)>$/;
7
+ export const TUPLE_TYPE_REGEX = /^\[(.*)]$/;
8
+ export const commentBlock = (...docs) => {
9
+ const flatLines = docs.flat();
10
+ if (flatLines.length === 0) {
11
+ return '';
12
+ }
13
+ else {
14
+ return `
15
+ /**
16
+ ${flatLines.map((line) => `* ${line.replaceAll(/\s+/g, ' ').trim()}`).join('\n')}
17
+ **/
18
+ `;
19
+ }
20
+ };
21
+ export const beautifySourceCode = async (source) => {
22
+ const prettierOptions = await prettier.resolveConfig(path.resolve(currentDirname(), '../../../../.prettierrc.js'));
23
+ return prettier.format(source, { parser: 'babel-ts', ...prettierOptions });
24
+ };
25
+ export const compileTemplate = (templateFileName) => {
26
+ const templateFilePath = path.resolve(currentDirname(), `../templates/${templateFileName}`);
27
+ return handlebars.compile(fs.readFileSync(templateFilePath, 'utf8'));
28
+ };
29
+ // TODO add more reserved words
30
+ const TS_RESERVED_WORDS = ['new', 'class'];
31
+ /**
32
+ * Check if a word is TypeScript/JavaScript reserved
33
+ * @param word
34
+ */
35
+ export const isReservedWord = (word) => TS_RESERVED_WORDS.includes(word);
package/index.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { MetadataLatest } from '@dedot/codecs';
2
+ import { NetworkInfo } from './types';
3
+ export declare function generateTypesFromChain(network: NetworkInfo, endpoint: string, outDir: string): Promise<void>;
4
+ export declare function generateTypes(network: NetworkInfo, metadata: MetadataLatest, rpcMethods: string[], runtimeApis: any[], outDir?: string): Promise<void>;
package/index.js ADDED
@@ -0,0 +1,48 @@
1
+ import { Dedot } from 'dedot';
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ import { ConstsGen, ErrorsGen, EventsGen, IndexGen, QueryGen, RpcGen, RuntimeApisGen, TxGen, TypesGen, } from './generator';
5
+ import { stringCamelCase } from '@polkadot/util';
6
+ export async function generateTypesFromChain(network, endpoint, outDir) {
7
+ const api = await Dedot.create(endpoint);
8
+ const { methods } = await api.rpc.rpc.methods();
9
+ const apis = api.runtimeVersion?.apis || [];
10
+ if (!network.chain) {
11
+ network.chain = stringCamelCase(api.runtimeVersion?.specName || api.runtimeChain || 'local');
12
+ }
13
+ await generateTypes(network, api.metadataLatest, methods, apis, outDir);
14
+ await api.disconnect();
15
+ }
16
+ export async function generateTypes(network, metadata, rpcMethods, runtimeApis, outDir = '.') {
17
+ const dirPath = path.resolve(outDir, network.chain);
18
+ const defTypesFileName = path.join(dirPath, `types.ts`);
19
+ const constsTypesFileName = path.join(dirPath, `consts.ts`);
20
+ const queryTypesFileName = path.join(dirPath, `query.ts`);
21
+ const rpcCallsFileName = path.join(dirPath, `rpc.ts`);
22
+ const indexFileName = path.join(dirPath, `index.ts`);
23
+ const errorsFileName = path.join(dirPath, `errors.ts`);
24
+ const eventsFileName = path.join(dirPath, `events.ts`);
25
+ const runtimeApisFileName = path.join(dirPath, `runtime.ts`);
26
+ const txFileName = path.join(dirPath, `tx.ts`);
27
+ if (!fs.existsSync(dirPath)) {
28
+ fs.mkdirSync(dirPath, { recursive: true });
29
+ }
30
+ const typesGen = new TypesGen(metadata);
31
+ const constsGen = new ConstsGen(typesGen);
32
+ const queryGen = new QueryGen(typesGen);
33
+ const rpcGen = new RpcGen(typesGen, rpcMethods);
34
+ const indexGen = new IndexGen(network);
35
+ const errorsGen = new ErrorsGen(typesGen);
36
+ const eventsGen = new EventsGen(typesGen);
37
+ const runtimeApisGen = new RuntimeApisGen(typesGen, runtimeApis);
38
+ const txGen = new TxGen(typesGen);
39
+ fs.writeFileSync(defTypesFileName, await typesGen.generate());
40
+ fs.writeFileSync(errorsFileName, await errorsGen.generate());
41
+ fs.writeFileSync(eventsFileName, await eventsGen.generate());
42
+ fs.writeFileSync(rpcCallsFileName, await rpcGen.generate());
43
+ fs.writeFileSync(queryTypesFileName, await queryGen.generate());
44
+ fs.writeFileSync(constsTypesFileName, await constsGen.generate());
45
+ fs.writeFileSync(txFileName, await txGen.generate());
46
+ fs.writeFileSync(indexFileName, await indexGen.generate());
47
+ fs.writeFileSync(runtimeApisFileName, await runtimeApisGen.generate());
48
+ }
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@dedot/codegen",
3
+ "version": "0.0.1-alpha.11+b5ca298",
4
+ "description": "Generate types",
5
+ "author": "Thang X. Vu <thang@coongcrafts.io>",
6
+ "homepage": "https://github.com/dedotdev/dedot/tree/main/packages/codegen",
7
+ "repository": {
8
+ "directory": "packages/codegen",
9
+ "type": "git",
10
+ "url": "https://github.com/dedotdev/dedot.git"
11
+ },
12
+ "main": "./cjs/index.js",
13
+ "type": "module",
14
+ "scripts": {
15
+ "build": "tsc --project tsconfig.build.json && tsc --project tsconfig.build.cjs.json && yarn copy",
16
+ "clean": "rm -rf ./dist && rm -rf ./tsconfig.tsbuildinfo ./tsconfig.build.tsbuildinfo",
17
+ "copy": "cp -R ./src/templates ./dist && cp -R ./src/templates ./dist/cjs"
18
+ },
19
+ "dependencies": {
20
+ "@dedot/codecs": "0.0.1-alpha.11+b5ca298",
21
+ "@dedot/shape": "0.0.1-alpha.11+b5ca298",
22
+ "@dedot/specs": "0.0.1-alpha.11+b5ca298",
23
+ "@dedot/utils": "0.0.1-alpha.11+b5ca298",
24
+ "@polkadot/util": "^12.6.2",
25
+ "dedot": "0.0.1-alpha.11+b5ca298",
26
+ "handlebars": "^4.7.8",
27
+ "prettier": "^3.0.3"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public",
31
+ "directory": "dist"
32
+ },
33
+ "license": "Apache-2.0",
34
+ "gitHead": "b5ca298916c21e2e490bb121275eb49b4b247fd9",
35
+ "module": "./index.js",
36
+ "types": "./index.d.ts",
37
+ "exports": {
38
+ ".": {
39
+ "import": {
40
+ "types": "./index.d.ts",
41
+ "default": "./index.js"
42
+ },
43
+ "require": {
44
+ "types": "./index.d.ts",
45
+ "default": "./cjs/index.js"
46
+ }
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,4 @@
1
+ export declare const packageInfo: {
2
+ name: string;
3
+ version: string;
4
+ };
package/packageInfo.js ADDED
@@ -0,0 +1,2 @@
1
+ // THIS FILE IS AUTO-GENERATED, DO NOT EDIT!
2
+ export const packageInfo = { name: '@dedot/codegen', version: '0.0.1-alpha.24' };
@@ -0,0 +1,7 @@
1
+ // Generated by @dedot/codegen
2
+
3
+ {{{ importTypes }}}
4
+
5
+ export interface ChainConsts extends GenericChainConsts {
6
+ {{{ defTypeOut }}}
7
+ }
@@ -0,0 +1,7 @@
1
+ // Generated by @dedot/codegen
2
+
3
+ {{{ importTypes }}}
4
+
5
+ export interface ChainErrors extends GenericChainErrors {
6
+ {{{ defTypeOut }}}
7
+ }
@@ -0,0 +1,7 @@
1
+ // Generated by @dedot/codegen
2
+
3
+ {{{ importTypes }}}
4
+
5
+ export interface ChainEvents extends GenericChainEvents {
6
+ {{{ defTypeOut }}}
7
+ }
@@ -0,0 +1,22 @@
1
+ // Generated by @dedot/codegen
2
+
3
+ import { GenericSubstrateApi } from '@dedot/types';
4
+ import { ChainConsts } from './consts';
5
+ import { ChainStorage } from './query';
6
+ import { RpcCalls } from './rpc';
7
+ import { ChainErrors } from './errors';
8
+ import { ChainEvents } from './events';
9
+ import { RuntimeApis } from './runtime';
10
+ import { ChainTx } from './tx';
11
+
12
+ export * from './types';
13
+
14
+ export interface {{{interfaceName}}}Api extends GenericSubstrateApi {
15
+ rpc: RpcCalls;
16
+ consts: ChainConsts;
17
+ query: ChainStorage;
18
+ errors: ChainErrors;
19
+ events: ChainEvents;
20
+ call: RuntimeApis;
21
+ tx: ChainTx;
22
+ }