@haneullabs/codegen 0.8.2 → 0.8.3
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.
- package/CHANGELOG.md +10 -0
- package/README.md +11 -11
- package/dist/bin/bash-complete.d.mts.map +1 -1
- package/dist/config.d.mts +0 -1
- package/dist/config.d.mts.map +1 -1
- package/dist/config.mjs.map +1 -1
- package/dist/file-builder.mjs +1 -0
- package/dist/file-builder.mjs.map +1 -1
- package/dist/index.d.mts.map +1 -1
- package/docs/index.md +436 -0
- package/docs/llms-index.md +6 -0
- package/package.json +7 -5
- package/src/config.ts +2 -2
- package/src/file-builder.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @mysten/codegen
|
|
2
2
|
|
|
3
|
+
## 0.8.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 43e69f8: Add embedded LLM-friendly docs to published packages
|
|
8
|
+
- Updated dependencies [43e69f8]
|
|
9
|
+
- Updated dependencies [e51dc5d]
|
|
10
|
+
- @mysten/bcs@2.0.3
|
|
11
|
+
- @mysten/sui@2.8.0
|
|
12
|
+
|
|
3
13
|
## 0.8.2
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -13,9 +13,9 @@ pnpm install @haneullabs/codegen
|
|
|
13
13
|
Then create a `haneul-codegen.config.ts` to define what packages you want to generate code for:
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
|
-
import type {
|
|
16
|
+
import type { HaneulCodegenConfig } from './src/config.js';
|
|
17
17
|
|
|
18
|
-
const config:
|
|
18
|
+
const config: HaneulCodegenConfig = {
|
|
19
19
|
output: './src/generated',
|
|
20
20
|
generateSummaries: true,
|
|
21
21
|
prune: true,
|
|
@@ -32,7 +32,7 @@ export default config;
|
|
|
32
32
|
|
|
33
33
|
The `package` field should be the MVR name for your move package. If you have not registered your
|
|
34
34
|
package on MVR yet, you can use the `@local-pkg` scope, and set up an override in your
|
|
35
|
-
`
|
|
35
|
+
`HaneulGrpcClient` to resolve it to the correct address.
|
|
36
36
|
|
|
37
37
|
## Generating code
|
|
38
38
|
|
|
@@ -68,13 +68,13 @@ or by adding something the following script to your package.json and running `pn
|
|
|
68
68
|
## Setting up Haneul Client with MVR
|
|
69
69
|
|
|
70
70
|
If your package is registered on MVR, the generated code should work without additional
|
|
71
|
-
configuration. If you are using a `@local-pkg` name, you will need to configure your `
|
|
71
|
+
configuration. If you are using a `@local-pkg` name, you will need to configure your `HaneulGrpcClient`
|
|
72
72
|
to resolve the package name correctly:
|
|
73
73
|
|
|
74
74
|
```ts
|
|
75
|
-
import {
|
|
75
|
+
import { HaneulGrpcClient } from '@haneullabs/haneul/grpc';
|
|
76
76
|
|
|
77
|
-
const client = new
|
|
77
|
+
const client = new HaneulGrpcClient({
|
|
78
78
|
network: 'testnet',
|
|
79
79
|
baseUrl: 'https://fullnode.testnet.haneul.io:443',
|
|
80
80
|
mvr: {
|
|
@@ -92,7 +92,7 @@ instance:
|
|
|
92
92
|
|
|
93
93
|
```ts
|
|
94
94
|
import { createDAppKit } from '@haneullabs/dapp-kit-core';
|
|
95
|
-
import {
|
|
95
|
+
import { HaneulGrpcClient } from '@haneullabs/haneul/grpc';
|
|
96
96
|
|
|
97
97
|
const GRPC_URLS = {
|
|
98
98
|
testnet: 'https://fullnode.testnet.haneul.io:443',
|
|
@@ -107,7 +107,7 @@ const PACKAGE_IDS = {
|
|
|
107
107
|
const dAppKit = createDAppKit({
|
|
108
108
|
networks: ['testnet'],
|
|
109
109
|
createClient: (network) => {
|
|
110
|
-
return new
|
|
110
|
+
return new HaneulGrpcClient({
|
|
111
111
|
network,
|
|
112
112
|
baseUrl: GRPC_URLS[network],
|
|
113
113
|
mvr: {
|
|
@@ -142,7 +142,7 @@ async function createCounter() {
|
|
|
142
142
|
// Add a create call
|
|
143
143
|
tx.add(counter.create());
|
|
144
144
|
|
|
145
|
-
const { digest } =
|
|
145
|
+
const { digest } = haneulClient.signAndExecuteTransaction({
|
|
146
146
|
transaction: tx,
|
|
147
147
|
signer: keypair,
|
|
148
148
|
});
|
|
@@ -161,7 +161,7 @@ async function incrementCount(id: string) {
|
|
|
161
161
|
}),
|
|
162
162
|
);
|
|
163
163
|
|
|
164
|
-
const { digest } =
|
|
164
|
+
const { digest } = haneulClient.signAndExecuteTransaction({
|
|
165
165
|
transaction: tx,
|
|
166
166
|
signer: keypair,
|
|
167
167
|
});
|
|
@@ -180,7 +180,7 @@ First, you will need to load the bcs data for your object, then parse it with yo
|
|
|
180
180
|
import * as counter from './generated/counter/counter';
|
|
181
181
|
|
|
182
182
|
async await function readCounter(id: string) {
|
|
183
|
-
const data =
|
|
183
|
+
const data = haneulClient.getObject({
|
|
184
184
|
id,
|
|
185
185
|
options: {
|
|
186
186
|
// request the bcs data when loading your object
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash-complete.d.mts","names":[],"sources":["../../src/bin/bash-complete.ts"],"
|
|
1
|
+
{"version":3,"file":"bash-complete.d.mts","names":[],"sources":["../../src/bin/bash-complete.ts"],"mappings":";;iBAqBsB,IAAA,CAAA,GAAI,OAAA"}
|
package/dist/config.d.mts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as z from "zod/v4";
|
|
2
2
|
|
|
3
3
|
//#region src/config.d.ts
|
|
4
|
-
|
|
5
4
|
declare const globalGenerateSchema: z.ZodObject<{
|
|
6
5
|
functions: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
7
6
|
private: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodLiteral<"entry">]>>;
|
package/dist/config.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.mts","names":[],"sources":["../src/config.ts"],"
|
|
1
|
+
{"version":3,"file":"config.d.mts","names":[],"sources":["../src/config.ts"],"mappings":";;;cAwBa,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;cAoCpB,mBAAA,EAAmB,CAAA,CAAA,QAAA,WAAA,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAEnB,qBAAA,EAAqB,CAAA,CAAA,QAAA,WAAA,CAAA,CAAA,UAAA,SAAA,CAAA,CAAA,UAAA,SAAA,CAAA,CAAA,UAAA;AAAA,KACtB,eAAA,GAAkB,CAAA,CAAE,KAAA,QAAa,qBAAA;AAAA,KAEjC,YAAA,GAAe,CAAA,CAAE,KAAA,QAAa,oBAAA;AAAA,cAK7B,YAAA,EAAY,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAYb,aAAA,GAAgB,CAAA,CAAE,KAAA,QAAa,mBAAA;AAAA,KAC/B,mBAAA,GAAsB,CAAA,CAAE,KAAA,QAAa,YAAA"}
|
package/dist/config.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.mjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { isValidNamedPackage, isValidHaneulObjectId } from '@haneullabs/haneul/utils';\nimport { cosmiconfig } from 'cosmiconfig';\nimport * as z from 'zod/v4';\n\nexport const globalFunctionsOptionSchema = z.union([\n\tz.boolean(),\n\tz.object({\n\t\tprivate: z.union([z.boolean(), z.literal('entry')]).optional(),\n\t}),\n]);\n\nexport const functionsOptionSchema = z.union([\n\tz.boolean(),\n\tz.array(z.string()),\n\tz.object({\n\t\tprivate: z.union([z.boolean(), z.literal('entry')]).optional(),\n\t}),\n]);\n\nexport const typesOptionSchema = z.union([z.boolean(), z.array(z.string())]);\n\nexport const globalGenerateSchema = z.object({\n\tfunctions: globalFunctionsOptionSchema.optional(),\n\ttypes: z.boolean().optional(),\n});\n\nexport const moduleGenerateSchema = z.object({\n\tfunctions: functionsOptionSchema.optional(),\n\ttypes: typesOptionSchema.optional(),\n});\n\nexport const packageGenerateSchema = globalGenerateSchema.extend({\n\tmodules: z\n\t\t.union([\n\t\t\tz.array(z.string()),\n\t\t\tz.record(z.string(), z.union([z.literal(true), moduleGenerateSchema])),\n\t\t])\n\t\t.optional(),\n});\n\nexport const onChainPackageSchema = z.object({\n\tpackage: z.string().refine((name) => isValidNamedPackage(name) || isValidHaneulObjectId(name), {\n\t\tmessage: 'Invalid package name or package ID',\n\t}),\n\tpackageName: z.string(),\n\tpath: z.never().optional(),\n\tnetwork: z.enum(['mainnet', 'testnet']),\n\tgenerate: packageGenerateSchema.optional(),\n});\n\nexport const localPackageSchema = z.object({\n\tpath: z.string(),\n\tpackage: z.string(),\n\tpackageName: z.string().optional(),\n\tgenerate: packageGenerateSchema.optional(),\n});\n\nexport const packageConfigSchema = z.union([onChainPackageSchema, localPackageSchema]);\n\nexport const importExtensionSchema = z.union([z.literal('.js'), z.literal('.ts'), z.literal('')]);\nexport type ImportExtension = z.infer<typeof importExtensionSchema>;\n\nexport type GenerateBase = z.infer<typeof globalGenerateSchema>;\nexport type PackageGenerate = z.infer<typeof packageGenerateSchema>;\nexport type FunctionsOption = z.infer<typeof functionsOptionSchema>;\nexport type TypesOption = z.infer<typeof typesOptionSchema>;\n\nexport const configSchema = z.object({\n\toutput: z.string(),\n\tprune: z.boolean().optional().default(true),\n\tgenerateSummaries: z.boolean().optional().default(true),\n\tpackages: z.array(packageConfigSchema),\n\tgenerate: globalGenerateSchema.optional(),\n\t/** @deprecated Use `generate: { functions: { private: 'entry' } }` instead */\n\tprivateMethods: z.union([z.literal('none'), z.literal('entry'), z.literal('all')]).optional(),\n\timportExtension: importExtensionSchema.optional().default('.js'),\n\tincludePhantomTypeParameters: z.boolean().optional().default(false),\n});\n\nexport type PackageConfig = z.infer<typeof packageConfigSchema>;\nexport type HaneulCodegenConfig = z.input<typeof configSchema>;\nexport type
|
|
1
|
+
{"version":3,"file":"config.mjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { isValidNamedPackage, isValidHaneulObjectId } from '@haneullabs/haneul/utils';\nimport { cosmiconfig } from 'cosmiconfig';\nimport * as z from 'zod/v4';\n\nexport const globalFunctionsOptionSchema = z.union([\n\tz.boolean(),\n\tz.object({\n\t\tprivate: z.union([z.boolean(), z.literal('entry')]).optional(),\n\t}),\n]);\n\nexport const functionsOptionSchema = z.union([\n\tz.boolean(),\n\tz.array(z.string()),\n\tz.object({\n\t\tprivate: z.union([z.boolean(), z.literal('entry')]).optional(),\n\t}),\n]);\n\nexport const typesOptionSchema = z.union([z.boolean(), z.array(z.string())]);\n\nexport const globalGenerateSchema = z.object({\n\tfunctions: globalFunctionsOptionSchema.optional(),\n\ttypes: z.boolean().optional(),\n});\n\nexport const moduleGenerateSchema = z.object({\n\tfunctions: functionsOptionSchema.optional(),\n\ttypes: typesOptionSchema.optional(),\n});\n\nexport const packageGenerateSchema = globalGenerateSchema.extend({\n\tmodules: z\n\t\t.union([\n\t\t\tz.array(z.string()),\n\t\t\tz.record(z.string(), z.union([z.literal(true), moduleGenerateSchema])),\n\t\t])\n\t\t.optional(),\n});\n\nexport const onChainPackageSchema = z.object({\n\tpackage: z.string().refine((name) => isValidNamedPackage(name) || isValidHaneulObjectId(name), {\n\t\tmessage: 'Invalid package name or package ID',\n\t}),\n\tpackageName: z.string(),\n\tpath: z.never().optional(),\n\tnetwork: z.enum(['mainnet', 'testnet']),\n\tgenerate: packageGenerateSchema.optional(),\n});\n\nexport const localPackageSchema = z.object({\n\tpath: z.string(),\n\tpackage: z.string(),\n\tpackageName: z.string().optional(),\n\tgenerate: packageGenerateSchema.optional(),\n});\n\nexport const packageConfigSchema = z.union([onChainPackageSchema, localPackageSchema]);\n\nexport const importExtensionSchema = z.union([z.literal('.js'), z.literal('.ts'), z.literal('')]);\nexport type ImportExtension = z.infer<typeof importExtensionSchema>;\n\nexport type GenerateBase = z.infer<typeof globalGenerateSchema>;\nexport type PackageGenerate = z.infer<typeof packageGenerateSchema>;\nexport type FunctionsOption = z.infer<typeof functionsOptionSchema>;\nexport type TypesOption = z.infer<typeof typesOptionSchema>;\n\nexport const configSchema = z.object({\n\toutput: z.string(),\n\tprune: z.boolean().optional().default(true),\n\tgenerateSummaries: z.boolean().optional().default(true),\n\tpackages: z.array(packageConfigSchema),\n\tgenerate: globalGenerateSchema.optional(),\n\t/** @deprecated Use `generate: { functions: { private: 'entry' } }` instead */\n\tprivateMethods: z.union([z.literal('none'), z.literal('entry'), z.literal('all')]).optional(),\n\timportExtension: importExtensionSchema.optional().default('.js'),\n\tincludePhantomTypeParameters: z.boolean().optional().default(false),\n});\n\nexport type PackageConfig = z.infer<typeof packageConfigSchema>;\nexport type HaneulCodegenConfig = z.input<typeof configSchema>;\nexport type ParsedHaneulCodegenConfig = z.infer<typeof configSchema>;\n\nexport async function loadConfig(): Promise<ParsedHaneulCodegenConfig> {\n\tconst config = await cosmiconfig('haneul-codegen').search();\n\n\tif (!config) {\n\t\treturn {\n\t\t\toutput: './generated',\n\t\t\tpackages: [],\n\t\t\tprune: true,\n\t\t\tgenerateSummaries: true,\n\t\t\timportExtension: '.js',\n\t\t\tincludePhantomTypeParameters: false,\n\t\t};\n\t}\n\n\treturn configSchema.parse(config.config);\n}\n"],"mappings":";;;;;AAOA,MAAa,8BAA8B,EAAE,MAAM,CAClD,EAAE,SAAS,EACX,EAAE,OAAO,EACR,SAAS,EAAE,MAAM,CAAC,EAAE,SAAS,EAAE,EAAE,QAAQ,QAAQ,CAAC,CAAC,CAAC,UAAU,EAC9D,CAAC,CACF,CAAC;AAEF,MAAa,wBAAwB,EAAE,MAAM;CAC5C,EAAE,SAAS;CACX,EAAE,MAAM,EAAE,QAAQ,CAAC;CACnB,EAAE,OAAO,EACR,SAAS,EAAE,MAAM,CAAC,EAAE,SAAS,EAAE,EAAE,QAAQ,QAAQ,CAAC,CAAC,CAAC,UAAU,EAC9D,CAAC;CACF,CAAC;AAEF,MAAa,oBAAoB,EAAE,MAAM,CAAC,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;AAE5E,MAAa,uBAAuB,EAAE,OAAO;CAC5C,WAAW,4BAA4B,UAAU;CACjD,OAAO,EAAE,SAAS,CAAC,UAAU;CAC7B,CAAC;AAEF,MAAa,uBAAuB,EAAE,OAAO;CAC5C,WAAW,sBAAsB,UAAU;CAC3C,OAAO,kBAAkB,UAAU;CACnC,CAAC;AAEF,MAAa,wBAAwB,qBAAqB,OAAO,EAChE,SAAS,EACP,MAAM,CACN,EAAE,MAAM,EAAE,QAAQ,CAAC,EACnB,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,MAAM,CAAC,EAAE,QAAQ,KAAK,EAAE,qBAAqB,CAAC,CAAC,CACtE,CAAC,CACD,UAAU,EACZ,CAAC;AAEF,MAAa,uBAAuB,EAAE,OAAO;CAC5C,SAAS,EAAE,QAAQ,CAAC,QAAQ,SAAS,oBAAoB,KAAK,IAAI,sBAAsB,KAAK,EAAE,EAC9F,SAAS,sCACT,CAAC;CACF,aAAa,EAAE,QAAQ;CACvB,MAAM,EAAE,OAAO,CAAC,UAAU;CAC1B,SAAS,EAAE,KAAK,CAAC,WAAW,UAAU,CAAC;CACvC,UAAU,sBAAsB,UAAU;CAC1C,CAAC;AAEF,MAAa,qBAAqB,EAAE,OAAO;CAC1C,MAAM,EAAE,QAAQ;CAChB,SAAS,EAAE,QAAQ;CACnB,aAAa,EAAE,QAAQ,CAAC,UAAU;CAClC,UAAU,sBAAsB,UAAU;CAC1C,CAAC;AAEF,MAAa,sBAAsB,EAAE,MAAM,CAAC,sBAAsB,mBAAmB,CAAC;AAEtF,MAAa,wBAAwB,EAAE,MAAM;CAAC,EAAE,QAAQ,MAAM;CAAE,EAAE,QAAQ,MAAM;CAAE,EAAE,QAAQ,GAAG;CAAC,CAAC;AAQjG,MAAa,eAAe,EAAE,OAAO;CACpC,QAAQ,EAAE,QAAQ;CAClB,OAAO,EAAE,SAAS,CAAC,UAAU,CAAC,QAAQ,KAAK;CAC3C,mBAAmB,EAAE,SAAS,CAAC,UAAU,CAAC,QAAQ,KAAK;CACvD,UAAU,EAAE,MAAM,oBAAoB;CACtC,UAAU,qBAAqB,UAAU;CAEzC,gBAAgB,EAAE,MAAM;EAAC,EAAE,QAAQ,OAAO;EAAE,EAAE,QAAQ,QAAQ;EAAE,EAAE,QAAQ,MAAM;EAAC,CAAC,CAAC,UAAU;CAC7F,iBAAiB,sBAAsB,UAAU,CAAC,QAAQ,MAAM;CAChE,8BAA8B,EAAE,SAAS,CAAC,UAAU,CAAC,QAAQ,MAAM;CACnE,CAAC;AAMF,eAAsB,aAAiD;CACtE,MAAM,SAAS,MAAM,YAAY,iBAAiB,CAAC,QAAQ;AAE3D,KAAI,CAAC,OACJ,QAAO;EACN,QAAQ;EACR,UAAU,EAAE;EACZ,OAAO;EACP,mBAAmB;EACnB,iBAAiB;EACjB,8BAA8B;EAC9B;AAGF,QAAO,aAAa,MAAM,OAAO,OAAO"}
|
package/dist/file-builder.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-builder.mjs","names":[],"sources":["../src/file-builder.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type ts from 'typescript';\nimport { parseTS, printNodes } from './utils.js';\nimport { relative, resolve } from 'path';\nimport { getSafeName } from './render-types.js';\n\nexport class FileBuilder {\n\tstatements: ts.Statement[] = [];\n\texports: string[] = [];\n\timports: Map<string, Set<string>> = new Map();\n\tstarImports: Map<string, string> = new Map();\n\tprotected reservedNames: Set<string> = new Set();\n\n\taddImport(module: string, name: string): string {\n\t\tif (!this.imports.has(module)) {\n\t\t\tthis.imports.set(module, new Set());\n\t\t}\n\n\t\tconst isTypeImport = name.startsWith('type ');\n\t\tconst baseName = isTypeImport ? name.slice(5) : name;\n\n\t\tif (this.reservedNames.has(baseName)) {\n\t\t\tconst alias = this.getUnusedName(baseName);\n\t\t\tconst aliasedImport = isTypeImport\n\t\t\t\t? `type ${baseName} as ${alias}`\n\t\t\t\t: `${baseName} as ${alias}`;\n\t\t\tthis.imports.get(module)!.add(aliasedImport);\n\t\t\treturn alias;\n\t\t}\n\n\t\tthis.imports.get(module)!.add(name);\n\t\treturn baseName;\n\t}\n\n\taddStarImport(module: string, name: string) {\n\t\tconst importName = this.getUnusedName(name);\n\t\tthis.starImports.set(importName, module);\n\t\treturn importName;\n\t}\n\n\tgetUnusedName(name: string) {\n\t\tlet deConflictedName = getSafeName(name);\n\n\t\tlet i = 1;\n\t\twhile (this.reservedNames.has(deConflictedName)) {\n\t\t\tdeConflictedName = `${name}_${i}`;\n\t\t\ti++;\n\t\t}\n\n\t\treturn deConflictedName;\n\t}\n\n\tasync getHeader() {\n\t\treturn [\n\t\t\t'/**************************************************************',\n\t\t\t' * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *',\n\t\t\t' **************************************************************/',\n\t\t\t'',\n\t\t].join('\\n');\n\t}\n\n\tasync toString(modDir: string, filePath: string) {\n\t\tconst importStatements = [...this.imports.entries()].flatMap(\n\t\t\t([module, names]) =>\n\t\t\t\tparseTS`import { ${[...names].join(', ')} } from '${modulePath(module)}'`,\n\t\t);\n\t\tconst starImportStatements = [...this.starImports.entries()].flatMap(\n\t\t\t([name, module]) => parseTS`import * as ${name} from '${modulePath(module)}'`,\n\t\t);\n\n\t\treturn `${await this.getHeader()}${printNodes(...importStatements, ...starImportStatements, ...this.statements)}`;\n\n\t\tfunction modulePath(mod: string) {\n\t\t\tif (!mod.startsWith('~root/')) {\n\t\t\t\treturn mod;\n\t\t\t}\n\n\t\t\tconst sourcePath = resolve(modDir, filePath);\n\t\t\tconst destPath = resolve(modDir, mod.replace('~root/', './'));\n\t\t\tconst sourceDirectory = sourcePath.split('/').slice(0, -1).join('/');\n\t\t\tconst relativePath = relative(sourceDirectory, destPath);\n\t\t\treturn relativePath.startsWith('.') ? relativePath : `./${relativePath}`;\n\t\t}\n\t}\n}\n"],"mappings":";;;;;AAQA,IAAa,cAAb,MAAyB;;oBACK,EAAE;iBACX,EAAE;iCACc,IAAI,KAAK;qCACV,IAAI,KAAK;uCACL,IAAI,KAAK;;CAEhD,UAAU,QAAgB,MAAsB;AAC/C,MAAI,CAAC,KAAK,QAAQ,IAAI,OAAO,CAC5B,MAAK,QAAQ,IAAI,wBAAQ,IAAI,KAAK,CAAC;EAGpC,MAAM,eAAe,KAAK,WAAW,QAAQ;EAC7C,MAAM,WAAW,eAAe,KAAK,MAAM,EAAE,GAAG;AAEhD,MAAI,KAAK,cAAc,IAAI,SAAS,EAAE;GACrC,MAAM,QAAQ,KAAK,cAAc,SAAS;GAC1C,MAAM,gBAAgB,eACnB,QAAQ,SAAS,MAAM,UACvB,GAAG,SAAS,MAAM;AACrB,QAAK,QAAQ,IAAI,OAAO,CAAE,IAAI,cAAc;AAC5C,UAAO;;AAGR,OAAK,QAAQ,IAAI,OAAO,CAAE,IAAI,KAAK;AACnC,SAAO;;CAGR,cAAc,QAAgB,MAAc;EAC3C,MAAM,aAAa,KAAK,cAAc,KAAK;AAC3C,OAAK,YAAY,IAAI,YAAY,OAAO;AACxC,SAAO;;CAGR,cAAc,MAAc;EAC3B,IAAI,mBAAmB,YAAY,KAAK;EAExC,IAAI,IAAI;AACR,SAAO,KAAK,cAAc,IAAI,iBAAiB,EAAE;AAChD,sBAAmB,GAAG,KAAK,GAAG;AAC9B;;AAGD,SAAO;;CAGR,MAAM,YAAY;AACjB,SAAO;GACN;GACA;GACA;GACA;GACA,CAAC,KAAK,KAAK;;CAGb,MAAM,SAAS,QAAgB,UAAkB;EAChD,MAAM,mBAAmB,CAAC,GAAG,KAAK,QAAQ,SAAS,CAAC,CAAC,SACnD,CAAC,QAAQ,WACT,OAAO,YAAY,CAAC,GAAG,MAAM,CAAC,KAAK,KAAK,CAAC,WAAW,WAAW,OAAO,CAAC,GACxE;EACD,MAAM,uBAAuB,CAAC,GAAG,KAAK,YAAY,SAAS,CAAC,CAAC,SAC3D,CAAC,MAAM,YAAY,OAAO,eAAe,KAAK,SAAS,WAAW,OAAO,CAAC,GAC3E;AAED,SAAO,GAAG,MAAM,KAAK,WAAW,GAAG,WAAW,GAAG,kBAAkB,GAAG,sBAAsB,GAAG,KAAK,WAAW;EAE/G,SAAS,WAAW,KAAa;AAChC,OAAI,CAAC,IAAI,WAAW,SAAS,CAC5B,QAAO;GAGR,MAAM,aAAa,QAAQ,QAAQ,SAAS;GAC5C,MAAM,WAAW,QAAQ,QAAQ,IAAI,QAAQ,UAAU,KAAK,CAAC;GAE7D,MAAM,eAAe,SADG,WAAW,MAAM,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,KAAK,IAAI,EACrB,SAAS;AACxD,UAAO,aAAa,WAAW,IAAI,GAAG,eAAe,KAAK"}
|
|
1
|
+
{"version":3,"file":"file-builder.mjs","names":[],"sources":["../src/file-builder.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type ts from 'typescript';\nimport { parseTS, printNodes } from './utils.js';\nimport { relative, resolve } from 'path';\nimport { getSafeName } from './render-types.js';\n\nexport class FileBuilder {\n\tstatements: ts.Statement[] = [];\n\texports: string[] = [];\n\timports: Map<string, Set<string>> = new Map();\n\tstarImports: Map<string, string> = new Map();\n\tprotected reservedNames: Set<string> = new Set();\n\n\taddImport(module: string, name: string): string {\n\t\tif (!this.imports.has(module)) {\n\t\t\tthis.imports.set(module, new Set());\n\t\t}\n\n\t\tconst isTypeImport = name.startsWith('type ');\n\t\tconst baseName = isTypeImport ? name.slice(5) : name;\n\n\t\tif (this.reservedNames.has(baseName)) {\n\t\t\tconst alias = this.getUnusedName(baseName);\n\t\t\tconst aliasedImport = isTypeImport\n\t\t\t\t? `type ${baseName} as ${alias}`\n\t\t\t\t: `${baseName} as ${alias}`;\n\t\t\tthis.imports.get(module)!.add(aliasedImport);\n\t\t\treturn alias;\n\t\t}\n\n\t\tthis.imports.get(module)!.add(name);\n\t\treturn baseName;\n\t}\n\n\taddStarImport(module: string, name: string) {\n\t\tconst importName = this.getUnusedName(name);\n\t\tthis.starImports.set(importName, module);\n\t\treturn importName;\n\t}\n\n\tgetUnusedName(name: string) {\n\t\tlet deConflictedName = getSafeName(name);\n\n\t\tlet i = 1;\n\t\twhile (this.reservedNames.has(deConflictedName)) {\n\t\t\tdeConflictedName = `${name}_${i}`;\n\t\t\ti++;\n\t\t}\n\n\t\tthis.reservedNames.add(deConflictedName);\n\t\treturn deConflictedName;\n\t}\n\n\tasync getHeader() {\n\t\treturn [\n\t\t\t'/**************************************************************',\n\t\t\t' * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *',\n\t\t\t' **************************************************************/',\n\t\t\t'',\n\t\t].join('\\n');\n\t}\n\n\tasync toString(modDir: string, filePath: string) {\n\t\tconst importStatements = [...this.imports.entries()].flatMap(\n\t\t\t([module, names]) =>\n\t\t\t\tparseTS`import { ${[...names].join(', ')} } from '${modulePath(module)}'`,\n\t\t);\n\t\tconst starImportStatements = [...this.starImports.entries()].flatMap(\n\t\t\t([name, module]) => parseTS`import * as ${name} from '${modulePath(module)}'`,\n\t\t);\n\n\t\treturn `${await this.getHeader()}${printNodes(...importStatements, ...starImportStatements, ...this.statements)}`;\n\n\t\tfunction modulePath(mod: string) {\n\t\t\tif (!mod.startsWith('~root/')) {\n\t\t\t\treturn mod;\n\t\t\t}\n\n\t\t\tconst sourcePath = resolve(modDir, filePath);\n\t\t\tconst destPath = resolve(modDir, mod.replace('~root/', './'));\n\t\t\tconst sourceDirectory = sourcePath.split('/').slice(0, -1).join('/');\n\t\t\tconst relativePath = relative(sourceDirectory, destPath);\n\t\t\treturn relativePath.startsWith('.') ? relativePath : `./${relativePath}`;\n\t\t}\n\t}\n}\n"],"mappings":";;;;;AAQA,IAAa,cAAb,MAAyB;;oBACK,EAAE;iBACX,EAAE;iCACc,IAAI,KAAK;qCACV,IAAI,KAAK;uCACL,IAAI,KAAK;;CAEhD,UAAU,QAAgB,MAAsB;AAC/C,MAAI,CAAC,KAAK,QAAQ,IAAI,OAAO,CAC5B,MAAK,QAAQ,IAAI,wBAAQ,IAAI,KAAK,CAAC;EAGpC,MAAM,eAAe,KAAK,WAAW,QAAQ;EAC7C,MAAM,WAAW,eAAe,KAAK,MAAM,EAAE,GAAG;AAEhD,MAAI,KAAK,cAAc,IAAI,SAAS,EAAE;GACrC,MAAM,QAAQ,KAAK,cAAc,SAAS;GAC1C,MAAM,gBAAgB,eACnB,QAAQ,SAAS,MAAM,UACvB,GAAG,SAAS,MAAM;AACrB,QAAK,QAAQ,IAAI,OAAO,CAAE,IAAI,cAAc;AAC5C,UAAO;;AAGR,OAAK,QAAQ,IAAI,OAAO,CAAE,IAAI,KAAK;AACnC,SAAO;;CAGR,cAAc,QAAgB,MAAc;EAC3C,MAAM,aAAa,KAAK,cAAc,KAAK;AAC3C,OAAK,YAAY,IAAI,YAAY,OAAO;AACxC,SAAO;;CAGR,cAAc,MAAc;EAC3B,IAAI,mBAAmB,YAAY,KAAK;EAExC,IAAI,IAAI;AACR,SAAO,KAAK,cAAc,IAAI,iBAAiB,EAAE;AAChD,sBAAmB,GAAG,KAAK,GAAG;AAC9B;;AAGD,OAAK,cAAc,IAAI,iBAAiB;AACxC,SAAO;;CAGR,MAAM,YAAY;AACjB,SAAO;GACN;GACA;GACA;GACA;GACA,CAAC,KAAK,KAAK;;CAGb,MAAM,SAAS,QAAgB,UAAkB;EAChD,MAAM,mBAAmB,CAAC,GAAG,KAAK,QAAQ,SAAS,CAAC,CAAC,SACnD,CAAC,QAAQ,WACT,OAAO,YAAY,CAAC,GAAG,MAAM,CAAC,KAAK,KAAK,CAAC,WAAW,WAAW,OAAO,CAAC,GACxE;EACD,MAAM,uBAAuB,CAAC,GAAG,KAAK,YAAY,SAAS,CAAC,CAAC,SAC3D,CAAC,MAAM,YAAY,OAAO,eAAe,KAAK,SAAS,WAAW,OAAO,CAAC,GAC3E;AAED,SAAO,GAAG,MAAM,KAAK,WAAW,GAAG,WAAW,GAAG,kBAAkB,GAAG,sBAAsB,GAAG,KAAK,WAAW;EAE/G,SAAS,WAAW,KAAa;AAChC,OAAI,CAAC,IAAI,WAAW,SAAS,CAC5B,QAAO;GAGR,MAAM,aAAa,QAAQ,QAAQ,SAAS;GAC5C,MAAM,WAAW,QAAQ,QAAQ,IAAI,QAAQ,UAAU,KAAK,CAAC;GAE7D,MAAM,eAAe,SADG,WAAW,MAAM,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,KAAK,IAAI,EACrB,SAAS;AACxD,UAAO,aAAa,WAAW,IAAI,GAAG,eAAe,KAAK"}
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;iBAmBsB,0BAAA,CAAA;EACrB,OAAA,EAAS,GAAA;EACT,KAAA;EACA,SAAA;EACA,cAAA;EACA,eAAA;EACA;AAAA;EAEA,OAAA,EAAS,aAAA;EACT,KAAA;EACA,SAAA;EACA,cAAA,GAAiB,YAAA;EACjB,eAAA,GAAkB,eAAA;EAClB,4BAAA;AAAA,IACA,OAAA"}
|
package/docs/index.md
ADDED
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
# Haneul TypeScript Codegen
|
|
2
|
+
|
|
3
|
+
> Generate type-safe TypeScript bindings from on-chain Haneul Move packages
|
|
4
|
+
|
|
5
|
+
The `@haneullabs/codegen` package automatically generates type-safe TypeScript code from your Move
|
|
6
|
+
packages, enabling seamless interaction with your smart contracts from TypeScript applications.
|
|
7
|
+
|
|
8
|
+
> **Warning:** This package is currently in development and may have breaking changes.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Type-safe Move calls**: Generate TypeScript functions with full type safety for calling your
|
|
13
|
+
Move functions
|
|
14
|
+
- **BCS type definitions**: Automatic BCS struct definitions for parsing on-chain data
|
|
15
|
+
- **Auto-completion**: IDE support with intelligent code completion for Move function arguments
|
|
16
|
+
- **Package resolution**: Support for both MVR-registered packages and local packages
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
Install the codegen package as a dev dependency:
|
|
21
|
+
|
|
22
|
+
```sh npm2yarn
|
|
23
|
+
npm install -D @haneullabs/codegen
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
### 1. Create a configuration file
|
|
29
|
+
|
|
30
|
+
Create a `haneul-codegen.config.ts` file in your project root:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
const config: HaneulCodegenConfig = {
|
|
34
|
+
output: './src/contracts',
|
|
35
|
+
packages: [
|
|
36
|
+
{
|
|
37
|
+
package: '@local-pkg/counter',
|
|
38
|
+
path: './move/counter',
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Generate TypeScript code
|
|
45
|
+
|
|
46
|
+
Add a script to your `package.json`:
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"scripts": {
|
|
51
|
+
"codegen": "haneul-ts-codegen generate"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Then run:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pnpm codegen
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
This generates TypeScript code in your configured output directory (e.g., `./src/contracts`).
|
|
63
|
+
|
|
64
|
+
## Configuration Options
|
|
65
|
+
|
|
66
|
+
The `HaneulCodegenConfig` type supports the following options:
|
|
67
|
+
|
|
68
|
+
| Option | Type | Default | Description |
|
|
69
|
+
| ------------------------------ | ---------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
70
|
+
| `output` | `string` | — | The directory where generated code will be written |
|
|
71
|
+
| `packages` | `PackageConfig[]` | — | Array of Move packages to generate code for |
|
|
72
|
+
| `prune` | `boolean` | `true` | When enabled, only generates code for the main package and omits dependency modules (dependency types referenced by included types are still generated under `deps/`) |
|
|
73
|
+
| `generateSummaries` | `boolean` | `true` | Automatically run `haneul move summary` before generating code. Creates a `package_summaries` directory in your Move package which can be added to `.gitignore` |
|
|
74
|
+
| `generate` | `GenerateOptions` | — | Default [generate options](#the-generate-option) (types, functions) for all packages |
|
|
75
|
+
| `importExtension` | `'.js' \| '.ts' \| ''` | `'.js'` | File extension used in generated import statements |
|
|
76
|
+
| `includePhantomTypeParameters` | `boolean` | `false` | Include [phantom type parameters](#phantom-types) as function arguments in generated BCS types |
|
|
77
|
+
|
|
78
|
+
### Package Configuration
|
|
79
|
+
|
|
80
|
+
Each entry in the `packages` array configures a Move package to generate code from. Packages can be
|
|
81
|
+
local (from source) or on-chain (fetched from a network).
|
|
82
|
+
|
|
83
|
+
#### Local Packages
|
|
84
|
+
|
|
85
|
+
| Option | Type | Required | Description |
|
|
86
|
+
| ------------- | ------------------------ | -------- | -------------------------------------------------- |
|
|
87
|
+
| `package` | `string` | yes | Package identifier (e.g., `@local-pkg/my-package`) |
|
|
88
|
+
| `path` | `string` | yes | Path to the Move package directory |
|
|
89
|
+
| `packageName` | `string` | no | Custom name for generated code directory |
|
|
90
|
+
| `generate` | `PackageGenerateOptions` | no | Control what gets generated from this package |
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
{
|
|
94
|
+
package: '@local-pkg/my-package',
|
|
95
|
+
path: './move/my-package',
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### On-Chain Packages
|
|
100
|
+
|
|
101
|
+
For packages already deployed on-chain, generate code directly from a package ID or MVR name without
|
|
102
|
+
needing local source code:
|
|
103
|
+
|
|
104
|
+
| Option | Type | Required | Description |
|
|
105
|
+
| ------------- | ------------------------ | -------- | --------------------------------------------- |
|
|
106
|
+
| `package` | `string` | yes | Package ID or MVR name |
|
|
107
|
+
| `packageName` | `string` | yes | Name for the generated code directory |
|
|
108
|
+
| `network` | `'mainnet' \| 'testnet'` | yes | Network to fetch the package from |
|
|
109
|
+
| `generate` | `PackageGenerateOptions` | no | Control what gets generated from this package |
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
{
|
|
113
|
+
package: '0xabf837e98c26087cba0883c0a7a28326b1fa3c5e1e2c5abdb486f9e8f594c837',
|
|
114
|
+
packageName: 'pyth',
|
|
115
|
+
network: 'testnet',
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## The `generate` option
|
|
120
|
+
|
|
121
|
+
The `generate` option controls what code is produced. It can be set at the global level (as a
|
|
122
|
+
default for all packages), at the per-package level, and at the per-module level. More specific
|
|
123
|
+
settings override less specific ones.
|
|
124
|
+
|
|
125
|
+
When no `generate` option is set, everything is generated (all types and functions). Package-level
|
|
126
|
+
`types` and `functions` also default to `true`. In the record form of `modules`, per-module `types`
|
|
127
|
+
and `functions` default to `false` — you opt in to exactly what you need from each module. Use
|
|
128
|
+
`true` as a shorthand to include everything from a module with package-level defaults.
|
|
129
|
+
|
|
130
|
+
At the **global** and **package** levels, `types` and `functions` only accept boolean values (or an
|
|
131
|
+
object for `functions`). Name-based filtering with `string[]` is only available at the **module**
|
|
132
|
+
level inside the record form of `modules`, where the filter applies unambiguously to a single
|
|
133
|
+
module.
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
// Global or package level
|
|
137
|
+
generate: {
|
|
138
|
+
types: true | false,
|
|
139
|
+
functions: true | false | { private: boolean | 'entry' },
|
|
140
|
+
modules: string[] | Record<string, true | { types?, functions? }>, // package-level only
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Module level (inside the record form of modules)
|
|
144
|
+
modules: {
|
|
145
|
+
my_module: true, // shorthand for "include everything"
|
|
146
|
+
other_module: {
|
|
147
|
+
types: true | false | string[],
|
|
148
|
+
functions: true | false | string[] | { private: boolean | 'entry' },
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Types
|
|
154
|
+
|
|
155
|
+
Controls which BCS type definitions (structs and enums) are generated:
|
|
156
|
+
|
|
157
|
+
- `true` — generate all types
|
|
158
|
+
- `false` — skip type generation
|
|
159
|
+
- `string[]` — generate only the listed types by name _(module level only)_
|
|
160
|
+
|
|
161
|
+
### Functions
|
|
162
|
+
|
|
163
|
+
Controls which Move function wrappers are generated:
|
|
164
|
+
|
|
165
|
+
- `true` — generate all public functions and private entry functions
|
|
166
|
+
- `false` — skip function generation
|
|
167
|
+
- `string[]` — generate only the listed functions by name; includes private functions _(module level
|
|
168
|
+
only)_
|
|
169
|
+
- `{ private: 'entry' }` — generate public functions plus private entry functions
|
|
170
|
+
- `{ private: true }` — generate all functions including private
|
|
171
|
+
- `{ private: false }` — only generate public functions
|
|
172
|
+
|
|
173
|
+
### Modules
|
|
174
|
+
|
|
175
|
+
Controls which modules from the package are included. Only available at the package level, not at
|
|
176
|
+
the global level.
|
|
177
|
+
|
|
178
|
+
- Not set (default) — include all modules
|
|
179
|
+
- `string[]` — only include the listed modules
|
|
180
|
+
- `Record<string, true | { types?, functions? }>` — only include the listed modules, with per-module
|
|
181
|
+
overrides for `types` and `functions`. Use `true` as a shorthand to include everything from a
|
|
182
|
+
module with package-level defaults
|
|
183
|
+
|
|
184
|
+
### Examples
|
|
185
|
+
|
|
186
|
+
Only generate code from specific modules of the Haneul framework:
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
{
|
|
190
|
+
package: '0x0000000000000000000000000000000000000000000000000000000000000002',
|
|
191
|
+
packageName: '0x2',
|
|
192
|
+
network: 'testnet',
|
|
193
|
+
generate: {
|
|
194
|
+
modules: ['kiosk', 'kiosk_extension', 'transfer_policy'],
|
|
195
|
+
},
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Only generate a single type from a dependency (functions are omitted automatically since `generate`
|
|
200
|
+
is configured and `functions` is not specified):
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
{
|
|
204
|
+
package: '0xabf837e98c26087cba0883c0a7a28326b1fa3c5e1e2c5abdb486f9e8f594c837',
|
|
205
|
+
packageName: 'pyth',
|
|
206
|
+
network: 'testnet',
|
|
207
|
+
generate: {
|
|
208
|
+
modules: {
|
|
209
|
+
state: { types: ['State'] },
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Generate specific types and functions from individual modules:
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
{
|
|
219
|
+
package: '@local-pkg/my-package',
|
|
220
|
+
path: './move/my-package',
|
|
221
|
+
generate: {
|
|
222
|
+
modules: {
|
|
223
|
+
token: {
|
|
224
|
+
types: ['Token', 'TokenMetadata'],
|
|
225
|
+
functions: ['mint', 'burn', 'transfer'],
|
|
226
|
+
},
|
|
227
|
+
admin: {
|
|
228
|
+
types: true,
|
|
229
|
+
functions: ['initialize'],
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Generate all types but include all private functions for a local package:
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
{
|
|
240
|
+
package: '@local-pkg/my-package',
|
|
241
|
+
path: './move/my-package',
|
|
242
|
+
generate: {
|
|
243
|
+
functions: { private: true },
|
|
244
|
+
},
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Dependency pruning
|
|
249
|
+
|
|
250
|
+
The global `prune` option (default: `true`) controls whether dependency packages are included in the
|
|
251
|
+
output. Even when pruning is enabled, dependency types referenced by your included types are still
|
|
252
|
+
generated under `deps/`:
|
|
253
|
+
|
|
254
|
+
```
|
|
255
|
+
src/contracts/
|
|
256
|
+
├── mypackage/
|
|
257
|
+
│ ├── module_a.ts
|
|
258
|
+
│ ├── module_b.ts
|
|
259
|
+
│ └── deps/
|
|
260
|
+
│ └── 0x2/
|
|
261
|
+
│ └── balance.ts # Auto-included dependency type
|
|
262
|
+
└── utils/
|
|
263
|
+
└── index.ts # Shared utilities (always generated)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Set `prune: false` to generate all dependency modules with their full types and functions.
|
|
267
|
+
|
|
268
|
+
## Phantom Types
|
|
269
|
+
|
|
270
|
+
In Move, phantom type parameters are type parameters that only appear at the type level and don't
|
|
271
|
+
affect the runtime data layout of a struct. For example, `Balance<T>` has a phantom type parameter
|
|
272
|
+
`T` that indicates the coin type, but the actual serialized data only contains a `u64` value:
|
|
273
|
+
|
|
274
|
+
```move
|
|
275
|
+
public struct Balance<phantom T> has store {
|
|
276
|
+
value: u64,
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Default Behavior
|
|
281
|
+
|
|
282
|
+
By default, codegen excludes phantom type parameters from the generated BCS type functions since
|
|
283
|
+
they don't affect serialization. The generated type is a constant rather than a function:
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
|
|
287
|
+
name: `${$moduleName}::Balance<phantom T>`,
|
|
288
|
+
fields: {
|
|
289
|
+
value: bcs.u64(),
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
This works correctly for parsing on-chain data because phantom types don't change the binary layout.
|
|
295
|
+
|
|
296
|
+
> **Note:** With the default behavior, phantom parameters appear as literals in the type name (e.g.,
|
|
297
|
+
> `Balance<phantom T>`). These names are useful for debugging but are not valid on-chain type tags.
|
|
298
|
+
> If you need valid type names with resolved phantom parameters, enable
|
|
299
|
+
> `includePhantomTypeParameters`.
|
|
300
|
+
|
|
301
|
+
### Including Phantom Type Parameters
|
|
302
|
+
|
|
303
|
+
If you need the phantom type parameters as function arguments (for example, to preserve type
|
|
304
|
+
information for other tooling), enable `includePhantomTypeParameters`:
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
const config: HaneulCodegenConfig = {
|
|
308
|
+
output: './src/contracts',
|
|
309
|
+
includePhantomTypeParameters: true,
|
|
310
|
+
packages: [
|
|
311
|
+
// ...
|
|
312
|
+
],
|
|
313
|
+
};
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
With this option enabled, phantom type parameters become function arguments:
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
|
|
320
|
+
return new MoveStruct({
|
|
321
|
+
name: `${$moduleName}::Balance<${T.name}>` as const,
|
|
322
|
+
fields: {
|
|
323
|
+
value: bcs.u64(),
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## Using Generated Code
|
|
330
|
+
|
|
331
|
+
### Calling Move Functions
|
|
332
|
+
|
|
333
|
+
The generated code provides type-safe functions for calling Move functions:
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
// Increment a counter
|
|
337
|
+
const tx = new Transaction();
|
|
338
|
+
tx.add(
|
|
339
|
+
counter.increment({
|
|
340
|
+
arguments: {
|
|
341
|
+
counter: '0x123...', // Counter object ID
|
|
342
|
+
},
|
|
343
|
+
}),
|
|
344
|
+
);
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Parsing BCS Data
|
|
348
|
+
|
|
349
|
+
Use generated BCS types to parse on-chain object data. Fetch the object with
|
|
350
|
+
`include: { content: true }` and pass `object.content` to the generated type's `.parse()` method:
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
async function readCounter(client: ClientWithCoreApi, id: string) {
|
|
354
|
+
const { object } = await client.core.getObject({
|
|
355
|
+
objectId: id,
|
|
356
|
+
include: { content: true },
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
// Parse the Move struct fields from BCS content
|
|
360
|
+
const parsed = CounterStruct.parse(object.content);
|
|
361
|
+
console.log('Counter value:', parsed.value);
|
|
362
|
+
console.log('Counter owner:', parsed.owner);
|
|
363
|
+
|
|
364
|
+
return parsed;
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
> **Warning:** Always use `content`, not `objectBcs`, when parsing with generated types. The
|
|
369
|
+
> `objectBcs` field contains a full object envelope with additional metadata that will cause parsing
|
|
370
|
+
> to fail. See the [Core API docs](/haneul/clients/core#objectbcs) for details.
|
|
371
|
+
|
|
372
|
+
## Client Configuration
|
|
373
|
+
|
|
374
|
+
### Using with MVR (Move Version Registry)
|
|
375
|
+
|
|
376
|
+
If your package is registered on MVR, the generated code works without additional configuration.
|
|
377
|
+
|
|
378
|
+
### Local Packages
|
|
379
|
+
|
|
380
|
+
For local packages using `@local-pkg/*` identifiers, configure your client with package overrides:
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
const client = new HaneulGrpcClient({
|
|
384
|
+
network: 'testnet',
|
|
385
|
+
baseUrl: 'https://fullnode.testnet.haneul.io:443',
|
|
386
|
+
mvr: {
|
|
387
|
+
overrides: {
|
|
388
|
+
packages: {
|
|
389
|
+
'@local-pkg/counter': '0xYOUR_PACKAGE_ID',
|
|
390
|
+
},
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
});
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### With dApp Kit
|
|
397
|
+
|
|
398
|
+
Configure package overrides when creating your dApp Kit instance:
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
const GRPC_URLS = {
|
|
402
|
+
testnet: 'https://fullnode.testnet.haneul.io:443',
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
const PACKAGE_IDS = {
|
|
406
|
+
testnet: {
|
|
407
|
+
counter: '0xYOUR_PACKAGE_ID',
|
|
408
|
+
},
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
const dAppKit = createDAppKit({
|
|
412
|
+
networks: ['testnet'],
|
|
413
|
+
createClient: (network) => {
|
|
414
|
+
return new HaneulGrpcClient({
|
|
415
|
+
network,
|
|
416
|
+
baseUrl: GRPC_URLS[network],
|
|
417
|
+
mvr: {
|
|
418
|
+
overrides: {
|
|
419
|
+
packages: {
|
|
420
|
+
'@local-pkg/counter': PACKAGE_IDS[network].counter,
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
},
|
|
424
|
+
});
|
|
425
|
+
},
|
|
426
|
+
});
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## Related Resources
|
|
430
|
+
|
|
431
|
+
- [create-dapp](/dapp-kit/getting-started/create-dapp) - Bootstrap a working dApp with codegen
|
|
432
|
+
already configured
|
|
433
|
+
- [Haneul Move documentation](https://docs.haneul.io/concepts/haneul-move-concepts)
|
|
434
|
+
- [BCS documentation](/bcs)
|
|
435
|
+
- [Transaction building](/haneul/transaction-building/basics)
|
|
436
|
+
- [dApp Kit](/dapp-kit)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haneullabs/codegen",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "typescript codegen for haneul move",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Haneul Labs <build@haneul-labs.com>",
|
|
@@ -18,11 +18,12 @@
|
|
|
18
18
|
"files": [
|
|
19
19
|
"CHANGELOG.md",
|
|
20
20
|
"dist",
|
|
21
|
+
"docs",
|
|
21
22
|
"src"
|
|
22
23
|
],
|
|
23
24
|
"bin": {
|
|
24
25
|
"haneul-ts-codegen": "dist/bin/cli.mjs",
|
|
25
|
-
"
|
|
26
|
+
"__haneul-ts-codegen_bash_complete": "dist/bin/bash-complete.mjs"
|
|
26
27
|
},
|
|
27
28
|
"repository": {
|
|
28
29
|
"type": "git",
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
"haneul"
|
|
35
36
|
],
|
|
36
37
|
"bugs": {
|
|
37
|
-
"url": "https://github.com/
|
|
38
|
+
"url": "https://github.com/GeunhwaJeong/ts-sdks/issues"
|
|
38
39
|
},
|
|
39
40
|
"homepage": "https://github.com/GeunhwaJeong/ts-sdks/blob/main/packages/codegen#readme",
|
|
40
41
|
"devDependencies": {
|
|
@@ -49,13 +50,14 @@
|
|
|
49
50
|
"toml": "^3.0.0",
|
|
50
51
|
"typescript": "^5.9.3",
|
|
51
52
|
"zod": "^4.3.5",
|
|
52
|
-
"@haneullabs/bcs": "^2.0.
|
|
53
|
-
"@haneullabs/haneul": "^2.
|
|
53
|
+
"@haneullabs/bcs": "^2.0.3",
|
|
54
|
+
"@haneullabs/haneul": "^2.13.0"
|
|
54
55
|
},
|
|
55
56
|
"scripts": {
|
|
56
57
|
"clean": "rm -rf tsconfig.tsbuildinfo ./dist",
|
|
57
58
|
"dev": "pnpm build --watch",
|
|
58
59
|
"build": "rm -rf dist && tsc --noEmit && tsdown",
|
|
60
|
+
"build:docs": "tsx ../docs/scripts/build-docs.ts",
|
|
59
61
|
"codegen": "pnpm tsx src/bin/cli.ts generate && pnpm lint:fix",
|
|
60
62
|
"test": "vitest run",
|
|
61
63
|
"test:watch": "vitest",
|
package/src/config.ts
CHANGED
|
@@ -82,9 +82,9 @@ export const configSchema = z.object({
|
|
|
82
82
|
|
|
83
83
|
export type PackageConfig = z.infer<typeof packageConfigSchema>;
|
|
84
84
|
export type HaneulCodegenConfig = z.input<typeof configSchema>;
|
|
85
|
-
export type
|
|
85
|
+
export type ParsedHaneulCodegenConfig = z.infer<typeof configSchema>;
|
|
86
86
|
|
|
87
|
-
export async function loadConfig(): Promise<
|
|
87
|
+
export async function loadConfig(): Promise<ParsedHaneulCodegenConfig> {
|
|
88
88
|
const config = await cosmiconfig('haneul-codegen').search();
|
|
89
89
|
|
|
90
90
|
if (!config) {
|