@haneullabs/codegen 0.1.0 → 0.8.2

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 (145) hide show
  1. package/CHANGELOG.md +128 -33
  2. package/README.md +35 -33
  3. package/dist/bin/bash-complete.d.mts +6 -0
  4. package/dist/bin/bash-complete.d.mts.map +1 -0
  5. package/dist/bin/bash-complete.mjs +29 -0
  6. package/dist/bin/bash-complete.mjs.map +1 -0
  7. package/dist/bin/cli.d.mts +1 -0
  8. package/dist/bin/cli.mjs +24 -0
  9. package/dist/bin/cli.mjs.map +1 -0
  10. package/dist/cli/cli.mjs +28 -0
  11. package/dist/cli/cli.mjs.map +1 -0
  12. package/dist/cli/commands/generate/command.mjs +90 -0
  13. package/dist/cli/commands/generate/command.mjs.map +1 -0
  14. package/dist/cli/commands/generate/impl.mjs +72 -0
  15. package/dist/cli/commands/generate/impl.mjs.map +1 -0
  16. package/dist/cli/context.mjs +17 -0
  17. package/dist/cli/context.mjs.map +1 -0
  18. package/dist/config.d.mts +106 -0
  19. package/dist/config.d.mts.map +1 -0
  20. package/dist/config.mjs +70 -0
  21. package/dist/config.mjs.map +1 -0
  22. package/dist/file-builder.mjs +65 -0
  23. package/dist/file-builder.mjs.map +1 -0
  24. package/dist/{esm/generate-utils.js → generate-utils.mjs} +95 -27
  25. package/dist/generate-utils.mjs.map +1 -0
  26. package/dist/index.d.mts +21 -0
  27. package/dist/index.d.mts.map +1 -0
  28. package/dist/index.mjs +80 -0
  29. package/dist/index.mjs.map +1 -0
  30. package/dist/move-module-builder.mjs +350 -0
  31. package/dist/move-module-builder.mjs.map +1 -0
  32. package/dist/render-types.mjs +207 -0
  33. package/dist/render-types.mjs.map +1 -0
  34. package/dist/utils.mjs +89 -0
  35. package/dist/utils.mjs.map +1 -0
  36. package/package.json +27 -28
  37. package/src/bin/bash-complete.ts +18 -7
  38. package/src/bin/cli.ts +3 -9
  39. package/src/cli/commands/generate/command.ts +32 -0
  40. package/src/cli/commands/generate/impl.ts +93 -5
  41. package/src/config.ts +55 -7
  42. package/src/file-builder.ts +14 -1
  43. package/src/generate-utils.ts +88 -18
  44. package/src/index.ts +89 -29
  45. package/src/move-module-builder.ts +181 -76
  46. package/src/render-types.ts +82 -29
  47. package/dist/cjs/bin/bash-complete.d.ts +0 -2
  48. package/dist/cjs/bin/bash-complete.js +0 -51
  49. package/dist/cjs/bin/bash-complete.js.map +0 -7
  50. package/dist/cjs/bin/cli.d.ts +0 -2
  51. package/dist/cjs/bin/cli.js +0 -34
  52. package/dist/cjs/bin/cli.js.map +0 -7
  53. package/dist/cjs/cli/cli.d.ts +0 -1
  54. package/dist/cjs/cli/cli.js +0 -49
  55. package/dist/cjs/cli/cli.js.map +0 -7
  56. package/dist/cjs/cli/commands/generate/command.d.ts +0 -1
  57. package/dist/cjs/cli/commands/generate/command.js +0 -80
  58. package/dist/cjs/cli/commands/generate/command.js.map +0 -7
  59. package/dist/cjs/cli/commands/generate/impl.d.ts +0 -8
  60. package/dist/cjs/cli/commands/generate/impl.js +0 -66
  61. package/dist/cjs/cli/commands/generate/impl.js.map +0 -7
  62. package/dist/cjs/cli/context.d.ts +0 -6
  63. package/dist/cjs/cli/context.js +0 -45
  64. package/dist/cjs/cli/context.js.map +0 -7
  65. package/dist/cjs/config.d.ts +0 -51
  66. package/dist/cjs/config.js +0 -75
  67. package/dist/cjs/config.js.map +0 -7
  68. package/dist/cjs/file-builder.d.ts +0 -13
  69. package/dist/cjs/file-builder.js +0 -83
  70. package/dist/cjs/file-builder.js.map +0 -7
  71. package/dist/cjs/generate-utils.d.ts +0 -1
  72. package/dist/cjs/generate-utils.js +0 -187
  73. package/dist/cjs/generate-utils.js.map +0 -7
  74. package/dist/cjs/index.d.ts +0 -8
  75. package/dist/cjs/index.js +0 -124
  76. package/dist/cjs/index.js.map +0 -7
  77. package/dist/cjs/move-module-builder.d.ts +0 -26
  78. package/dist/cjs/move-module-builder.js +0 -464
  79. package/dist/cjs/move-module-builder.js.map +0 -7
  80. package/dist/cjs/package.json +0 -5
  81. package/dist/cjs/render-types.d.ts +0 -19
  82. package/dist/cjs/render-types.js +0 -313
  83. package/dist/cjs/render-types.js.map +0 -7
  84. package/dist/cjs/summary.d.ts +0 -3
  85. package/dist/cjs/summary.js +0 -218
  86. package/dist/cjs/summary.js.map +0 -7
  87. package/dist/cjs/types/deserialized.d.ts +0 -89
  88. package/dist/cjs/types/deserialized.js +0 -17
  89. package/dist/cjs/types/deserialized.js.map +0 -7
  90. package/dist/cjs/types/summary.d.ts +0 -105
  91. package/dist/cjs/types/summary.js +0 -17
  92. package/dist/cjs/types/summary.js.map +0 -7
  93. package/dist/cjs/utils.d.ts +0 -22
  94. package/dist/cjs/utils.js +0 -164
  95. package/dist/cjs/utils.js.map +0 -7
  96. package/dist/esm/bin/bash-complete.d.ts +0 -2
  97. package/dist/esm/bin/bash-complete.js +0 -31
  98. package/dist/esm/bin/bash-complete.js.map +0 -7
  99. package/dist/esm/bin/cli.d.ts +0 -2
  100. package/dist/esm/bin/cli.js +0 -32
  101. package/dist/esm/bin/cli.js.map +0 -7
  102. package/dist/esm/cli/cli.d.ts +0 -1
  103. package/dist/esm/cli/cli.js +0 -29
  104. package/dist/esm/cli/cli.js.map +0 -7
  105. package/dist/esm/cli/commands/generate/command.d.ts +0 -1
  106. package/dist/esm/cli/commands/generate/command.js +0 -50
  107. package/dist/esm/cli/commands/generate/command.js.map +0 -7
  108. package/dist/esm/cli/commands/generate/impl.d.ts +0 -8
  109. package/dist/esm/cli/commands/generate/impl.js +0 -46
  110. package/dist/esm/cli/commands/generate/impl.js.map +0 -7
  111. package/dist/esm/cli/context.d.ts +0 -6
  112. package/dist/esm/cli/context.js +0 -15
  113. package/dist/esm/cli/context.js.map +0 -7
  114. package/dist/esm/config.d.ts +0 -51
  115. package/dist/esm/config.js +0 -45
  116. package/dist/esm/config.js.map +0 -7
  117. package/dist/esm/file-builder.d.ts +0 -13
  118. package/dist/esm/file-builder.js +0 -63
  119. package/dist/esm/file-builder.js.map +0 -7
  120. package/dist/esm/generate-utils.d.ts +0 -1
  121. package/dist/esm/generate-utils.js.map +0 -7
  122. package/dist/esm/index.d.ts +0 -8
  123. package/dist/esm/index.js +0 -104
  124. package/dist/esm/index.js.map +0 -7
  125. package/dist/esm/move-module-builder.d.ts +0 -26
  126. package/dist/esm/move-module-builder.js +0 -457
  127. package/dist/esm/move-module-builder.js.map +0 -7
  128. package/dist/esm/package.json +0 -5
  129. package/dist/esm/render-types.d.ts +0 -19
  130. package/dist/esm/render-types.js +0 -293
  131. package/dist/esm/render-types.js.map +0 -7
  132. package/dist/esm/summary.d.ts +0 -3
  133. package/dist/esm/summary.js +0 -198
  134. package/dist/esm/summary.js.map +0 -7
  135. package/dist/esm/types/deserialized.d.ts +0 -89
  136. package/dist/esm/types/deserialized.js +0 -1
  137. package/dist/esm/types/deserialized.js.map +0 -7
  138. package/dist/esm/types/summary.d.ts +0 -105
  139. package/dist/esm/types/summary.js +0 -1
  140. package/dist/esm/types/summary.js.map +0 -7
  141. package/dist/esm/utils.d.ts +0 -22
  142. package/dist/esm/utils.js +0 -134
  143. package/dist/esm/utils.js.map +0 -7
  144. package/dist/tsconfig.esm.tsbuildinfo +0 -1
  145. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -19,8 +19,22 @@ import {
19
19
  withComment,
20
20
  } from './utils.js';
21
21
  import type { Fields, ModuleSummary, Type, TypeParameter } from './types/summary.js';
22
+ import type { FunctionsOption, ImportExtension, TypesOption } from './config.js';
22
23
  import { join } from 'node:path';
23
24
 
25
+ const IMPORT_MAP = {
26
+ Transaction: { module: '@haneullabs/haneul/transactions', isType: true },
27
+ BcsType: { module: '@haneullabs/haneul/bcs', isType: true },
28
+ bcs: { module: '@haneullabs/haneul/bcs', isType: false },
29
+ MoveStruct: { module: '~root/../utils/index', isType: false },
30
+ MoveTuple: { module: '~root/../utils/index', isType: false },
31
+ MoveEnum: { module: '~root/../utils/index', isType: false },
32
+ normalizeMoveArguments: { module: '~root/../utils/index', isType: false },
33
+ RawTransactionArgument: { module: '~root/../utils/index', isType: true },
34
+ } as const;
35
+
36
+ type ImportName = keyof typeof IMPORT_MAP;
37
+
24
38
  export class MoveModuleBuilder extends FileBuilder {
25
39
  summary: ModuleSummary;
26
40
  #depsDir = './deps';
@@ -29,26 +43,37 @@ export class MoveModuleBuilder extends FileBuilder {
29
43
  #includedFunctions: Set<string> = new Set();
30
44
  #orderedTypes: string[] = [];
31
45
  #mvrNameOrAddress?: string;
46
+ #importNames: Partial<Record<ImportName, string>> = {};
47
+ #importExtension: ImportExtension;
48
+ #includePhantomTypeParameters: boolean;
32
49
 
33
50
  constructor({
34
51
  mvrNameOrAddress,
35
52
  summary,
36
53
  addressMappings = {},
54
+ importExtension = '.js',
55
+ includePhantomTypeParameters = false,
37
56
  }: {
38
57
  summary: ModuleSummary;
39
58
  addressMappings?: Record<string, string>;
40
59
  mvrNameOrAddress?: string;
60
+ importExtension?: ImportExtension;
61
+ includePhantomTypeParameters?: boolean;
41
62
  }) {
42
63
  super();
43
64
  this.summary = summary;
44
65
  this.#addressMappings = addressMappings;
45
66
  this.#mvrNameOrAddress = mvrNameOrAddress;
67
+ this.#importExtension = importExtension;
68
+ this.#includePhantomTypeParameters = includePhantomTypeParameters;
46
69
  }
47
70
 
48
71
  static async fromSummaryFile(
49
72
  file: string,
50
73
  addressMappings: Record<string, string>,
51
74
  mvrNameOrAddress?: string,
75
+ importExtension?: ImportExtension,
76
+ includePhantomTypeParameters?: boolean,
52
77
  ) {
53
78
  const summary = JSON.parse(await readFile(file, 'utf-8'));
54
79
 
@@ -56,6 +81,8 @@ export class MoveModuleBuilder extends FileBuilder {
56
81
  summary,
57
82
  addressMappings,
58
83
  mvrNameOrAddress,
84
+ importExtension,
85
+ includePhantomTypeParameters,
59
86
  });
60
87
  }
61
88
 
@@ -74,6 +101,19 @@ export class MoveModuleBuilder extends FileBuilder {
74
101
  }
75
102
  }
76
103
 
104
+ #getImportName(name: ImportName): string {
105
+ if (!this.#importNames[name]) {
106
+ const config = IMPORT_MAP[name];
107
+ const importSpec = config.isType ? `type ${name}` : name;
108
+ // Add extension for relative imports (utils)
109
+ const module = config.module.startsWith('~root')
110
+ ? `${config.module}${this.#importExtension}`
111
+ : config.module;
112
+ this.#importNames[name] = this.addImport(module, importSpec);
113
+ }
114
+ return this.#importNames[name]!;
115
+ }
116
+
77
117
  override async getHeader() {
78
118
  if (!this.summary.doc) {
79
119
  return super.getHeader();
@@ -82,26 +122,29 @@ export class MoveModuleBuilder extends FileBuilder {
82
122
  return `${await super.getHeader()}\n\n/*${await formatComment(this.summary.doc)}*/\n\n`;
83
123
  }
84
124
 
85
- includeAllFunctions({ privateMethods = 'entry' }: { privateMethods?: 'none' | 'entry' | 'all' }) {
86
- for (const [name, func] of Object.entries(this.summary.functions)) {
125
+ includeFunctions(option?: FunctionsOption) {
126
+ if (option === false) return;
127
+
128
+ const filterByVisibility = !Array.isArray(option);
129
+ const names = Array.isArray(option) ? option : Object.keys(this.summary.functions);
130
+ const privateFunctions =
131
+ typeof option === 'object' && filterByVisibility ? (option.private ?? 'entry') : 'entry';
132
+
133
+ for (const name of names) {
134
+ const func = this.summary.functions[name];
135
+ if (!func) {
136
+ throw new Error(
137
+ `Function ${name} not found in ${this.summary.id.address}::${this.summary.id.name}`,
138
+ );
139
+ }
140
+
87
141
  if (func.macro_) {
88
142
  continue;
89
143
  }
90
144
 
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
- }
145
+ if (filterByVisibility && func.visibility !== 'Public') {
146
+ if (privateFunctions === false) continue;
147
+ if (privateFunctions === 'entry' && !func.entry) continue;
105
148
  }
106
149
 
107
150
  const safeName = getSafeName(camelCase(name));
@@ -134,6 +177,7 @@ export class MoveModuleBuilder extends FileBuilder {
134
177
  format: 'bcs',
135
178
  summary: this.summary,
136
179
  typeParameters: struct.type_parameters,
180
+ includePhantomTypeParameters: false,
137
181
  resolveAddress: (address) => this.#resolveAddress(address),
138
182
  onDependency: (address, mod, name) => {
139
183
  const builder = moduleBuilders[`${address}::${mod}`];
@@ -157,6 +201,7 @@ export class MoveModuleBuilder extends FileBuilder {
157
201
  format: 'bcs',
158
202
  summary: this.summary,
159
203
  typeParameters: enum_.type_parameters,
204
+ includePhantomTypeParameters: false,
160
205
  resolveAddress: (address) => this.#resolveAddress(address),
161
206
  onDependency: (address, mod, name) => {
162
207
  const builder = moduleBuilders[`${address}::${mod}`];
@@ -178,9 +223,16 @@ export class MoveModuleBuilder extends FileBuilder {
178
223
  this.#orderedTypes.push(name);
179
224
  }
180
225
 
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));
226
+ includeTypes(moduleBuilders: Record<string, MoveModuleBuilder>, option?: TypesOption) {
227
+ if (option === false) return;
228
+
229
+ const names = Array.isArray(option)
230
+ ? option
231
+ : [...Object.keys(this.summary.structs), ...Object.keys(this.summary.enums)];
232
+
233
+ for (const name of names) {
234
+ this.includeType(name, moduleBuilders);
235
+ }
184
236
  }
185
237
 
186
238
  async renderBCSTypes() {
@@ -216,8 +268,9 @@ export class MoveModuleBuilder extends FileBuilder {
216
268
  name: string,
217
269
  { fields }: Fields,
218
270
  typeParameters: TypeParameter[] = [],
271
+ includePhantomTypeParameters = false,
219
272
  ) {
220
- this.addImport('~root/../utils/index.js', 'MoveStruct');
273
+ const moveStructName = this.#getImportName('MoveStruct');
221
274
  const fieldObject = await mapToObject({
222
275
  items: Object.entries(fields),
223
276
  getComment: ([_name, field]) => field.doc,
@@ -225,18 +278,17 @@ export class MoveModuleBuilder extends FileBuilder {
225
278
  name,
226
279
  renderTypeSignature(field.type_, {
227
280
  format: 'bcs',
228
- onBcsType: () => {
229
- this.addImport('@haneullabs/haneul/bcs', 'bcs');
230
- },
281
+ bcsImport: () => this.#getImportName('bcs'),
231
282
  summary: this.summary,
232
283
  typeParameters,
284
+ includePhantomTypeParameters,
233
285
  resolveAddress: (address) => this.#resolveAddress(address),
234
286
  onDependency: (address, mod) => {
235
287
  if (address !== this.summary.id.address || mod !== this.summary.id.name) {
236
288
  return this.addStarImport(
237
289
  address === this.summary.id.address
238
- ? `./${mod}.js`
239
- : join(`~root`, this.#depsDir, `${address}/${mod}.js`),
290
+ ? `./${mod}${this.#importExtension}`
291
+ : join(`~root`, this.#depsDir, `${address}/${mod}${this.#importExtension}`),
240
292
  mod,
241
293
  );
242
294
  }
@@ -247,30 +299,30 @@ export class MoveModuleBuilder extends FileBuilder {
247
299
  ],
248
300
  });
249
301
 
250
- return parseTS /* ts */ `new MoveStruct({ name: \`${name}\`, fields: ${fieldObject} })`;
302
+ return parseTS /* ts */ `new ${moveStructName}({ name: \`${name}\`, fields: ${fieldObject} })`;
251
303
  }
252
304
 
253
305
  async #renderFieldsAsTuple(
254
306
  name: string,
255
307
  { fields }: Fields,
256
308
  typeParameters: TypeParameter[] = [],
309
+ includePhantomTypeParameters = false,
257
310
  ) {
258
- this.addImport('~root/../utils/index.js', 'MoveTuple');
311
+ const moveTupleName = this.#getImportName('MoveTuple');
259
312
  const values = Object.values(fields).map((field) =>
260
313
  renderTypeSignature(field.type_, {
261
314
  format: 'bcs',
262
315
  summary: this.summary,
263
316
  typeParameters,
264
- onBcsType: () => {
265
- this.addImport('@haneullabs/haneul/bcs', 'bcs');
266
- },
317
+ includePhantomTypeParameters,
318
+ bcsImport: () => this.#getImportName('bcs'),
267
319
  resolveAddress: (address) => this.#resolveAddress(address),
268
320
  onDependency: (address, mod) => {
269
321
  if (address !== this.summary.id.address || mod !== this.summary.id.name) {
270
322
  return this.addStarImport(
271
323
  address === this.summary.id.address
272
- ? `./${mod}.js`
273
- : join(`~root`, this.#depsDir, `${address}/${mod}.js`),
324
+ ? `./${mod}${this.#importExtension}`
325
+ : join(`~root`, this.#depsDir, `${address}/${mod}${this.#importExtension}`),
274
326
  mod,
275
327
  );
276
328
  }
@@ -280,7 +332,7 @@ export class MoveModuleBuilder extends FileBuilder {
280
332
  }),
281
333
  );
282
334
 
283
- return parseTS /* ts */ `new MoveTuple({ name: \`${name}\`, fields: [${values.join(', ')}] })`;
335
+ return parseTS /* ts */ `new ${moveTupleName}({ name: \`${name}\`, fields: [${values.join(', ')}] })`;
284
336
  }
285
337
 
286
338
  async renderStruct(name: string) {
@@ -298,23 +350,51 @@ export class MoveModuleBuilder extends FileBuilder {
298
350
 
299
351
  this.exports.push(name);
300
352
 
301
- const params = struct.type_parameters.filter((param) => !param.phantom);
353
+ const includePhantom = this.#includePhantomTypeParameters;
354
+ const params = struct.type_parameters
355
+ .map((param, i) => ({ param, originalIndex: i }))
356
+ .filter(({ param }) => includePhantom || !param.phantom);
302
357
  const structName = `\${$moduleName}::${name}`;
303
358
 
304
359
  if (params.length === 0) {
360
+ const hasPhantoms = struct.type_parameters.some((p) => p.phantom);
361
+ const phantomPlaceholders = hasPhantoms
362
+ ? `<${struct.type_parameters.map((p, i) => `phantom ${p.name ?? `T${i}`}`).join(', ')}>`
363
+ : '';
305
364
  this.statements.push(
306
365
  ...parseTS /* ts */ `export const ${name} = ${
307
366
  struct.fields.positional_fields
308
- ? await this.#renderFieldsAsTuple(structName, struct.fields, struct.type_parameters)
309
- : await this.#renderFieldsAsStruct(structName, struct.fields, struct.type_parameters)
367
+ ? await this.#renderFieldsAsTuple(
368
+ `${structName}${phantomPlaceholders}`,
369
+ struct.fields,
370
+ struct.type_parameters,
371
+ includePhantom,
372
+ )
373
+ : await this.#renderFieldsAsStruct(
374
+ `${structName}${phantomPlaceholders}`,
375
+ struct.fields,
376
+ struct.type_parameters,
377
+ includePhantom,
378
+ )
310
379
  }`,
311
380
  );
312
381
  } else {
313
- this.addImport('@haneullabs/haneul/bcs', 'type BcsType');
382
+ const bcsTypeName = this.#getImportName('BcsType');
314
383
 
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(', ')}`;
384
+ const typeParams = `...typeParameters: [${params.map(({ param, originalIndex }) => param.name ?? `T${originalIndex}`).join(', ')}]`;
385
+ const typeGenerics = `${params.map(({ param, originalIndex }) => `${param.name ?? `T${originalIndex}`} extends ${bcsTypeName}<any>`).join(', ')}`;
386
+
387
+ let filteredIndex = 0;
388
+ const nameGenerics = struct.type_parameters
389
+ .map((param, i) => {
390
+ if (!includePhantom && param.phantom) {
391
+ return `phantom ${param.name ?? `T${i}`}`;
392
+ }
393
+ const idx = filteredIndex++;
394
+ const paramName = param.name ?? `T${idx}`;
395
+ return `\${typeParameters[${idx}].name as ${paramName}['name']}`;
396
+ })
397
+ .join(', ');
318
398
 
319
399
  this.statements.push(
320
400
  ...(await withComment(
@@ -326,11 +406,13 @@ export class MoveModuleBuilder extends FileBuilder {
326
406
  `${structName}<${nameGenerics}>`,
327
407
  struct.fields,
328
408
  struct.type_parameters,
409
+ includePhantom,
329
410
  )
330
411
  : await this.#renderFieldsAsStruct(
331
412
  `${structName}<${nameGenerics}>`,
332
413
  struct.fields,
333
414
  struct.type_parameters,
415
+ includePhantom,
334
416
  )
335
417
  }
336
418
  }`,
@@ -352,7 +434,8 @@ export class MoveModuleBuilder extends FileBuilder {
352
434
  );
353
435
  }
354
436
 
355
- this.addImport('~root/../utils/index.js', 'MoveEnum');
437
+ const includePhantom = this.#includePhantomTypeParameters;
438
+ const moveEnumName = this.#getImportName('MoveEnum');
356
439
  this.exports.push(name);
357
440
 
358
441
  const enumName = `\${$moduleName}::${name}`;
@@ -370,16 +453,15 @@ export class MoveModuleBuilder extends FileBuilder {
370
453
  format: 'bcs',
371
454
  summary: this.summary,
372
455
  typeParameters: enumDef.type_parameters,
373
- onBcsType: () => {
374
- this.addImport('@haneullabs/haneul/bcs', 'bcs');
375
- },
456
+ includePhantomTypeParameters: includePhantom,
457
+ bcsImport: () => this.#getImportName('bcs'),
376
458
  resolveAddress: (address) => this.#resolveAddress(address),
377
459
  onDependency: (address, mod) => {
378
460
  if (address !== this.summary.id.address || mod !== this.summary.id.name) {
379
461
  return this.addStarImport(
380
462
  address === this.summary.id.address
381
- ? `./${mod}.js`
382
- : `~root/deps/${address}/${mod}.js`,
463
+ ? `./${mod}${this.#importExtension}`
464
+ : `~root/deps/${address}/${mod}${this.#importExtension}`,
383
465
  mod,
384
466
  );
385
467
  }
@@ -391,37 +473,56 @@ export class MoveModuleBuilder extends FileBuilder {
391
473
  `${name}.${variantName}`,
392
474
  variant.fields,
393
475
  enumDef.type_parameters,
476
+ includePhantom,
394
477
  )
395
478
  : await this.#renderFieldsAsStruct(
396
479
  `${name}.${variantName}`,
397
480
  variant.fields,
398
481
  enumDef.type_parameters,
482
+ includePhantom,
399
483
  ),
400
484
  ],
401
485
  });
402
486
 
403
- const params = enumDef.type_parameters.filter((param) => !param.phantom);
487
+ const params = enumDef.type_parameters
488
+ .map((param, i) => ({ param, originalIndex: i }))
489
+ .filter(({ param }) => includePhantom || !param.phantom);
404
490
 
405
491
  if (params.length === 0) {
492
+ const hasPhantoms = enumDef.type_parameters.some((p) => p.phantom);
493
+ const phantomPlaceholders = hasPhantoms
494
+ ? `<${enumDef.type_parameters.map((p, i) => `phantom ${p.name ?? `T${i}`}`).join(', ')}>`
495
+ : '';
406
496
  this.statements.push(
407
497
  ...(await withComment(
408
498
  enumDef,
409
- parseTS /* ts */ `export const ${name} = new MoveEnum({ name: \`${enumName}\`, fields: ${variantsObject} })`,
499
+ parseTS /* ts */ `export const ${name} = new ${moveEnumName}({ name: \`${enumName}${phantomPlaceholders}\`, fields: ${variantsObject} })`,
410
500
  )),
411
501
  );
412
502
  } else {
413
- this.addImport('@haneullabs/haneul/bcs', 'type BcsType');
503
+ const bcsTypeName = this.#getImportName('BcsType');
504
+
505
+ const typeParams = `...typeParameters: [${params.map(({ param, originalIndex }) => param.name ?? `T${originalIndex}`).join(', ')}]`;
506
+ const typeGenerics = `${params.map(({ param, originalIndex }) => `${param.name ?? `T${originalIndex}`} extends ${bcsTypeName}<any>`).join(', ')}`;
414
507
 
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(', ')}`;
508
+ let filteredIndex = 0;
509
+ const nameGenerics = enumDef.type_parameters
510
+ .map((param, i) => {
511
+ if (!includePhantom && param.phantom) {
512
+ return `phantom ${param.name ?? `T${i}`}`;
513
+ }
514
+ const idx = filteredIndex++;
515
+ const paramName = param.name ?? `T${idx}`;
516
+ return `\${typeParameters[${idx}].name as ${paramName}['name']}`;
517
+ })
518
+ .join(', ');
418
519
 
419
520
  this.statements.push(
420
521
  ...(await withComment(
421
522
  enumDef,
422
523
  parseTS /* ts */ `
423
524
  export function ${name}<${typeGenerics}>(${typeParams}) {
424
- return new MoveEnum({ name: \`${enumName}<${nameGenerics}>\`, fields: ${variantsObject} })
525
+ return new ${moveEnumName}({ name: \`${enumName}<${nameGenerics}>\`, fields: ${variantsObject} })
425
526
  }`,
426
527
  )),
427
528
  );
@@ -434,7 +535,8 @@ export class MoveModuleBuilder extends FileBuilder {
434
535
  if (!this.hasFunctions()) {
435
536
  return;
436
537
  }
437
- this.addImport('@haneullabs/haneul/transactions', 'type Transaction');
538
+
539
+ const transactionTypeName = this.#getImportName('Transaction');
438
540
 
439
541
  for (const [name, func] of Object.entries(this.summary.functions)) {
440
542
  if (func.macro_ || !this.#includedFunctions.has(name)) {
@@ -453,51 +555,51 @@ export class MoveModuleBuilder extends FileBuilder {
453
555
  !isWellKnownObjectParameter(param.type_, (address) => this.#resolveAddress(address)),
454
556
  );
455
557
 
456
- if (parameters.length > 0) {
457
- this.addImport('~root/../utils/index.js', 'normalizeMoveArguments');
458
- }
558
+ const normalizeName =
559
+ parameters.length > 0 ? this.#getImportName('normalizeMoveArguments') : null;
459
560
 
460
561
  names.push(fnName);
461
562
 
462
563
  const usedTypeParameters = new Set<number | string>();
463
564
 
565
+ const rawTxArgName =
566
+ requiredParameters.length > 0 ? this.#getImportName('RawTransactionArgument') : null;
567
+
464
568
  const argumentsTypes = requiredParameters
465
569
  .map((param) =>
466
570
  renderTypeSignature(param.type_, {
467
571
  format: 'typescriptArg',
468
572
  summary: this.summary,
469
573
  typeParameters: func.type_parameters,
574
+ includePhantomTypeParameters: false,
470
575
  resolveAddress: (address) => this.#resolveAddress(address),
471
576
  onTypeParameter: (typeParameter) => usedTypeParameters.add(typeParameter),
472
577
  }),
473
578
  )
474
579
  .map((type, i) =>
475
580
  requiredParameters[i].name
476
- ? `${camelCase(requiredParameters[i].name)}: RawTransactionArgument<${type}>`
477
- : `RawTransactionArgument<${type}>`,
581
+ ? `${camelCase(requiredParameters[i].name)}: ${rawTxArgName}<${type}>`
582
+ : `${rawTxArgName}<${type}>`,
478
583
  )
479
584
  .join(',\n');
480
585
 
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
- }
586
+ const bcsTypeName = usedTypeParameters.size > 0 ? this.#getImportName('BcsType') : null;
488
587
 
489
- const filteredTypeParameters = func.type_parameters.filter(
490
- (param, i) =>
491
- usedTypeParameters.has(i) || (param.name && usedTypeParameters.has(param.name)),
492
- );
588
+ const filteredTypeParameters = func.type_parameters
589
+ .map((param, i) => ({ param, originalIndex: i }))
590
+ .filter(
591
+ ({ param, originalIndex }) =>
592
+ usedTypeParameters.has(originalIndex) ||
593
+ (param.name && usedTypeParameters.has(param.name)),
594
+ );
493
595
 
494
596
  const genericTypes =
495
597
  filteredTypeParameters.length > 0
496
- ? `<${filteredTypeParameters.map((param, i) => `${param.name ?? `T${i}`} extends BcsType<any>`).join(', ')}>`
598
+ ? `<${filteredTypeParameters.map(({ param, originalIndex }) => `${param.name ?? `T${originalIndex}`} extends ${bcsTypeName}<any>`).join(', ')}>`
497
599
  : '';
498
600
  const genericTypeArgs =
499
601
  filteredTypeParameters.length > 0
500
- ? `<${filteredTypeParameters.map((param, i) => `${param.name ?? `T${i}`}`).join(', ')}>`
602
+ ? `<${filteredTypeParameters.map(({ param, originalIndex }) => `${param.name ?? `T${originalIndex}`}`).join(', ')}>`
501
603
  : '';
502
604
 
503
605
  const argumentsInterface = this.getUnusedName(
@@ -544,19 +646,22 @@ export class MoveModuleBuilder extends FileBuilder {
544
646
  format: 'typeTag',
545
647
  summary: this.summary,
546
648
  typeParameters: func.type_parameters,
649
+ includePhantomTypeParameters: false,
547
650
  resolveAddress: (address) => this.#resolveAddress(address),
548
651
  }),
549
652
  )
550
- .map((tag) => (tag.includes('{') ? `\`${tag}\`` : `'${tag}'`))
653
+ .map((tag) =>
654
+ tag === 'null' ? 'null' : tag.includes('{') ? `\`${tag}\`` : `'${tag}'`,
655
+ )
551
656
  .join(',\n')}
552
- ] satisfies string[]\n`
657
+ ] satisfies (string | null)[]\n`
553
658
  : ''
554
659
  }${hasAllParameterNames ? `const parameterNames = ${JSON.stringify(requiredParameters.map((param) => camelCase(param.name!)))}\n` : ''}
555
- return (tx: Transaction) => tx.moveCall({
660
+ return (tx: ${transactionTypeName}) => tx.moveCall({
556
661
  package: packageAddress,
557
662
  module: '${this.summary.id.name}',
558
663
  function: '${name}',
559
- ${parameters.length > 0 ? `arguments: normalizeMoveArguments(options.arguments${argumentsTypes.length > 0 ? '' : ' ?? []'} , argumentsTypes${hasAllParameterNames ? `, parameterNames` : ''}),` : ''}
664
+ ${parameters.length > 0 ? `arguments: ${normalizeName}(options.arguments${argumentsTypes.length > 0 ? '' : ' ?? []'} , argumentsTypes${hasAllParameterNames ? `, parameterNames` : ''}),` : ''}
560
665
  ${func.type_parameters.length ? 'typeArguments: options.typeArguments' : ''}
561
666
  })
562
667
  }`,