@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
@@ -3,16 +3,23 @@
3
3
 
4
4
  import type { LocalContext } from '../../context.js';
5
5
  import { generateFromPackageSummary } from '../../../index.js';
6
- import { loadConfig } from '../../../config.js';
6
+ import { loadConfig, type GenerateBase, type PackageGenerate } from '../../../config.js';
7
7
  import { isValidNamedPackage, isValidHaneulObjectId } from '@haneullabs/haneul/utils';
8
8
  import { execSync } from 'node:child_process';
9
- import { existsSync } from 'node:fs';
9
+ import { existsSync, mkdtempSync } from 'node:fs';
10
+ import { tmpdir } from 'node:os';
11
+ import { join } from 'node:path';
10
12
 
11
13
  export interface SubdirCommandFlags {
12
14
  outputDir?: string;
13
15
  noPrune?: boolean;
14
16
  noSummaries?: boolean;
15
17
  network?: 'mainnet' | 'testnet';
18
+ importExtension?: '.js' | '.ts' | 'none';
19
+ modules?: string[];
20
+ noTypes?: boolean;
21
+ noFunctions?: boolean;
22
+ private?: 'none' | 'entry' | 'all';
16
23
  }
17
24
 
18
25
  export default async function generate(
@@ -31,6 +38,7 @@ export default async function generate(
31
38
  network: flags.network ?? 'testnet',
32
39
  packageName: isValidHaneulObjectId(trimmed) ? trimmed : trimmed.split('/')[1],
33
40
  package: trimmed,
41
+ packageId: isValidHaneulObjectId(trimmed) ? trimmed : undefined,
34
42
  };
35
43
  } else {
36
44
  return {
@@ -45,8 +53,53 @@ export default async function generate(
45
53
  const generateSummaries =
46
54
  flags.noSummaries === undefined ? config.generateSummaries : !flags.noSummaries;
47
55
 
56
+ const cliPrivate =
57
+ flags.private !== undefined
58
+ ? flags.private === 'all'
59
+ ? true
60
+ : flags.private === 'none'
61
+ ? false
62
+ : 'entry'
63
+ : undefined;
64
+
65
+ const cliGenerate: PackageGenerate | undefined =
66
+ flags.modules !== undefined ||
67
+ flags.noTypes !== undefined ||
68
+ flags.noFunctions !== undefined ||
69
+ flags.private !== undefined
70
+ ? {
71
+ ...(flags.modules !== undefined && { modules: flags.modules }),
72
+ ...(flags.noTypes !== undefined && { types: !flags.noTypes as boolean }),
73
+ ...(flags.noFunctions !== undefined || flags.private !== undefined
74
+ ? {
75
+ functions: flags.noFunctions
76
+ ? false
77
+ : cliPrivate !== undefined
78
+ ? { private: cliPrivate }
79
+ : true,
80
+ }
81
+ : {}),
82
+ }
83
+ : undefined;
84
+
48
85
  for (const pkg of normalizedPackages) {
49
- if (generateSummaries && pkg.path) {
86
+ // Detect on-chain packages: they have 'network' field and no 'path'
87
+ const isOnChainPackage =
88
+ ('packageId' in pkg && pkg.packageId) || ('network' in pkg && !('path' in pkg));
89
+
90
+ // Generate summaries for on-chain packages using --package-id
91
+ if (isOnChainPackage) {
92
+ const packageId = 'packageId' in pkg ? pkg.packageId : pkg.package;
93
+ const tempDir = mkdtempSync(join(tmpdir(), 'haneul-codegen-'));
94
+ console.log(`Generating summary for on-chain package ${packageId} to ${tempDir}`);
95
+
96
+ execSync(`haneul move summary --package-id ${packageId} --output-directory ${tempDir}`, {
97
+ stdio: 'inherit',
98
+ });
99
+
100
+ // Set the path to use the generated summary directory
101
+ (pkg as { path?: string }).path = tempDir;
102
+ } else if (generateSummaries && pkg.path) {
50
103
  if (!existsSync(pkg.path)) {
51
104
  throw new Error(`Package path does not exist: ${pkg.path}`);
52
105
  }
@@ -56,11 +109,46 @@ export default async function generate(
56
109
  stdio: 'inherit',
57
110
  });
58
111
  }
112
+ const importExtension =
113
+ flags.importExtension === undefined
114
+ ? config.importExtension
115
+ : flags.importExtension === 'none'
116
+ ? ''
117
+ : flags.importExtension;
118
+
119
+ const pkgWithOverrides = cliGenerate
120
+ ? {
121
+ ...pkg,
122
+ generate: {
123
+ ...('generate' in pkg ? pkg.generate : {}),
124
+ ...cliGenerate,
125
+ },
126
+ }
127
+ : pkg;
128
+
129
+ // Fold deprecated privateMethods into globalGenerate
130
+ const globalGenerate: GenerateBase | undefined =
131
+ config.privateMethods && !config.generate?.functions
132
+ ? {
133
+ ...config.generate,
134
+ functions: {
135
+ private:
136
+ config.privateMethods === 'all'
137
+ ? true
138
+ : config.privateMethods === 'none'
139
+ ? false
140
+ : 'entry',
141
+ },
142
+ }
143
+ : config.generate;
144
+
59
145
  await generateFromPackageSummary({
60
- package: pkg,
146
+ package: pkgWithOverrides,
61
147
  prune: flags.noPrune === undefined ? config.prune : !flags.noPrune,
62
148
  outputDir: flags.outputDir ?? config.output,
63
- privateMethods: config.privateMethods,
149
+ globalGenerate,
150
+ importExtension,
151
+ includePhantomTypeParameters: config.includePhantomTypeParameters,
64
152
  });
65
153
  }
66
154
  }
package/src/config.ts CHANGED
@@ -5,6 +5,42 @@ import { isValidNamedPackage, isValidHaneulObjectId } from '@haneullabs/haneul/u
5
5
  import { cosmiconfig } from 'cosmiconfig';
6
6
  import * as z from 'zod/v4';
7
7
 
8
+ export const globalFunctionsOptionSchema = z.union([
9
+ z.boolean(),
10
+ z.object({
11
+ private: z.union([z.boolean(), z.literal('entry')]).optional(),
12
+ }),
13
+ ]);
14
+
15
+ export const functionsOptionSchema = z.union([
16
+ z.boolean(),
17
+ z.array(z.string()),
18
+ z.object({
19
+ private: z.union([z.boolean(), z.literal('entry')]).optional(),
20
+ }),
21
+ ]);
22
+
23
+ export const typesOptionSchema = z.union([z.boolean(), z.array(z.string())]);
24
+
25
+ export const globalGenerateSchema = z.object({
26
+ functions: globalFunctionsOptionSchema.optional(),
27
+ types: z.boolean().optional(),
28
+ });
29
+
30
+ export const moduleGenerateSchema = z.object({
31
+ functions: functionsOptionSchema.optional(),
32
+ types: typesOptionSchema.optional(),
33
+ });
34
+
35
+ export const packageGenerateSchema = globalGenerateSchema.extend({
36
+ modules: z
37
+ .union([
38
+ z.array(z.string()),
39
+ z.record(z.string(), z.union([z.literal(true), moduleGenerateSchema])),
40
+ ])
41
+ .optional(),
42
+ });
43
+
8
44
  export const onChainPackageSchema = z.object({
9
45
  package: z.string().refine((name) => isValidNamedPackage(name) || isValidHaneulObjectId(name), {
10
46
  message: 'Invalid package name or package ID',
@@ -12,32 +48,43 @@ export const onChainPackageSchema = z.object({
12
48
  packageName: z.string(),
13
49
  path: z.never().optional(),
14
50
  network: z.enum(['mainnet', 'testnet']),
51
+ generate: packageGenerateSchema.optional(),
15
52
  });
16
53
 
17
54
  export const localPackageSchema = z.object({
18
55
  path: z.string(),
19
56
  package: z.string(),
20
57
  packageName: z.string().optional(),
58
+ generate: packageGenerateSchema.optional(),
21
59
  });
22
60
 
23
61
  export const packageConfigSchema = z.union([onChainPackageSchema, localPackageSchema]);
24
62
 
63
+ export const importExtensionSchema = z.union([z.literal('.js'), z.literal('.ts'), z.literal('')]);
64
+ export type ImportExtension = z.infer<typeof importExtensionSchema>;
65
+
66
+ export type GenerateBase = z.infer<typeof globalGenerateSchema>;
67
+ export type PackageGenerate = z.infer<typeof packageGenerateSchema>;
68
+ export type FunctionsOption = z.infer<typeof functionsOptionSchema>;
69
+ export type TypesOption = z.infer<typeof typesOptionSchema>;
70
+
25
71
  export const configSchema = z.object({
26
72
  output: z.string(),
27
73
  prune: z.boolean().optional().default(true),
28
74
  generateSummaries: z.boolean().optional().default(true),
29
75
  packages: z.array(packageConfigSchema),
30
- privateMethods: z
31
- .union([z.literal('none'), z.literal('entry'), z.literal('all')])
32
- .optional()
33
- .default('entry'),
76
+ generate: globalGenerateSchema.optional(),
77
+ /** @deprecated Use `generate: { functions: { private: 'entry' } }` instead */
78
+ privateMethods: z.union([z.literal('none'), z.literal('entry'), z.literal('all')]).optional(),
79
+ importExtension: importExtensionSchema.optional().default('.js'),
80
+ includePhantomTypeParameters: z.boolean().optional().default(false),
34
81
  });
35
82
 
36
83
  export type PackageConfig = z.infer<typeof packageConfigSchema>;
37
84
  export type HaneulCodegenConfig = z.input<typeof configSchema>;
38
- export type ParsedHaneulCodegenConfig = z.infer<typeof configSchema>;
85
+ export type ParsedSuiCodegenConfig = z.infer<typeof configSchema>;
39
86
 
40
- export async function loadConfig(): Promise<ParsedHaneulCodegenConfig> {
87
+ export async function loadConfig(): Promise<ParsedSuiCodegenConfig> {
41
88
  const config = await cosmiconfig('haneul-codegen').search();
42
89
 
43
90
  if (!config) {
@@ -46,7 +93,8 @@ export async function loadConfig(): Promise<ParsedHaneulCodegenConfig> {
46
93
  packages: [],
47
94
  prune: true,
48
95
  generateSummaries: true,
49
- privateMethods: 'entry',
96
+ importExtension: '.js',
97
+ includePhantomTypeParameters: false,
50
98
  };
51
99
  }
52
100
 
@@ -13,12 +13,25 @@ export class FileBuilder {
13
13
  starImports: Map<string, string> = new Map();
14
14
  protected reservedNames: Set<string> = new Set();
15
15
 
16
- addImport(module: string, name: string) {
16
+ addImport(module: string, name: string): string {
17
17
  if (!this.imports.has(module)) {
18
18
  this.imports.set(module, new Set());
19
19
  }
20
20
 
21
+ const isTypeImport = name.startsWith('type ');
22
+ const baseName = isTypeImport ? name.slice(5) : name;
23
+
24
+ if (this.reservedNames.has(baseName)) {
25
+ const alias = this.getUnusedName(baseName);
26
+ const aliasedImport = isTypeImport
27
+ ? `type ${baseName} as ${alias}`
28
+ : `${baseName} as ${alias}`;
29
+ this.imports.get(module)!.add(aliasedImport);
30
+ return alias;
31
+ }
32
+
21
33
  this.imports.get(module)!.add(name);
34
+ return baseName;
22
35
  }
23
36
 
24
37
  addStarImport(module: string, name: string) {
@@ -2,16 +2,36 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  export const utilsContent = /* ts */ `
5
- import { bcs, BcsType, TypeTag, TypeTagSerializer, BcsStruct, BcsEnum, BcsTuple } from '@haneullabs/haneul/bcs';
5
+ import {
6
+ bcs,
7
+ BcsType,
8
+ TypeTag,
9
+ TypeTagSerializer,
10
+ BcsStruct,
11
+ BcsEnum,
12
+ BcsTuple,
13
+ } from '@haneullabs/haneul/bcs';
6
14
  import { normalizeHaneulAddress } from '@haneullabs/haneul/utils';
7
15
  import { TransactionArgument, isArgument } from '@haneullabs/haneul/transactions';
16
+ import { ClientWithCoreApi, HaneulClientTypes } from '@haneullabs/haneul/client';
8
17
 
9
18
  const MOVE_STDLIB_ADDRESS = normalizeHaneulAddress('0x1');
10
19
  const HANEUL_FRAMEWORK_ADDRESS = normalizeHaneulAddress('0x2');
11
- const HANEUL_SYSTEM_ADDRESS = normalizeHaneulAddress('0x3');
12
20
 
13
21
  export type RawTransactionArgument<T> = T | TransactionArgument;
14
22
 
23
+ export interface GetOptions<
24
+ Include extends Omit<HaneulClientTypes.ObjectInclude, 'content'> = {},
25
+ > extends HaneulClientTypes.GetObjectOptions<Include> {
26
+ client: ClientWithCoreApi;
27
+ }
28
+
29
+ export interface GetManyOptions<
30
+ Include extends Omit<HaneulClientTypes.ObjectInclude, 'content'> = {},
31
+ > extends HaneulClientTypes.GetObjectsOptions<Include> {
32
+ client: ClientWithCoreApi;
33
+ }
34
+
15
35
  export function getPureBcsSchema(typeTag: string | TypeTag): BcsType<any> | null {
16
36
  const parsedTag = typeof typeTag === 'string' ? TypeTagSerializer.parseFromStr(typeTag) : typeTag;
17
37
 
@@ -36,7 +56,7 @@ export function getPureBcsSchema(typeTag: string | TypeTag): BcsType<any> | null
36
56
  return type ? bcs.vector(type) : null;
37
57
  } else if ('struct' in parsedTag) {
38
58
  const structTag = parsedTag.struct;
39
- const pkg = normalizeHaneulAddress(parsedTag.struct.address);
59
+ const pkg = normalizeHaneulAddress(structTag.address);
40
60
 
41
61
  if (pkg === MOVE_STDLIB_ADDRESS) {
42
62
  if (
@@ -47,12 +67,16 @@ export function getPureBcsSchema(typeTag: string | TypeTag): BcsType<any> | null
47
67
  }
48
68
 
49
69
  if (structTag.module === 'option' && structTag.name === 'Option') {
50
- const type = getPureBcsSchema(structTag.typeParams[0]!);
70
+ const type = getPureBcsSchema(structTag.typeParams[0]);
51
71
  return type ? bcs.option(type) : null;
52
72
  }
53
73
  }
54
74
 
55
- if (pkg === HANEUL_FRAMEWORK_ADDRESS && structTag.module === 'Object' && structTag.name === 'ID') {
75
+ if (
76
+ pkg === HANEUL_FRAMEWORK_ADDRESS &&
77
+ structTag.module === 'object' &&
78
+ (structTag.name === 'ID' || structTag.name === 'UID')
79
+ ) {
56
80
  return bcs.Address;
57
81
  }
58
82
  }
@@ -60,7 +84,11 @@ export function getPureBcsSchema(typeTag: string | TypeTag): BcsType<any> | null
60
84
  return null;
61
85
  }
62
86
 
63
- export function normalizeMoveArguments(args: unknown[] | object, argTypes: string[], parameterNames?: string[]) {
87
+ export function normalizeMoveArguments(
88
+ args: unknown[] | object,
89
+ argTypes: readonly (string | null)[],
90
+ parameterNames?: string[],
91
+ ) {
64
92
  const argLen = Array.isArray(args) ? args.length : Object.keys(args).length;
65
93
  if (parameterNames && argLen !== parameterNames.length) {
66
94
  throw new Error(
@@ -72,30 +100,32 @@ export function normalizeMoveArguments(args: unknown[] | object, argTypes: strin
72
100
 
73
101
  let index = 0;
74
102
  for (const [i, argType] of argTypes.entries()) {
75
- if (argType === \`\${HANEUL_FRAMEWORK_ADDRESS}::deny_list::DenyList\`) {
76
- normalizedArgs.push((tx) => tx.object.denyList());
103
+ if (argType === '0x2::clock::Clock') {
104
+ normalizedArgs.push((tx) => tx.object.clock());
77
105
  continue;
78
106
  }
79
107
 
80
- if (argType === \`\${HANEUL_FRAMEWORK_ADDRESS}::random::Random\`) {
108
+ if (argType === '0x2::random::Random') {
81
109
  normalizedArgs.push((tx) => tx.object.random());
82
110
  continue;
83
111
  }
84
112
 
85
- if (argType === \`\${HANEUL_FRAMEWORK_ADDRESS}::clock::Clock\`) {
86
- normalizedArgs.push((tx) => tx.object.clock());
113
+ if (argType === '0x2::deny_list::DenyList') {
114
+ normalizedArgs.push((tx) => tx.object.denyList());
87
115
  continue;
88
116
  }
89
117
 
90
- if (argType === \`\${HANEUL_SYSTEM_ADDRESS}::haneul_system::HaneulSystemState\`) {
118
+ if (argType === '0x3::haneul_system::HaneulSystemState') {
91
119
  normalizedArgs.push((tx) => tx.object.system());
92
120
  continue;
93
121
  }
94
122
 
95
- let arg
123
+ let arg;
96
124
  if (Array.isArray(args)) {
97
125
  if (index >= args.length) {
98
- throw new Error(\`Invalid number of arguments, expected at least \${index + 1}, got \${args.length}\`);
126
+ throw new Error(
127
+ \`Invalid number of arguments, expected at least \${index + 1}, got \${args.length}\`,
128
+ );
99
129
  }
100
130
  arg = args[index];
101
131
  } else {
@@ -117,8 +147,8 @@ export function normalizeMoveArguments(args: unknown[] | object, argTypes: strin
117
147
  continue;
118
148
  }
119
149
 
120
- const type = argTypes[i]!;
121
- const bcsType = getPureBcsSchema(type);
150
+ const type = argTypes[i];
151
+ const bcsType = type === null ? null : getPureBcsSchema(type);
122
152
 
123
153
  if (bcsType) {
124
154
  const bytes = bcsType.serialize(arg as never);
@@ -138,7 +168,47 @@ export function normalizeMoveArguments(args: unknown[] | object, argTypes: strin
138
168
  export class MoveStruct<
139
169
  T extends Record<string, BcsType<any>>,
140
170
  const Name extends string = string,
141
- > extends BcsStruct<T, Name> {}
171
+ > extends BcsStruct<T, Name> {
172
+ async get<Include extends Omit<HaneulClientTypes.ObjectInclude, 'content' | 'json'> = {}>({
173
+ objectId,
174
+ ...options
175
+ }: GetOptions<Include>): Promise<
176
+ HaneulClientTypes.Object<Include & { content: true, json: true }> & { json: BcsStruct<T>['$inferType'] }
177
+ > {
178
+ const [res] = await this.getMany<Include>({
179
+ ...options,
180
+ objectIds: [objectId],
181
+ });
182
+
183
+ return res;
184
+ }
185
+
186
+ async getMany<Include extends Omit<HaneulClientTypes.ObjectInclude, 'content' | 'json'> = {}>({
187
+ client,
188
+ ...options
189
+ }: GetManyOptions<Include>): Promise<
190
+ Array<HaneulClientTypes.Object<Include & { content: true, json: true }> & { json: BcsStruct<T>['$inferType'] }>
191
+ > {
192
+ const response = (await client.core.getObjects({
193
+ ...options,
194
+ include: {
195
+ ...options.include,
196
+ content: true,
197
+ },
198
+ })) as HaneulClientTypes.GetObjectsResponse<Include & { content: true }>;
199
+
200
+ return response.objects.map((obj) => {
201
+ if (obj instanceof Error) {
202
+ throw obj;
203
+ }
204
+
205
+ return {
206
+ ...obj,
207
+ json: this.parse(obj.content),
208
+ };
209
+ });
210
+ }
211
+ }
142
212
 
143
213
  export class MoveEnum<
144
214
  T extends Record<string, BcsType<any> | null>,
@@ -146,7 +216,7 @@ export class MoveEnum<
146
216
  > extends BcsEnum<T, Name> {}
147
217
 
148
218
  export class MoveTuple<
149
- T extends readonly BcsType<any>[],
219
+ const T extends readonly BcsType<any>[],
150
220
  const Name extends string,
151
221
  > extends BcsTuple<T, Name> {}
152
222
 
package/src/index.ts CHANGED
@@ -1,40 +1,65 @@
1
1
  // Copyright (c) Mysten Labs, Inc.
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
- import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
4
+ import { mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises';
5
5
  import { basename, join } from 'node:path';
6
6
  import { MoveModuleBuilder } from './move-module-builder.js';
7
7
  import { existsSync, statSync } from 'node:fs';
8
8
  import { utilsContent } from './generate-utils.js';
9
9
  import { parse } from 'toml';
10
- import type { PackageConfig } from './config.js';
10
+ import type {
11
+ FunctionsOption,
12
+ GenerateBase,
13
+ ImportExtension,
14
+ PackageConfig,
15
+ PackageGenerate,
16
+ TypesOption,
17
+ } from './config.js';
11
18
  export { type HaneulCodegenConfig } from './config.js';
12
19
 
13
20
  export async function generateFromPackageSummary({
14
21
  package: pkg,
15
22
  prune,
16
23
  outputDir,
17
- privateMethods,
24
+ globalGenerate,
25
+ importExtension = '.js',
26
+ includePhantomTypeParameters = false,
18
27
  }: {
19
28
  package: PackageConfig;
20
29
  prune: boolean;
21
30
  outputDir: string;
22
- privateMethods: 'none' | 'entry' | 'all';
31
+ globalGenerate?: GenerateBase;
32
+ importExtension?: ImportExtension;
33
+ includePhantomTypeParameters?: boolean;
23
34
  }) {
24
35
  if (!pkg.path) {
25
- throw new Error(`On-chain packages are not supported yet (got ${pkg.package})`);
36
+ throw new Error(`Package path is required (got ${pkg.package})`);
26
37
  }
27
38
 
28
- const summaryDir = join(pkg.path, 'package_summaries');
39
+ // Check for on-chain package summary (directly in path) or local package summary (in package_summaries subdirectory)
40
+ const localSummaryDir = join(pkg.path, 'package_summaries');
41
+ const isOnChainPackage = existsSync(join(pkg.path, 'root_package_metadata.json'));
42
+ const summaryDir = isOnChainPackage ? pkg.path : localSummaryDir;
29
43
 
30
- if (!existsSync(summaryDir)) {
44
+ if (!existsSync(summaryDir) || !existsSync(join(summaryDir, 'address_mapping.json'))) {
31
45
  throw new Error(`Package summary directory not found: ${summaryDir}`);
32
46
  }
33
47
 
34
48
  let packageName = pkg.packageName!;
49
+ let mainPackageAddress: string | undefined;
35
50
  const mvrNameOrAddress = pkg.package;
36
51
 
37
- if (!pkg.packageName) {
52
+ if (isOnChainPackage) {
53
+ // For on-chain packages, get the main package address from root_package_metadata.json
54
+ const metadata = JSON.parse(
55
+ await readFile(join(pkg.path, 'root_package_metadata.json'), 'utf-8'),
56
+ );
57
+ mainPackageAddress = metadata.root_package_id;
58
+ // Use the package name provided or fall back to the full address
59
+ if (!packageName) {
60
+ packageName = mainPackageAddress!;
61
+ }
62
+ } else if (!pkg.packageName) {
38
63
  try {
39
64
  const packageToml = await readFile(join(pkg.path, 'Move.toml'), 'utf-8');
40
65
  packageName = parse(packageToml).package.name.toLowerCase();
@@ -48,10 +73,6 @@ export async function generateFromPackageSummary({
48
73
  }
49
74
  }
50
75
 
51
- if (!existsSync(summaryDir)) {
52
- throw new Error(`Package summary directory not found: ${summaryDir}`);
53
- }
54
-
55
76
  const addressMappings: Record<string, string> = JSON.parse(
56
77
  await readFile(join(summaryDir, 'address_mapping.json'), 'utf-8'),
57
78
  );
@@ -59,21 +80,35 @@ export async function generateFromPackageSummary({
59
80
  const packages = (await readdir(summaryDir)).filter((file) =>
60
81
  statSync(join(summaryDir, file)).isDirectory(),
61
82
  );
83
+
84
+ // For on-chain packages, the main package is identified by the root_package_id
85
+ // For local packages, it's identified by the packageName
86
+ const isMainPackage = (pkgDir: string) => {
87
+ if (isOnChainPackage) {
88
+ return pkgDir === mainPackageAddress;
89
+ }
90
+ return pkgDir === packageName;
91
+ };
92
+
62
93
  const modules = (
63
94
  await Promise.all(
64
- packages.map(async (pkg) => {
65
- const modules = await readdir(join(summaryDir, pkg));
95
+ packages.map(async (pkgDir) => {
96
+ const moduleFiles = await readdir(join(summaryDir, pkgDir));
66
97
  return Promise.all(
67
- modules.map(async (mod) => ({
68
- package: pkg,
69
- isMainPackage: pkg === packageName,
70
- module: basename(mod, '.json'),
71
- builder: await MoveModuleBuilder.fromSummaryFile(
72
- join(summaryDir, pkg, mod),
73
- addressMappings,
74
- pkg === packageName ? mvrNameOrAddress : undefined,
75
- ),
76
- })),
98
+ moduleFiles
99
+ .filter((f) => f.endsWith('.json'))
100
+ .map(async (mod) => ({
101
+ package: pkgDir,
102
+ isMainPackage: isMainPackage(pkgDir),
103
+ module: basename(mod, '.json'),
104
+ builder: await MoveModuleBuilder.fromSummaryFile(
105
+ join(summaryDir, pkgDir, mod),
106
+ addressMappings,
107
+ isMainPackage(pkgDir) ? mvrNameOrAddress : undefined,
108
+ importExtension,
109
+ includePhantomTypeParameters,
110
+ ),
111
+ })),
77
112
  );
78
113
  }),
79
114
  )
@@ -83,15 +118,40 @@ export async function generateFromPackageSummary({
83
118
  modules.map((mod) => [`${mod.package}::${mod.module}`, mod.builder]),
84
119
  );
85
120
 
86
- modules.forEach((mod) => {
87
- if (mod.isMainPackage || !prune) {
88
- mod.builder.includeAllTypes(moduleBuilders);
89
- mod.builder.includeAllFunctions({ privateMethods });
121
+ const packageGenerate: PackageGenerate | undefined = 'generate' in pkg ? pkg.generate : undefined;
122
+ const pkgModules = packageGenerate?.modules;
123
+ const pkgTypes: TypesOption = packageGenerate?.types ?? globalGenerate?.types ?? true;
124
+ const pkgFunctions: FunctionsOption =
125
+ packageGenerate?.functions ?? globalGenerate?.functions ?? true;
126
+
127
+ for (const mod of modules) {
128
+ if (!mod.isMainPackage && prune) {
129
+ continue;
90
130
  }
91
- });
131
+
132
+ const moduleGenerate = !pkgModules
133
+ ? true
134
+ : Array.isArray(pkgModules)
135
+ ? pkgModules.includes(mod.module) || null
136
+ : mod.module in pkgModules
137
+ ? pkgModules[mod.module]
138
+ : null;
139
+
140
+ if (!moduleGenerate) continue;
141
+
142
+ const types = moduleGenerate === true ? pkgTypes : (moduleGenerate.types ?? false);
143
+ const functions = moduleGenerate === true ? pkgFunctions : (moduleGenerate.functions ?? false);
144
+
145
+ mod.builder.includeTypes(moduleBuilders, types);
146
+ mod.builder.includeFunctions(functions);
147
+ }
92
148
 
93
149
  await generateUtils({ outputDir });
94
150
 
151
+ // Clean the package output directory to remove stale files from previous runs
152
+ const packageOutputDir = join(outputDir, packageName);
153
+ await rm(packageOutputDir, { recursive: true, force: true });
154
+
95
155
  await Promise.all(
96
156
  modules.map(async (mod) => {
97
157
  if ((mod.isMainPackage || !prune) && mod.builder.hasTypesOrFunctions()) {