@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,74 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import type ts from 'typescript';
5
+ import { parseTS, printNodes } from './utils.js';
6
+ import { relative, resolve } from 'path';
7
+ import { getSafeName } from './render-types.js';
8
+
9
+ export class FileBuilder {
10
+ statements: ts.Statement[] = [];
11
+ exports: string[] = [];
12
+ imports: Map<string, Set<string>> = new Map();
13
+ starImports: Map<string, string> = new Map();
14
+ protected reservedNames: Set<string> = new Set();
15
+
16
+ addImport(module: string, name: string) {
17
+ if (!this.imports.has(module)) {
18
+ this.imports.set(module, new Set());
19
+ }
20
+
21
+ this.imports.get(module)!.add(name);
22
+ }
23
+
24
+ addStarImport(module: string, name: string) {
25
+ const importName = this.getUnusedName(name);
26
+ this.starImports.set(importName, module);
27
+ return importName;
28
+ }
29
+
30
+ getUnusedName(name: string) {
31
+ let deConflictedName = getSafeName(name);
32
+
33
+ let i = 1;
34
+ while (this.reservedNames.has(deConflictedName)) {
35
+ deConflictedName = `${name}_${i}`;
36
+ i++;
37
+ }
38
+
39
+ return deConflictedName;
40
+ }
41
+
42
+ async getHeader() {
43
+ return [
44
+ '/**************************************************************',
45
+ ' * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *',
46
+ ' **************************************************************/',
47
+ '',
48
+ ].join('\n');
49
+ }
50
+
51
+ async toString(modDir: string, filePath: string) {
52
+ const importStatements = [...this.imports.entries()].flatMap(
53
+ ([module, names]) =>
54
+ parseTS`import { ${[...names].join(', ')} } from '${modulePath(module)}'`,
55
+ );
56
+ const starImportStatements = [...this.starImports.entries()].flatMap(
57
+ ([name, module]) => parseTS`import * as ${name} from '${modulePath(module)}'`,
58
+ );
59
+
60
+ return `${await this.getHeader()}${printNodes(...importStatements, ...starImportStatements, ...this.statements)}`;
61
+
62
+ function modulePath(mod: string) {
63
+ if (!mod.startsWith('~root/')) {
64
+ return mod;
65
+ }
66
+
67
+ const sourcePath = resolve(modDir, filePath);
68
+ const destPath = resolve(modDir, mod.replace('~root/', './'));
69
+ const sourceDirectory = sourcePath.split('/').slice(0, -1).join('/');
70
+ const relativePath = relative(sourceDirectory, destPath);
71
+ return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;
72
+ }
73
+ }
74
+ }
@@ -0,0 +1,163 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export const utilsContent = /* ts */ `
5
+ import { bcs, BcsType, TypeTag, TypeTagSerializer, BcsStruct, BcsEnum, BcsTuple } from '@haneullabs/haneul/bcs';
6
+ import { normalizeHaneulAddress } from '@haneullabs/haneul/utils';
7
+ import { TransactionArgument, isArgument } from '@haneullabs/haneul/transactions';
8
+
9
+ const MOVE_STDLIB_ADDRESS = normalizeHaneulAddress('0x1');
10
+ const HANEUL_FRAMEWORK_ADDRESS = normalizeHaneulAddress('0x2');
11
+ const HANEUL_SYSTEM_ADDRESS = normalizeHaneulAddress('0x3');
12
+
13
+ export type RawTransactionArgument<T> = T | TransactionArgument;
14
+
15
+ export function getPureBcsSchema(typeTag: string | TypeTag): BcsType<any> | null {
16
+ const parsedTag = typeof typeTag === 'string' ? TypeTagSerializer.parseFromStr(typeTag) : typeTag;
17
+
18
+ if ('u8' in parsedTag) {
19
+ return bcs.U8;
20
+ } else if ('u16' in parsedTag) {
21
+ return bcs.U16;
22
+ } else if ('u32' in parsedTag) {
23
+ return bcs.U32;
24
+ } else if ('u64' in parsedTag) {
25
+ return bcs.U64;
26
+ } else if ('u128' in parsedTag) {
27
+ return bcs.U128;
28
+ } else if ('u256' in parsedTag) {
29
+ return bcs.U256;
30
+ } else if ('address' in parsedTag) {
31
+ return bcs.Address;
32
+ } else if ('bool' in parsedTag) {
33
+ return bcs.Bool;
34
+ } else if ('vector' in parsedTag) {
35
+ const type = getPureBcsSchema(parsedTag.vector);
36
+ return type ? bcs.vector(type) : null;
37
+ } else if ('struct' in parsedTag) {
38
+ const structTag = parsedTag.struct;
39
+ const pkg = normalizeHaneulAddress(parsedTag.struct.address);
40
+
41
+ if (pkg === MOVE_STDLIB_ADDRESS) {
42
+ if (
43
+ (structTag.module === 'ascii' || structTag.module === 'string') &&
44
+ structTag.name === 'String'
45
+ ) {
46
+ return bcs.String;
47
+ }
48
+
49
+ if (structTag.module === 'option' && structTag.name === 'Option') {
50
+ const type = getPureBcsSchema(structTag.typeParams[0]!);
51
+ return type ? bcs.option(type) : null;
52
+ }
53
+ }
54
+
55
+ if (pkg === HANEUL_FRAMEWORK_ADDRESS && structTag.module === 'Object' && structTag.name === 'ID') {
56
+ return bcs.Address;
57
+ }
58
+ }
59
+
60
+ return null;
61
+ }
62
+
63
+ export function normalizeMoveArguments(args: unknown[] | object, argTypes: string[], parameterNames?: string[]) {
64
+ const argLen = Array.isArray(args) ? args.length : Object.keys(args).length;
65
+ if (parameterNames && argLen !== parameterNames.length) {
66
+ throw new Error(
67
+ \`Invalid number of arguments, expected \${parameterNames.length}, got \${argLen}\`,
68
+ );
69
+ }
70
+
71
+ const normalizedArgs: TransactionArgument[] = [];
72
+
73
+ let index = 0;
74
+ for (const [i, argType] of argTypes.entries()) {
75
+ if (argType === \`\${HANEUL_FRAMEWORK_ADDRESS}::deny_list::DenyList\`) {
76
+ normalizedArgs.push((tx) => tx.object.denyList());
77
+ continue;
78
+ }
79
+
80
+ if (argType === \`\${HANEUL_FRAMEWORK_ADDRESS}::random::Random\`) {
81
+ normalizedArgs.push((tx) => tx.object.random());
82
+ continue;
83
+ }
84
+
85
+ if (argType === \`\${HANEUL_FRAMEWORK_ADDRESS}::clock::Clock\`) {
86
+ normalizedArgs.push((tx) => tx.object.clock());
87
+ continue;
88
+ }
89
+
90
+ if (argType === \`\${HANEUL_SYSTEM_ADDRESS}::haneul_system::HaneulSystemState\`) {
91
+ normalizedArgs.push((tx) => tx.object.system());
92
+ continue;
93
+ }
94
+
95
+ let arg
96
+ if (Array.isArray(args)) {
97
+ if (index >= args.length) {
98
+ throw new Error(\`Invalid number of arguments, expected at least \${index + 1}, got \${args.length}\`);
99
+ }
100
+ arg = args[index];
101
+ } else {
102
+ if (!parameterNames) {
103
+ throw new Error(\`Expected arguments to be passed as an array\`);
104
+ }
105
+ const name = parameterNames[index];
106
+ arg = args[name as keyof typeof args];
107
+
108
+ if (arg === undefined) {
109
+ throw new Error(\`Parameter \${name} is required\`);
110
+ }
111
+ }
112
+
113
+ index += 1;
114
+
115
+ if (typeof arg === 'function' || isArgument(arg)) {
116
+ normalizedArgs.push(arg as TransactionArgument);
117
+ continue;
118
+ }
119
+
120
+ const type = argTypes[i]!;
121
+ const bcsType = getPureBcsSchema(type);
122
+
123
+ if (bcsType) {
124
+ const bytes = bcsType.serialize(arg as never);
125
+ normalizedArgs.push((tx) => tx.pure(bytes));
126
+ continue;
127
+ } else if (typeof arg === 'string') {
128
+ normalizedArgs.push((tx) => tx.object(arg));
129
+ continue;
130
+ }
131
+
132
+ throw new Error(\`Invalid argument \${stringify(arg)} for type \${type}\`);
133
+ }
134
+
135
+ return normalizedArgs;
136
+ }
137
+
138
+ export class MoveStruct<
139
+ T extends Record<string, BcsType<any>>,
140
+ const Name extends string = string,
141
+ > extends BcsStruct<T, Name> {}
142
+
143
+ export class MoveEnum<
144
+ T extends Record<string, BcsType<any> | null>,
145
+ const Name extends string,
146
+ > extends BcsEnum<T, Name> {}
147
+
148
+ export class MoveTuple<
149
+ T extends readonly BcsType<any>[],
150
+ const Name extends string,
151
+ > extends BcsTuple<T, Name> {}
152
+
153
+ function stringify(val: unknown) {
154
+ if (typeof val === 'object') {
155
+ return JSON.stringify(val, (val: unknown) => val);
156
+ }
157
+ if (typeof val === 'bigint') {
158
+ return val.toString();
159
+ }
160
+
161
+ return val;
162
+ }
163
+ `;
package/src/index.ts ADDED
@@ -0,0 +1,131 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
5
+ import { basename, join } from 'node:path';
6
+ import { MoveModuleBuilder } from './move-module-builder.js';
7
+ import { existsSync, statSync } from 'node:fs';
8
+ import { utilsContent } from './generate-utils.js';
9
+ import { parse } from 'toml';
10
+ import type { PackageConfig } from './config.js';
11
+ export { type HaneulCodegenConfig } from './config.js';
12
+
13
+ export async function generateFromPackageSummary({
14
+ package: pkg,
15
+ prune,
16
+ outputDir,
17
+ privateMethods,
18
+ }: {
19
+ package: PackageConfig;
20
+ prune: boolean;
21
+ outputDir: string;
22
+ privateMethods: 'none' | 'entry' | 'all';
23
+ }) {
24
+ if (!pkg.path) {
25
+ throw new Error(`On-chain packages are not supported yet (got ${pkg.package})`);
26
+ }
27
+
28
+ const summaryDir = join(pkg.path, 'package_summaries');
29
+
30
+ if (!existsSync(summaryDir)) {
31
+ throw new Error(`Package summary directory not found: ${summaryDir}`);
32
+ }
33
+
34
+ let packageName = pkg.packageName!;
35
+ const mvrNameOrAddress = pkg.package;
36
+
37
+ if (!pkg.packageName) {
38
+ try {
39
+ const packageToml = await readFile(join(pkg.path, 'Move.toml'), 'utf-8');
40
+ packageName = parse(packageToml).package.name.toLowerCase();
41
+ } catch {
42
+ const message = `Package name not found in package.toml for ${pkg.path}`;
43
+ if (packageName) {
44
+ console.warn(message);
45
+ } else {
46
+ throw new Error(message);
47
+ }
48
+ }
49
+ }
50
+
51
+ if (!existsSync(summaryDir)) {
52
+ throw new Error(`Package summary directory not found: ${summaryDir}`);
53
+ }
54
+
55
+ const addressMappings: Record<string, string> = JSON.parse(
56
+ await readFile(join(summaryDir, 'address_mapping.json'), 'utf-8'),
57
+ );
58
+
59
+ const packages = (await readdir(summaryDir)).filter((file) =>
60
+ statSync(join(summaryDir, file)).isDirectory(),
61
+ );
62
+ const modules = (
63
+ await Promise.all(
64
+ packages.map(async (pkg) => {
65
+ const modules = await readdir(join(summaryDir, pkg));
66
+ 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
+ })),
77
+ );
78
+ }),
79
+ )
80
+ ).flat();
81
+
82
+ const moduleBuilders = Object.fromEntries(
83
+ modules.map((mod) => [`${mod.package}::${mod.module}`, mod.builder]),
84
+ );
85
+
86
+ modules.forEach((mod) => {
87
+ if (mod.isMainPackage || !prune) {
88
+ mod.builder.includeAllTypes(moduleBuilders);
89
+ mod.builder.includeAllFunctions({ privateMethods });
90
+ }
91
+ });
92
+
93
+ await generateUtils({ outputDir });
94
+
95
+ await Promise.all(
96
+ modules.map(async (mod) => {
97
+ if ((mod.isMainPackage || !prune) && mod.builder.hasTypesOrFunctions()) {
98
+ await mod.builder.renderBCSTypes();
99
+ await mod.builder.renderFunctions();
100
+ } else if (mod.isMainPackage) {
101
+ return;
102
+ } else if (mod.builder.hasBcsTypes()) {
103
+ await mod.builder.renderBCSTypes();
104
+ } else {
105
+ return;
106
+ }
107
+
108
+ await mkdir(
109
+ mod.isMainPackage
110
+ ? join(outputDir, packageName)
111
+ : join(outputDir, packageName, 'deps', mod.package),
112
+ { recursive: true },
113
+ );
114
+
115
+ await writeFile(
116
+ mod.isMainPackage
117
+ ? join(outputDir, packageName, `${mod.module}.ts`)
118
+ : join(outputDir, packageName, 'deps', mod.package, `${mod.module}.ts`),
119
+ await mod.builder.toString(
120
+ './',
121
+ mod.isMainPackage ? `./${mod.module}.ts` : `./deps/${mod.package}/${mod.module}.ts`,
122
+ ),
123
+ );
124
+ }),
125
+ );
126
+ }
127
+
128
+ async function generateUtils({ outputDir }: { outputDir: string }) {
129
+ await mkdir(join(outputDir, 'utils'), { recursive: true });
130
+ await writeFile(join(outputDir, 'utils', 'index.ts'), utilsContent);
131
+ }