@haneullabs/codegen 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/CHANGELOG.md +259 -0
  2. package/README.md +195 -0
  3. package/dist/cjs/bin/bash-complete.d.ts +2 -0
  4. package/dist/cjs/bin/bash-complete.js +51 -0
  5. package/dist/cjs/bin/bash-complete.js.map +7 -0
  6. package/dist/cjs/bin/cli.d.ts +2 -0
  7. package/dist/cjs/bin/cli.js +34 -0
  8. package/dist/cjs/bin/cli.js.map +7 -0
  9. package/dist/cjs/cli/cli.d.ts +1 -0
  10. package/dist/cjs/cli/cli.js +49 -0
  11. package/dist/cjs/cli/cli.js.map +7 -0
  12. package/dist/cjs/cli/commands/generate/command.d.ts +1 -0
  13. package/dist/cjs/cli/commands/generate/command.js +80 -0
  14. package/dist/cjs/cli/commands/generate/command.js.map +7 -0
  15. package/dist/cjs/cli/commands/generate/impl.d.ts +8 -0
  16. package/dist/cjs/cli/commands/generate/impl.js +66 -0
  17. package/dist/cjs/cli/commands/generate/impl.js.map +7 -0
  18. package/dist/cjs/cli/context.d.ts +6 -0
  19. package/dist/cjs/cli/context.js +45 -0
  20. package/dist/cjs/cli/context.js.map +7 -0
  21. package/dist/cjs/config.d.ts +51 -0
  22. package/dist/cjs/config.js +75 -0
  23. package/dist/cjs/config.js.map +7 -0
  24. package/dist/cjs/file-builder.d.ts +13 -0
  25. package/dist/cjs/file-builder.js +83 -0
  26. package/dist/cjs/file-builder.js.map +7 -0
  27. package/dist/cjs/generate-utils.d.ts +1 -0
  28. package/dist/cjs/generate-utils.js +187 -0
  29. package/dist/cjs/generate-utils.js.map +7 -0
  30. package/dist/cjs/index.d.ts +8 -0
  31. package/dist/cjs/index.js +124 -0
  32. package/dist/cjs/index.js.map +7 -0
  33. package/dist/cjs/move-module-builder.d.ts +26 -0
  34. package/dist/cjs/move-module-builder.js +464 -0
  35. package/dist/cjs/move-module-builder.js.map +7 -0
  36. package/dist/cjs/package.json +5 -0
  37. package/dist/cjs/render-types.d.ts +19 -0
  38. package/dist/cjs/render-types.js +313 -0
  39. package/dist/cjs/render-types.js.map +7 -0
  40. package/dist/cjs/summary.d.ts +3 -0
  41. package/dist/cjs/summary.js +218 -0
  42. package/dist/cjs/summary.js.map +7 -0
  43. package/dist/cjs/types/deserialized.d.ts +89 -0
  44. package/dist/cjs/types/deserialized.js +17 -0
  45. package/dist/cjs/types/deserialized.js.map +7 -0
  46. package/dist/cjs/types/summary.d.ts +105 -0
  47. package/dist/cjs/types/summary.js +17 -0
  48. package/dist/cjs/types/summary.js.map +7 -0
  49. package/dist/cjs/utils.d.ts +22 -0
  50. package/dist/cjs/utils.js +164 -0
  51. package/dist/cjs/utils.js.map +7 -0
  52. package/dist/esm/bin/bash-complete.d.ts +2 -0
  53. package/dist/esm/bin/bash-complete.js +31 -0
  54. package/dist/esm/bin/bash-complete.js.map +7 -0
  55. package/dist/esm/bin/cli.d.ts +2 -0
  56. package/dist/esm/bin/cli.js +32 -0
  57. package/dist/esm/bin/cli.js.map +7 -0
  58. package/dist/esm/cli/cli.d.ts +1 -0
  59. package/dist/esm/cli/cli.js +29 -0
  60. package/dist/esm/cli/cli.js.map +7 -0
  61. package/dist/esm/cli/commands/generate/command.d.ts +1 -0
  62. package/dist/esm/cli/commands/generate/command.js +50 -0
  63. package/dist/esm/cli/commands/generate/command.js.map +7 -0
  64. package/dist/esm/cli/commands/generate/impl.d.ts +8 -0
  65. package/dist/esm/cli/commands/generate/impl.js +46 -0
  66. package/dist/esm/cli/commands/generate/impl.js.map +7 -0
  67. package/dist/esm/cli/context.d.ts +6 -0
  68. package/dist/esm/cli/context.js +15 -0
  69. package/dist/esm/cli/context.js.map +7 -0
  70. package/dist/esm/config.d.ts +51 -0
  71. package/dist/esm/config.js +45 -0
  72. package/dist/esm/config.js.map +7 -0
  73. package/dist/esm/file-builder.d.ts +13 -0
  74. package/dist/esm/file-builder.js +63 -0
  75. package/dist/esm/file-builder.js.map +7 -0
  76. package/dist/esm/generate-utils.d.ts +1 -0
  77. package/dist/esm/generate-utils.js +167 -0
  78. package/dist/esm/generate-utils.js.map +7 -0
  79. package/dist/esm/index.d.ts +8 -0
  80. package/dist/esm/index.js +104 -0
  81. package/dist/esm/index.js.map +7 -0
  82. package/dist/esm/move-module-builder.d.ts +26 -0
  83. package/dist/esm/move-module-builder.js +457 -0
  84. package/dist/esm/move-module-builder.js.map +7 -0
  85. package/dist/esm/package.json +5 -0
  86. package/dist/esm/render-types.d.ts +19 -0
  87. package/dist/esm/render-types.js +293 -0
  88. package/dist/esm/render-types.js.map +7 -0
  89. package/dist/esm/summary.d.ts +3 -0
  90. package/dist/esm/summary.js +198 -0
  91. package/dist/esm/summary.js.map +7 -0
  92. package/dist/esm/types/deserialized.d.ts +89 -0
  93. package/dist/esm/types/deserialized.js +1 -0
  94. package/dist/esm/types/deserialized.js.map +7 -0
  95. package/dist/esm/types/summary.d.ts +105 -0
  96. package/dist/esm/types/summary.js +1 -0
  97. package/dist/esm/types/summary.js.map +7 -0
  98. package/dist/esm/utils.d.ts +22 -0
  99. package/dist/esm/utils.js +134 -0
  100. package/dist/esm/utils.js.map +7 -0
  101. package/dist/tsconfig.esm.tsbuildinfo +1 -0
  102. package/dist/tsconfig.tsbuildinfo +1 -0
  103. package/package.json +70 -0
  104. package/src/bin/bash-complete.ts +35 -0
  105. package/src/bin/cli.ts +40 -0
  106. package/src/cli/cli.ts +29 -0
  107. package/src/cli/commands/generate/command.ts +50 -0
  108. package/src/cli/commands/generate/impl.ts +66 -0
  109. package/src/cli/context.ts +21 -0
  110. package/src/config.ts +54 -0
  111. package/src/file-builder.ts +74 -0
  112. package/src/generate-utils.ts +163 -0
  113. package/src/index.ts +131 -0
  114. package/src/move-module-builder.ts +599 -0
  115. package/src/render-types.ts +349 -0
  116. package/src/summary.ts +242 -0
  117. package/src/types/deserialized.ts +107 -0
  118. package/src/types/summary.ts +144 -0
  119. package/src/utils.ts +180 -0
@@ -0,0 +1,599 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { FileBuilder } from './file-builder.js';
5
+ import { readFile } from 'node:fs/promises';
6
+ import {
7
+ getSafeName,
8
+ renderTypeSignature,
9
+ HANEUL_FRAMEWORK_ADDRESS,
10
+ HANEUL_SYSTEM_ADDRESS,
11
+ } from './render-types.js';
12
+ import {
13
+ camelCase,
14
+ capitalize,
15
+ formatComment,
16
+ isWellKnownObjectParameter,
17
+ mapToObject,
18
+ parseTS,
19
+ withComment,
20
+ } from './utils.js';
21
+ import type { Fields, ModuleSummary, Type, TypeParameter } from './types/summary.js';
22
+ import { join } from 'node:path';
23
+
24
+ export class MoveModuleBuilder extends FileBuilder {
25
+ summary: ModuleSummary;
26
+ #depsDir = './deps';
27
+ #addressMappings: Record<string, string>;
28
+ #includedTypes: Set<string> = new Set();
29
+ #includedFunctions: Set<string> = new Set();
30
+ #orderedTypes: string[] = [];
31
+ #mvrNameOrAddress?: string;
32
+
33
+ constructor({
34
+ mvrNameOrAddress,
35
+ summary,
36
+ addressMappings = {},
37
+ }: {
38
+ summary: ModuleSummary;
39
+ addressMappings?: Record<string, string>;
40
+ mvrNameOrAddress?: string;
41
+ }) {
42
+ super();
43
+ this.summary = summary;
44
+ this.#addressMappings = addressMappings;
45
+ this.#mvrNameOrAddress = mvrNameOrAddress;
46
+ }
47
+
48
+ static async fromSummaryFile(
49
+ file: string,
50
+ addressMappings: Record<string, string>,
51
+ mvrNameOrAddress?: string,
52
+ ) {
53
+ const summary = JSON.parse(await readFile(file, 'utf-8'));
54
+
55
+ return new MoveModuleBuilder({
56
+ summary,
57
+ addressMappings,
58
+ mvrNameOrAddress,
59
+ });
60
+ }
61
+
62
+ #resolveAddress(address: string) {
63
+ return this.#addressMappings[address] ?? address;
64
+ }
65
+
66
+ #getModuleTypeName() {
67
+ const resolvedAddress = this.#resolveAddress(this.summary.id.address);
68
+ if (resolvedAddress === HANEUL_FRAMEWORK_ADDRESS) {
69
+ return '0x2';
70
+ } else if (resolvedAddress === HANEUL_SYSTEM_ADDRESS) {
71
+ return '0x3';
72
+ } else {
73
+ return this.#mvrNameOrAddress ?? this.summary.id.address;
74
+ }
75
+ }
76
+
77
+ override async getHeader() {
78
+ if (!this.summary.doc) {
79
+ return super.getHeader();
80
+ }
81
+
82
+ return `${await super.getHeader()}\n\n/*${await formatComment(this.summary.doc)}*/\n\n`;
83
+ }
84
+
85
+ includeAllFunctions({ privateMethods = 'entry' }: { privateMethods?: 'none' | 'entry' | 'all' }) {
86
+ for (const [name, func] of Object.entries(this.summary.functions)) {
87
+ if (func.macro_) {
88
+ continue;
89
+ }
90
+
91
+ if (func.visibility !== 'Public') {
92
+ switch (privateMethods) {
93
+ case 'none':
94
+ continue;
95
+ case 'entry':
96
+ if (!func.entry) {
97
+ continue;
98
+ }
99
+ break;
100
+ case 'all':
101
+ break;
102
+ default:
103
+ throw new Error(`Unknown privateMethods option: ${privateMethods}`);
104
+ }
105
+ }
106
+
107
+ const safeName = getSafeName(camelCase(name));
108
+
109
+ this.reservedNames.add(safeName);
110
+ this.#includedFunctions.add(name);
111
+ }
112
+ }
113
+
114
+ includeType(name: string, moduleBuilders: Record<string, MoveModuleBuilder>) {
115
+ if (this.#includedTypes.has(name)) {
116
+ return;
117
+ }
118
+
119
+ this.#includedTypes.add(name);
120
+ this.reservedNames.add(name);
121
+
122
+ const struct = this.summary.structs[name];
123
+ const enum_ = this.summary.enums[name];
124
+
125
+ if (!struct && !enum_) {
126
+ throw new Error(
127
+ `Type ${name} not found in ${this.summary.id.address}::${this.summary.id.name}`,
128
+ );
129
+ }
130
+
131
+ if (struct) {
132
+ Object.values(struct.fields.fields).forEach((field) => {
133
+ renderTypeSignature(field.type_, {
134
+ format: 'bcs',
135
+ summary: this.summary,
136
+ typeParameters: struct.type_parameters,
137
+ resolveAddress: (address) => this.#resolveAddress(address),
138
+ onDependency: (address, mod, name) => {
139
+ const builder = moduleBuilders[`${address}::${mod}`];
140
+
141
+ if (!builder) {
142
+ throw new Error(`Module builder not found for ${address}::${mod}`);
143
+ }
144
+
145
+ builder.includeType(name, moduleBuilders);
146
+
147
+ return undefined;
148
+ },
149
+ });
150
+ });
151
+ }
152
+
153
+ if (enum_) {
154
+ Object.values(enum_.variants).forEach((variant) => {
155
+ Object.values(variant.fields.fields).forEach((field) => {
156
+ renderTypeSignature(field.type_, {
157
+ format: 'bcs',
158
+ summary: this.summary,
159
+ typeParameters: enum_.type_parameters,
160
+ resolveAddress: (address) => this.#resolveAddress(address),
161
+ onDependency: (address, mod, name) => {
162
+ const builder = moduleBuilders[`${address}::${mod}`];
163
+
164
+ if (!builder) {
165
+ throw new Error(`Module builder not found for ${address}::${mod}`);
166
+ }
167
+
168
+ builder.includeType(name, moduleBuilders);
169
+
170
+ return undefined;
171
+ },
172
+ });
173
+ });
174
+ });
175
+ }
176
+
177
+ // Add after all dependencies are included to avoid declaration order issues
178
+ this.#orderedTypes.push(name);
179
+ }
180
+
181
+ includeAllTypes(moduleBuilders: Record<string, MoveModuleBuilder>) {
182
+ Object.keys(this.summary.structs).forEach((name) => this.includeType(name, moduleBuilders));
183
+ Object.keys(this.summary.enums).forEach((name) => this.includeType(name, moduleBuilders));
184
+ }
185
+
186
+ async renderBCSTypes() {
187
+ if (this.hasBcsTypes()) {
188
+ this.statements.push(
189
+ ...parseTS /* ts */ `
190
+ const $moduleName = '${this.#getModuleTypeName()}::${this.summary.id.name}';
191
+ `,
192
+ );
193
+ }
194
+ for (const name of this.#orderedTypes) {
195
+ if (this.summary.structs[name]) {
196
+ await this.renderStruct(name);
197
+ } else if (this.summary.enums[name]) {
198
+ await this.renderEnum(name);
199
+ }
200
+ }
201
+ }
202
+
203
+ hasBcsTypes() {
204
+ return this.#includedTypes.size > 0;
205
+ }
206
+
207
+ hasFunctions() {
208
+ return this.#includedFunctions.size > 0;
209
+ }
210
+
211
+ hasTypesOrFunctions() {
212
+ return this.hasBcsTypes() || this.hasFunctions();
213
+ }
214
+
215
+ async #renderFieldsAsStruct(
216
+ name: string,
217
+ { fields }: Fields,
218
+ typeParameters: TypeParameter[] = [],
219
+ ) {
220
+ this.addImport('~root/../utils/index.js', 'MoveStruct');
221
+ const fieldObject = await mapToObject({
222
+ items: Object.entries(fields),
223
+ getComment: ([_name, field]) => field.doc,
224
+ mapper: ([name, field]) => [
225
+ name,
226
+ renderTypeSignature(field.type_, {
227
+ format: 'bcs',
228
+ onBcsType: () => {
229
+ this.addImport('@haneullabs/haneul/bcs', 'bcs');
230
+ },
231
+ summary: this.summary,
232
+ typeParameters,
233
+ resolveAddress: (address) => this.#resolveAddress(address),
234
+ onDependency: (address, mod) => {
235
+ if (address !== this.summary.id.address || mod !== this.summary.id.name) {
236
+ return this.addStarImport(
237
+ address === this.summary.id.address
238
+ ? `./${mod}.js`
239
+ : join(`~root`, this.#depsDir, `${address}/${mod}.js`),
240
+ mod,
241
+ );
242
+ }
243
+
244
+ return undefined;
245
+ },
246
+ }),
247
+ ],
248
+ });
249
+
250
+ return parseTS /* ts */ `new MoveStruct({ name: \`${name}\`, fields: ${fieldObject} })`;
251
+ }
252
+
253
+ async #renderFieldsAsTuple(
254
+ name: string,
255
+ { fields }: Fields,
256
+ typeParameters: TypeParameter[] = [],
257
+ ) {
258
+ this.addImport('~root/../utils/index.js', 'MoveTuple');
259
+ const values = Object.values(fields).map((field) =>
260
+ renderTypeSignature(field.type_, {
261
+ format: 'bcs',
262
+ summary: this.summary,
263
+ typeParameters,
264
+ onBcsType: () => {
265
+ this.addImport('@haneullabs/haneul/bcs', 'bcs');
266
+ },
267
+ resolveAddress: (address) => this.#resolveAddress(address),
268
+ onDependency: (address, mod) => {
269
+ if (address !== this.summary.id.address || mod !== this.summary.id.name) {
270
+ return this.addStarImport(
271
+ address === this.summary.id.address
272
+ ? `./${mod}.js`
273
+ : join(`~root`, this.#depsDir, `${address}/${mod}.js`),
274
+ mod,
275
+ );
276
+ }
277
+
278
+ return undefined;
279
+ },
280
+ }),
281
+ );
282
+
283
+ return parseTS /* ts */ `new MoveTuple({ name: \`${name}\`, fields: [${values.join(', ')}] })`;
284
+ }
285
+
286
+ async renderStruct(name: string) {
287
+ if (!this.#includedTypes.has(name)) {
288
+ return;
289
+ }
290
+
291
+ const struct = this.summary.structs[name];
292
+
293
+ if (!struct) {
294
+ throw new Error(
295
+ `Struct ${name} not found in ${this.summary.id.address}::${this.summary.id.name}`,
296
+ );
297
+ }
298
+
299
+ this.exports.push(name);
300
+
301
+ const params = struct.type_parameters.filter((param) => !param.phantom);
302
+ const structName = `\${$moduleName}::${name}`;
303
+
304
+ if (params.length === 0) {
305
+ this.statements.push(
306
+ ...parseTS /* ts */ `export const ${name} = ${
307
+ struct.fields.positional_fields
308
+ ? await this.#renderFieldsAsTuple(structName, struct.fields, struct.type_parameters)
309
+ : await this.#renderFieldsAsStruct(structName, struct.fields, struct.type_parameters)
310
+ }`,
311
+ );
312
+ } else {
313
+ this.addImport('@haneullabs/haneul/bcs', 'type BcsType');
314
+
315
+ const typeParams = `...typeParameters: [${params.map((param, i) => param.name ?? `T${i}`).join(', ')}]`;
316
+ const typeGenerics = `${params.map((param, i) => `${param.name ?? `T${i}`} extends BcsType<any>`).join(', ')}`;
317
+ const nameGenerics = `${params.map((param, i) => `\${typeParameters[${i}].name as ${param.name ?? `T${i}`}['name']}`).join(', ')}`;
318
+
319
+ this.statements.push(
320
+ ...(await withComment(
321
+ struct,
322
+ parseTS /* ts */ `export function ${name}<${typeGenerics}>(${typeParams}) {
323
+ return ${
324
+ struct.fields.positional_fields
325
+ ? await this.#renderFieldsAsTuple(
326
+ `${structName}<${nameGenerics}>`,
327
+ struct.fields,
328
+ struct.type_parameters,
329
+ )
330
+ : await this.#renderFieldsAsStruct(
331
+ `${structName}<${nameGenerics}>`,
332
+ struct.fields,
333
+ struct.type_parameters,
334
+ )
335
+ }
336
+ }`,
337
+ )),
338
+ );
339
+ }
340
+ }
341
+
342
+ async renderEnum(name: string) {
343
+ if (!this.#includedTypes.has(name)) {
344
+ return;
345
+ }
346
+
347
+ const enumDef = this.summary.enums[name];
348
+
349
+ if (!enumDef) {
350
+ throw new Error(
351
+ `Enum ${name} not found in ${this.summary.id.address}::${this.summary.id.name}`,
352
+ );
353
+ }
354
+
355
+ this.addImport('~root/../utils/index.js', 'MoveEnum');
356
+ this.exports.push(name);
357
+
358
+ const enumName = `\${$moduleName}::${name}`;
359
+
360
+ const variantsObject = await mapToObject({
361
+ items: Object.entries(enumDef.variants),
362
+ getComment: ([_name, variant]) => variant.doc,
363
+ mapper: async ([variantName, variant]) => [
364
+ variantName,
365
+ Object.keys(variant.fields.fields).length === 0
366
+ ? 'null'
367
+ : isPositional(variant.fields)
368
+ ? Object.keys(variant.fields.fields).length === 1
369
+ ? renderTypeSignature(Object.values(variant.fields.fields)[0].type_, {
370
+ format: 'bcs',
371
+ summary: this.summary,
372
+ typeParameters: enumDef.type_parameters,
373
+ onBcsType: () => {
374
+ this.addImport('@haneullabs/haneul/bcs', 'bcs');
375
+ },
376
+ resolveAddress: (address) => this.#resolveAddress(address),
377
+ onDependency: (address, mod) => {
378
+ if (address !== this.summary.id.address || mod !== this.summary.id.name) {
379
+ return this.addStarImport(
380
+ address === this.summary.id.address
381
+ ? `./${mod}.js`
382
+ : `~root/deps/${address}/${mod}.js`,
383
+ mod,
384
+ );
385
+ }
386
+
387
+ return undefined;
388
+ },
389
+ })
390
+ : await this.#renderFieldsAsTuple(
391
+ `${name}.${variantName}`,
392
+ variant.fields,
393
+ enumDef.type_parameters,
394
+ )
395
+ : await this.#renderFieldsAsStruct(
396
+ `${name}.${variantName}`,
397
+ variant.fields,
398
+ enumDef.type_parameters,
399
+ ),
400
+ ],
401
+ });
402
+
403
+ const params = enumDef.type_parameters.filter((param) => !param.phantom);
404
+
405
+ if (params.length === 0) {
406
+ this.statements.push(
407
+ ...(await withComment(
408
+ enumDef,
409
+ parseTS /* ts */ `export const ${name} = new MoveEnum({ name: \`${enumName}\`, fields: ${variantsObject} })`,
410
+ )),
411
+ );
412
+ } else {
413
+ this.addImport('@haneullabs/haneul/bcs', 'type BcsType');
414
+
415
+ const typeParams = `...typeParameters: [${params.map((param, i) => param.name ?? `T${i}`).join(', ')}]`;
416
+ const typeGenerics = `${params.map((param, i) => `${param.name ?? `T${i}`} extends BcsType<any>`).join(', ')}`;
417
+ const nameGenerics = `${params.map((param, i) => `\${typeParameters[${i}].name as ${param.name ?? `T${i}`}['name']}`).join(', ')}`;
418
+
419
+ this.statements.push(
420
+ ...(await withComment(
421
+ enumDef,
422
+ parseTS /* ts */ `
423
+ export function ${name}<${typeGenerics}>(${typeParams}) {
424
+ return new MoveEnum({ name: \`${enumName}<${nameGenerics}>\`, fields: ${variantsObject} })
425
+ }`,
426
+ )),
427
+ );
428
+ }
429
+ }
430
+
431
+ async renderFunctions() {
432
+ const names = [];
433
+
434
+ if (!this.hasFunctions()) {
435
+ return;
436
+ }
437
+ this.addImport('@haneullabs/haneul/transactions', 'type Transaction');
438
+
439
+ for (const [name, func] of Object.entries(this.summary.functions)) {
440
+ if (func.macro_ || !this.#includedFunctions.has(name)) {
441
+ continue;
442
+ }
443
+
444
+ const parameters = func.parameters.filter((param) => !this.isContextReference(param.type_));
445
+ const hasAllParameterNames =
446
+ parameters.length > 0 &&
447
+ parameters.every(
448
+ (param, i) => param.name && parameters.findIndex((p) => p.name === param.name) === i,
449
+ );
450
+ const fnName = getSafeName(camelCase(name));
451
+ const requiredParameters = parameters.filter(
452
+ (param) =>
453
+ !isWellKnownObjectParameter(param.type_, (address) => this.#resolveAddress(address)),
454
+ );
455
+
456
+ if (parameters.length > 0) {
457
+ this.addImport('~root/../utils/index.js', 'normalizeMoveArguments');
458
+ }
459
+
460
+ names.push(fnName);
461
+
462
+ const usedTypeParameters = new Set<number | string>();
463
+
464
+ const argumentsTypes = requiredParameters
465
+ .map((param) =>
466
+ renderTypeSignature(param.type_, {
467
+ format: 'typescriptArg',
468
+ summary: this.summary,
469
+ typeParameters: func.type_parameters,
470
+ resolveAddress: (address) => this.#resolveAddress(address),
471
+ onTypeParameter: (typeParameter) => usedTypeParameters.add(typeParameter),
472
+ }),
473
+ )
474
+ .map((type, i) =>
475
+ requiredParameters[i].name
476
+ ? `${camelCase(requiredParameters[i].name)}: RawTransactionArgument<${type}>`
477
+ : `RawTransactionArgument<${type}>`,
478
+ )
479
+ .join(',\n');
480
+
481
+ if (argumentsTypes.length > 0) {
482
+ this.addImport('~root/../utils/index.js', 'type RawTransactionArgument');
483
+ }
484
+
485
+ if (usedTypeParameters.size > 0) {
486
+ this.addImport('@haneullabs/haneul/bcs', 'type BcsType');
487
+ }
488
+
489
+ const filteredTypeParameters = func.type_parameters.filter(
490
+ (param, i) =>
491
+ usedTypeParameters.has(i) || (param.name && usedTypeParameters.has(param.name)),
492
+ );
493
+
494
+ const genericTypes =
495
+ filteredTypeParameters.length > 0
496
+ ? `<${filteredTypeParameters.map((param, i) => `${param.name ?? `T${i}`} extends BcsType<any>`).join(', ')}>`
497
+ : '';
498
+ const genericTypeArgs =
499
+ filteredTypeParameters.length > 0
500
+ ? `<${filteredTypeParameters.map((param, i) => `${param.name ?? `T${i}`}`).join(', ')}>`
501
+ : '';
502
+
503
+ const argumentsInterface = this.getUnusedName(
504
+ `${capitalize(fnName.replace(/^_/, ''))}Arguments`,
505
+ );
506
+ if (hasAllParameterNames) {
507
+ this.statements.push(
508
+ ...parseTS /* ts */ `export interface ${argumentsInterface}${genericTypes} {
509
+ ${argumentsTypes}
510
+ }`,
511
+ );
512
+ }
513
+
514
+ const optionsInterface = this.getUnusedName(`${capitalize(fnName.replace(/^_/, ''))}Options`);
515
+ const requiresOptions = argumentsTypes.length > 0 || func.type_parameters.length > 0;
516
+
517
+ this.statements.push(
518
+ ...parseTS /* ts */ `export interface ${optionsInterface}${genericTypes} {
519
+ package${this.#mvrNameOrAddress ? '?: string' : ': string'}
520
+ ${argumentsTypes.length > 0 ? 'arguments: ' : 'arguments?: '}${
521
+ hasAllParameterNames
522
+ ? `${argumentsInterface}${genericTypeArgs} | [${argumentsTypes}]`
523
+ : `[${argumentsTypes}]`
524
+ },
525
+ ${
526
+ func.type_parameters.length
527
+ ? `typeArguments: [${func.type_parameters.map(() => 'string').join(', ')}]`
528
+ : ''
529
+ }
530
+ }`,
531
+ );
532
+
533
+ this.statements.push(
534
+ ...(await withComment(
535
+ func,
536
+ parseTS /* ts */ `export function ${fnName}${genericTypes}(options: ${optionsInterface}${genericTypeArgs}${requiresOptions ? '' : ' = {}'}) {
537
+ const packageAddress = options.package${this.#mvrNameOrAddress ? ` ?? '${this.#mvrNameOrAddress}'` : ''};
538
+ ${
539
+ parameters.length > 0
540
+ ? `const argumentsTypes = [
541
+ ${parameters
542
+ .map((param) =>
543
+ renderTypeSignature(param.type_, {
544
+ format: 'typeTag',
545
+ summary: this.summary,
546
+ typeParameters: func.type_parameters,
547
+ resolveAddress: (address) => this.#resolveAddress(address),
548
+ }),
549
+ )
550
+ .map((tag) => (tag.includes('{') ? `\`${tag}\`` : `'${tag}'`))
551
+ .join(',\n')}
552
+ ] satisfies string[]\n`
553
+ : ''
554
+ }${hasAllParameterNames ? `const parameterNames = ${JSON.stringify(requiredParameters.map((param) => camelCase(param.name!)))}\n` : ''}
555
+ return (tx: Transaction) => tx.moveCall({
556
+ package: packageAddress,
557
+ module: '${this.summary.id.name}',
558
+ function: '${name}',
559
+ ${parameters.length > 0 ? `arguments: normalizeMoveArguments(options.arguments${argumentsTypes.length > 0 ? '' : ' ?? []'} , argumentsTypes${hasAllParameterNames ? `, parameterNames` : ''}),` : ''}
560
+ ${func.type_parameters.length ? 'typeArguments: options.typeArguments' : ''}
561
+ })
562
+ }`,
563
+ )),
564
+ );
565
+ }
566
+ }
567
+
568
+ isContextReference(type: Type): boolean {
569
+ if (typeof type === 'string') {
570
+ return false;
571
+ }
572
+
573
+ if ('Reference' in type) {
574
+ return this.isContextReference(type.Reference[1]);
575
+ }
576
+
577
+ if ('Datatype' in type) {
578
+ return (
579
+ this.#resolveAddress(type.Datatype.module.address) === HANEUL_FRAMEWORK_ADDRESS &&
580
+ type.Datatype.module.name === 'tx_context' &&
581
+ type.Datatype.name === 'TxContext'
582
+ );
583
+ }
584
+
585
+ return false;
586
+ }
587
+ }
588
+
589
+ function isPositional(fields: Fields) {
590
+ if (fields.positional_fields === true) {
591
+ return true;
592
+ }
593
+
594
+ if (Object.keys(fields.fields).every((field, i) => field === `pos${i}`)) {
595
+ return true;
596
+ }
597
+
598
+ return false;
599
+ }