@ic-reactor/codegen 0.4.0 → 0.5.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.
package/src/bindgen.ts DELETED
@@ -1,101 +0,0 @@
1
- /**
2
- * Bindgen utilities
3
- *
4
- * Generates TypeScript declarations from Candid files using @ic-reactor/parser.
5
- */
6
-
7
- import { didToJs, didToTs } from "@ic-reactor/parser"
8
- import path from "node:path"
9
- import fs from "node:fs"
10
-
11
- export interface BindgenOptions {
12
- /** Path to the .did file */
13
- didFile: string
14
- /** Output directory for generated declarations */
15
- outDir: string
16
- /** Canister name (used for naming) */
17
- canisterName: string
18
- }
19
-
20
- export interface BindgenResult {
21
- success: boolean
22
- declarationsDir: string
23
- error?: string
24
- }
25
-
26
- /**
27
- * Generate TypeScript declarations from a Candid file
28
- *
29
- * This creates:
30
- * - declarations/<canisterName>.js - IDL factory
31
- * - declarations/<canisterName>.d.ts - Types
32
- */
33
- export async function generateDeclarations(
34
- options: BindgenOptions
35
- ): Promise<BindgenResult> {
36
- const { didFile, outDir } = options
37
-
38
- // Ensure the .did file exists
39
- if (!fs.existsSync(didFile)) {
40
- return {
41
- success: false,
42
- declarationsDir: "",
43
- error: `DID file not found: ${didFile}`,
44
- }
45
- }
46
-
47
- const declarationsDir = path.join(outDir, "declarations")
48
- const didFileName = path.basename(didFile) // e.g., "my_canister.did"
49
-
50
- try {
51
- // Read content first so we can safely delete the directory if didFile is inside it
52
- const didContent = fs.readFileSync(didFile, "utf-8")
53
-
54
- // Ensure the output directory exists
55
- if (!fs.existsSync(outDir)) {
56
- fs.mkdirSync(outDir, { recursive: true })
57
- }
58
-
59
- // Clean existing declarations before regenerating
60
- if (fs.existsSync(declarationsDir)) {
61
- fs.rmSync(declarationsDir, { recursive: true, force: true })
62
- }
63
- fs.mkdirSync(declarationsDir, { recursive: true })
64
-
65
- const jsContent = didToJs(didContent)
66
- const tsContent = didToTs(didContent)
67
-
68
- // Write .did, .js and .d.ts
69
- const baseName = didFileName.replace(/\.did$/, "")
70
- const jsPath = path.join(declarationsDir, baseName + ".js")
71
- const dtsPath = path.join(declarationsDir, baseName + ".d.ts")
72
- const didPath = path.join(declarationsDir, didFileName)
73
-
74
- fs.writeFileSync(jsPath, jsContent)
75
- fs.writeFileSync(dtsPath, tsContent)
76
- fs.writeFileSync(didPath, didContent)
77
-
78
- return {
79
- success: true,
80
- declarationsDir,
81
- }
82
- } catch (error) {
83
- return {
84
- success: false,
85
- declarationsDir,
86
- error: error instanceof Error ? error.message : String(error),
87
- }
88
- }
89
- }
90
-
91
- /**
92
- * Check if declarations already exist for a canister
93
- */
94
- export function declarationsExist(
95
- outDir: string,
96
- canisterName: string
97
- ): boolean {
98
- const declarationsDir = path.join(outDir, "declarations")
99
- const didTsPath = path.join(declarationsDir, `${canisterName}.d.ts`)
100
- return fs.existsSync(didTsPath)
101
- }
@@ -1,35 +0,0 @@
1
- // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
-
3
- exports[`Client File Generation > generates correctly with custom query client 1`] = `
4
- "import { ClientManager } from "@ic-reactor/react"
5
- import { queryClient } from "../query-client"
6
-
7
- /**
8
- * IC Reactor Client Manager
9
- *
10
- * Auto-generated by @ic-reactor/codegen
11
- */
12
- export const clientManager = new ClientManager({
13
- queryClient,
14
- withCanisterEnv: true,
15
- })
16
- "
17
- `;
18
-
19
- exports[`Client File Generation > generates correctly with default host 1`] = `
20
- "import { ClientManager } from "@ic-reactor/react"
21
- import { QueryClient } from "@tanstack/react-query"
22
-
23
- export const queryClient = new QueryClient()
24
-
25
- /**
26
- * IC Reactor Client Manager
27
- *
28
- * Auto-generated by @ic-reactor/codegen
29
- */
30
- export const clientManager = new ClientManager({
31
- queryClient,
32
- withCanisterEnv: true,
33
- })
34
- "
35
- `;
@@ -1,28 +0,0 @@
1
- // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
-
3
- exports[`Reactor File Generation > Standard Mode > generates correctly 1`] = `
4
- "import { DisplayReactor, createActorHooks } from "@ic-reactor/react"
5
- import { clientManager } from "../../client"
6
- import { idlFactory, type _SERVICE } from "./declarations/my_canister"
7
-
8
- export type MyCanisterService = _SERVICE
9
-
10
- /**
11
- * MyCanister Display Reactor
12
- */
13
- export const myCanisterReactor = new DisplayReactor<MyCanisterService>({
14
- clientManager,
15
- idlFactory,
16
- name: "my_canister",
17
- })
18
-
19
- export const {
20
- useActorQuery: useMyCanisterQuery,
21
- useActorSuspenseQuery: useMyCanisterSuspenseQuery,
22
- useActorInfiniteQuery: useMyCanisterInfiniteQuery,
23
- useActorSuspenseInfiniteQuery: useMyCanisterSuspenseInfiniteQuery,
24
- useActorMutation: useMyCanisterMutation,
25
- useActorMethod: useMyCanisterMethod,
26
- } = createActorHooks(myCanisterReactor)
27
- "
28
- `;
@@ -1,20 +0,0 @@
1
- import { describe, it, expect } from "vitest"
2
- import { generateClientFile } from "./client"
3
-
4
- describe("Client File Generation", () => {
5
- it("generates correctly with default host", () => {
6
- const result = generateClientFile()
7
- expect(result).toMatchSnapshot()
8
- expect(result).toContain(
9
- 'import { QueryClient } from "@tanstack/react-query'
10
- )
11
- })
12
-
13
- it("generates correctly with custom query client", () => {
14
- const result = generateClientFile({
15
- queryClientPath: "../query-client",
16
- })
17
- expect(result).toMatchSnapshot()
18
- expect(result).toContain('import { queryClient } from "../query-client"')
19
- })
20
- })
@@ -1,37 +0,0 @@
1
- /**
2
- * Client Manager Generator
3
- */
4
-
5
- export interface ClientGeneratorOptions {
6
- /** Optional path to an existing queryClient */
7
- queryClientPath?: string
8
- }
9
-
10
- /**
11
- * Generate a central client manager file
12
- */
13
- export function generateClientFile(
14
- options: ClientGeneratorOptions = {}
15
- ): string {
16
- const { queryClientPath } = options
17
-
18
- return `import { ClientManager } from "@ic-reactor/react"
19
- ${
20
- queryClientPath
21
- ? `import { queryClient } from "${queryClientPath}"`
22
- : `import { QueryClient } from "@tanstack/react-query"
23
-
24
- export const queryClient = new QueryClient()`
25
- }
26
-
27
- /**
28
- * IC Reactor Client Manager
29
- *
30
- * Auto-generated by @ic-reactor/codegen
31
- */
32
- export const clientManager = new ClientManager({
33
- queryClient,
34
- withCanisterEnv: true,
35
- })
36
- `
37
- }
@@ -1,23 +0,0 @@
1
- import { describe, it, expect } from "vitest"
2
- import { generateReactorFile, type ReactorGeneratorOptions } from "./reactor"
3
-
4
- describe("Reactor File Generation", () => {
5
- const baseOptions: ReactorGeneratorOptions = {
6
- canisterName: "my_canister",
7
- didFile: "path/to/my_canister.did",
8
- clientManagerPath: "../../client",
9
- }
10
-
11
- describe("Standard Mode", () => {
12
- it("generates correctly", () => {
13
- const result = generateReactorFile(baseOptions)
14
- expect(result).toMatchSnapshot()
15
- })
16
-
17
- it("uses default client path if not provided", () => {
18
- const options = { ...baseOptions, canisterConfig: { didFile: "foo.did" } }
19
- const result = generateReactorFile(options)
20
- expect(result).toContain('import { clientManager } from "../../client"')
21
- })
22
- })
23
- })
@@ -1,99 +0,0 @@
1
- /**
2
- * Reactor file template generator
3
- *
4
- * Generates the reactor instance file for a canister using DisplayReactor.
5
- * Standardizes the output to include typed hooks and clean imports.
6
- */
7
-
8
- import path from "node:path"
9
- import { toPascalCase, getReactorName, getServiceTypeName } from "../naming.js"
10
-
11
- export type ReactorGeneratorOptions = {
12
- canisterName: string
13
- didFile: string
14
- clientManagerPath?: string
15
- }
16
-
17
- /**
18
- * Generate the reactor file content
19
- */
20
- export function generateReactorFile(options: ReactorGeneratorOptions): string {
21
- const pascalName = toPascalCase(options.canisterName)
22
- const reactorName = getReactorName(options.canisterName)
23
- const serviceName = getServiceTypeName(options.canisterName)
24
- // Always use DisplayReactor for now
25
- const reactorType = "DisplayReactor"
26
-
27
- const didFileName = path.basename(options.didFile)
28
- const baseName = didFileName.replace(/\.did$/, "")
29
- const declarationsPath = `./declarations/${baseName}`
30
- const clientManagerPath = options.clientManagerPath ?? "../../clients"
31
-
32
- const vars: TemplateVars = {
33
- canisterName: options.canisterName,
34
- pascalName,
35
- reactorName,
36
- serviceName,
37
- reactorType,
38
- clientManagerPath,
39
- declarationsPath,
40
- }
41
-
42
- // If we have DID content, we can generate method-specific hooks (clean & typed)
43
- return generateStandardReactorFile(vars)
44
- }
45
-
46
- // ═══════════════════════════════════════════════════════════════════════════
47
- // SHARED TYPES
48
- // ═══════════════════════════════════════════════════════════════════════════
49
-
50
- interface TemplateVars {
51
- canisterName: string
52
- pascalName: string
53
- reactorName: string
54
- serviceName: string
55
- reactorType: string
56
- clientManagerPath: string
57
- declarationsPath: string
58
- }
59
-
60
- // ═══════════════════════════════════════════════════════════════════════════
61
- // STANDARD MODE
62
- // ═══════════════════════════════════════════════════════════════════════════
63
-
64
- function generateStandardReactorFile(vars: TemplateVars): string {
65
- const {
66
- pascalName,
67
- reactorName,
68
- serviceName,
69
- reactorType,
70
- clientManagerPath,
71
- declarationsPath,
72
- canisterName,
73
- } = vars
74
-
75
- return `import { ${reactorType}, createActorHooks } from "@ic-reactor/react"
76
- import { clientManager } from "${clientManagerPath}"
77
- import { idlFactory, type _SERVICE } from "${declarationsPath}"
78
-
79
- export type ${serviceName} = _SERVICE
80
-
81
- /**
82
- * ${pascalName} Display Reactor
83
- */
84
- export const ${reactorName} = new ${reactorType}<${serviceName}>({
85
- clientManager,
86
- idlFactory,
87
- name: "${canisterName}",
88
- })
89
-
90
- export const {
91
- useActorQuery: use${pascalName}Query,
92
- useActorSuspenseQuery: use${pascalName}SuspenseQuery,
93
- useActorInfiniteQuery: use${pascalName}InfiniteQuery,
94
- useActorSuspenseInfiniteQuery: use${pascalName}SuspenseInfiniteQuery,
95
- useActorMutation: use${pascalName}Mutation,
96
- useActorMethod: use${pascalName}Method,
97
- } = createActorHooks(${reactorName})
98
- `
99
- }