@ic-reactor/codegen 0.6.0 → 0.7.1
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/README.md +1 -60
- package/dist/index.cjs +12 -78
- package/dist/index.d.cts +4 -30
- package/dist/index.d.ts +4 -30
- package/dist/index.js +12 -77
- package/package.json +1 -1
- package/src/generators/index.ts +1 -1
- package/src/generators/reactor.ts +8 -57
- package/src/index.ts +1 -7
- package/src/pipeline.ts +9 -63
- package/src/types.ts +0 -17
- package/src/__snapshots__/reactor.test.ts.snap +0 -100
- package/src/pipeline.test.ts +0 -178
- package/src/reactor.test.ts +0 -42
package/README.md
CHANGED
|
@@ -23,75 +23,16 @@ await runCanisterPipeline({
|
|
|
23
23
|
globalConfig: {
|
|
24
24
|
outDir: "src/declarations",
|
|
25
25
|
clientManagerPath: "../../clients",
|
|
26
|
-
reactor: {
|
|
27
|
-
defaultMode: "display",
|
|
28
|
-
canisters: {
|
|
29
|
-
workflow_engine: "raw",
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
26
|
},
|
|
33
27
|
})
|
|
34
28
|
```
|
|
35
29
|
|
|
36
|
-
## Reactor Mode Configuration
|
|
37
|
-
|
|
38
|
-
`reactor.defaultMode` controls whether generated default hook exports use:
|
|
39
|
-
|
|
40
|
-
- `display` → `DisplayReactor` (current/default behavior)
|
|
41
|
-
- `raw` → `Reactor` (raw Candid shapes)
|
|
42
|
-
|
|
43
|
-
`reactor.canisters` lets you override specific canisters without editing generated files.
|
|
44
|
-
|
|
45
|
-
## Generated File Layout (Stable Wrapper)
|
|
46
|
-
|
|
47
|
-
Each canister now generates:
|
|
48
|
-
|
|
49
|
-
- `index.generated.ts` (regenerated on every run)
|
|
50
|
-
- `index.ts` (created only if missing; not overwritten)
|
|
51
|
-
|
|
52
|
-
The stable wrapper defaults to:
|
|
53
|
-
|
|
54
|
-
```ts
|
|
55
|
-
export * from "./index.generated"
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
This lets applications customize exports once and keep them across regenerations.
|
|
59
|
-
|
|
60
|
-
## Generated Output Examples
|
|
61
|
-
|
|
62
|
-
Display default:
|
|
63
|
-
|
|
64
|
-
```ts
|
|
65
|
-
export function createBackendRawReactor() {
|
|
66
|
-
/* ... */
|
|
67
|
-
}
|
|
68
|
-
export function createBackendDisplayReactor() {
|
|
69
|
-
/* ... */
|
|
70
|
-
}
|
|
71
|
-
export const backendReactor = createBackendDisplayReactor()
|
|
72
|
-
export const BackendReactorMode = "display" as const
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
Raw default:
|
|
76
|
-
|
|
77
|
-
```ts
|
|
78
|
-
export function createWorkflowEngineRawReactor() {
|
|
79
|
-
/* ... */
|
|
80
|
-
}
|
|
81
|
-
export function createWorkflowEngineDisplayReactor() {
|
|
82
|
-
/* ... */
|
|
83
|
-
}
|
|
84
|
-
export const workflowEngineReactor = createWorkflowEngineRawReactor()
|
|
85
|
-
export const WorkflowEngineReactorMode = "raw" as const
|
|
86
|
-
```
|
|
87
|
-
|
|
88
30
|
## Generators
|
|
89
31
|
|
|
90
32
|
You can also use individual generators if you need more granular control:
|
|
91
33
|
|
|
92
34
|
- **`generateDeclarations`**: Generates `.js` (factory), `.d.ts` (types), and `.did` copy.
|
|
93
|
-
- **`generateReactorFile`**: Generates the `index.
|
|
94
|
-
- **`generateReactorWrapperFile`**: Generates the stable `index.ts` wrapper (create-once, preserve-on-regenerate).
|
|
35
|
+
- **`generateReactorFile`**: Generates the `index.ts` file with `DisplayReactor` and hooks.
|
|
95
36
|
- **`generateClientFile`**: Generates a `ClientManager` boilerplate file.
|
|
96
37
|
|
|
97
38
|
## Utilities
|
package/dist/index.cjs
CHANGED
|
@@ -35,7 +35,6 @@ __export(index_exports, {
|
|
|
35
35
|
generateClientFile: () => generateClientFile,
|
|
36
36
|
generateDeclarations: () => generateDeclarations,
|
|
37
37
|
generateReactorFile: () => generateReactorFile,
|
|
38
|
-
generateReactorWrapperFile: () => generateReactorWrapperFile,
|
|
39
38
|
getReactorName: () => getReactorName,
|
|
40
39
|
getServiceTypeName: () => getServiceTypeName,
|
|
41
40
|
parseDIDFile: () => parseDIDFile,
|
|
@@ -125,21 +124,13 @@ function getServiceTypeName(canisterName) {
|
|
|
125
124
|
|
|
126
125
|
// src/generators/reactor.ts
|
|
127
126
|
function generateReactorFile(options) {
|
|
128
|
-
const {
|
|
129
|
-
canisterName,
|
|
130
|
-
didFile,
|
|
131
|
-
clientManagerPath = "../../clients",
|
|
132
|
-
reactorMode = "display"
|
|
133
|
-
} = options;
|
|
127
|
+
const { canisterName, didFile, clientManagerPath = "../../clients" } = options;
|
|
134
128
|
const pascalName = toPascalCase(canisterName);
|
|
135
129
|
const reactorName = getReactorName(canisterName);
|
|
136
130
|
const serviceName = getServiceTypeName(canisterName);
|
|
137
|
-
const rawFactoryName = `create${pascalName}RawReactor`;
|
|
138
|
-
const displayFactoryName = `create${pascalName}DisplayReactor`;
|
|
139
|
-
const defaultFactoryName = reactorMode === "raw" ? rawFactoryName : displayFactoryName;
|
|
140
131
|
const baseName = import_node_path2.default.basename(didFile, ".did");
|
|
141
132
|
const declarationsPath = `./declarations/${baseName}`;
|
|
142
|
-
return `import { DisplayReactor,
|
|
133
|
+
return `import { DisplayReactor, createActorHooks } from "@ic-reactor/react"
|
|
143
134
|
import { clientManager } from "${clientManagerPath}"
|
|
144
135
|
import { idlFactory, type _SERVICE } from "${declarationsPath}"
|
|
145
136
|
|
|
@@ -151,25 +142,11 @@ export type ${serviceName} = _SERVICE
|
|
|
151
142
|
* Auto-generated by @ic-reactor/codegen \u2014 do not edit.
|
|
152
143
|
* Re-run \`ic-reactor generate\` (or the Vite plugin) to regenerate.
|
|
153
144
|
*/
|
|
154
|
-
export
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
})
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export function ${displayFactoryName}() {
|
|
163
|
-
return new DisplayReactor<${serviceName}>({
|
|
164
|
-
clientManager,
|
|
165
|
-
idlFactory,
|
|
166
|
-
name: "${canisterName}",
|
|
167
|
-
})
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
export const ${reactorName} = ${defaultFactoryName}()
|
|
171
|
-
|
|
172
|
-
export const ${pascalName}ReactorMode = "${reactorMode}" as const
|
|
145
|
+
export const ${reactorName} = new DisplayReactor<${serviceName}>({
|
|
146
|
+
clientManager,
|
|
147
|
+
idlFactory,
|
|
148
|
+
name: "${canisterName}",
|
|
149
|
+
})
|
|
173
150
|
|
|
174
151
|
export const {
|
|
175
152
|
useActorQuery: use${pascalName}Query,
|
|
@@ -181,29 +158,8 @@ export const {
|
|
|
181
158
|
} = createActorHooks(${reactorName})
|
|
182
159
|
`;
|
|
183
160
|
}
|
|
184
|
-
function generateReactorWrapperFile(options) {
|
|
185
|
-
const { canisterName } = options;
|
|
186
|
-
const pascalName = toPascalCase(canisterName);
|
|
187
|
-
return `/**
|
|
188
|
-
* ${pascalName} canister exports
|
|
189
|
-
*
|
|
190
|
-
* This wrapper is created once by @ic-reactor/codegen and is not overwritten.
|
|
191
|
-
* Customize it if you need to swap reactor implementations or compose custom exports.
|
|
192
|
-
*/
|
|
193
|
-
export * from "./index.generated"
|
|
194
|
-
`;
|
|
195
|
-
}
|
|
196
161
|
|
|
197
162
|
// src/pipeline.ts
|
|
198
|
-
function resolveReactorMode(canisterName, globalConfig) {
|
|
199
|
-
return globalConfig.reactor?.canisters?.[canisterName] ?? globalConfig.reactor?.defaultMode ?? "display";
|
|
200
|
-
}
|
|
201
|
-
function isStableWrapperFile(content) {
|
|
202
|
-
return content.includes('export * from "./index.generated"');
|
|
203
|
-
}
|
|
204
|
-
function isLegacyGeneratedIndexFile(content) {
|
|
205
|
-
return content.includes("Auto-generated by @ic-reactor/codegen") && content.includes("createActorHooks(") && !isStableWrapperFile(content);
|
|
206
|
-
}
|
|
207
163
|
async function runCanisterPipeline(options) {
|
|
208
164
|
const { canisterConfig, projectRoot, globalConfig } = options;
|
|
209
165
|
const { name, didFile, clientManagerPath } = canisterConfig;
|
|
@@ -242,41 +198,20 @@ async function runCanisterPipeline(options) {
|
|
|
242
198
|
error: `Declarations step failed: ${err instanceof Error ? err.message : String(err)}`
|
|
243
199
|
};
|
|
244
200
|
}
|
|
245
|
-
const
|
|
246
|
-
const wrapperPath = import_node_path3.default.join(canisterOutDir, "index.ts");
|
|
247
|
-
const reactorMode = resolveReactorMode(name, globalConfig);
|
|
201
|
+
const reactorPath = import_node_path3.default.join(canisterOutDir, "index.ts");
|
|
248
202
|
try {
|
|
249
203
|
const reactorContent = generateReactorFile({
|
|
250
204
|
canisterName: name,
|
|
251
205
|
didFile: resolvedDidFile,
|
|
252
|
-
clientManagerPath: resolvedClientManagerPath
|
|
253
|
-
reactorMode
|
|
254
|
-
});
|
|
255
|
-
const wrapperContent = generateReactorWrapperFile({
|
|
256
|
-
canisterName: name,
|
|
257
|
-
didFile: resolvedDidFile,
|
|
258
|
-
clientManagerPath: resolvedClientManagerPath,
|
|
259
|
-
reactorMode
|
|
206
|
+
clientManagerPath: resolvedClientManagerPath
|
|
260
207
|
});
|
|
261
208
|
import_node_fs2.default.mkdirSync(canisterOutDir, { recursive: true });
|
|
262
|
-
import_node_fs2.default.writeFileSync(
|
|
263
|
-
files.push({ success: true, filePath:
|
|
264
|
-
if (!import_node_fs2.default.existsSync(wrapperPath)) {
|
|
265
|
-
import_node_fs2.default.writeFileSync(wrapperPath, wrapperContent);
|
|
266
|
-
files.push({ success: true, filePath: wrapperPath });
|
|
267
|
-
} else {
|
|
268
|
-
const existingWrapperContent = import_node_fs2.default.readFileSync(wrapperPath, "utf-8");
|
|
269
|
-
if (isLegacyGeneratedIndexFile(existingWrapperContent)) {
|
|
270
|
-
import_node_fs2.default.writeFileSync(wrapperPath, wrapperContent);
|
|
271
|
-
files.push({ success: true, filePath: wrapperPath });
|
|
272
|
-
} else {
|
|
273
|
-
files.push({ success: true, filePath: wrapperPath, skipped: true });
|
|
274
|
-
}
|
|
275
|
-
}
|
|
209
|
+
import_node_fs2.default.writeFileSync(reactorPath, reactorContent);
|
|
210
|
+
files.push({ success: true, filePath: reactorPath });
|
|
276
211
|
} catch (err) {
|
|
277
212
|
files.push({
|
|
278
213
|
success: false,
|
|
279
|
-
filePath:
|
|
214
|
+
filePath: reactorPath,
|
|
280
215
|
error: `Reactor generation failed: ${err instanceof Error ? err.message : String(err)}`
|
|
281
216
|
});
|
|
282
217
|
return {
|
|
@@ -355,7 +290,6 @@ export const clientManager = new ClientManager({
|
|
|
355
290
|
generateClientFile,
|
|
356
291
|
generateDeclarations,
|
|
357
292
|
generateReactorFile,
|
|
358
|
-
generateReactorWrapperFile,
|
|
359
293
|
getReactorName,
|
|
360
294
|
getServiceTypeName,
|
|
361
295
|
parseDIDFile,
|
package/dist/index.d.cts
CHANGED
|
@@ -22,19 +22,6 @@ interface CanisterConfig {
|
|
|
22
22
|
/** Optional fixed canister ID */
|
|
23
23
|
canisterId?: string;
|
|
24
24
|
}
|
|
25
|
-
type ReactorMode = "raw" | "display";
|
|
26
|
-
interface ReactorGenerationConfig {
|
|
27
|
-
/**
|
|
28
|
-
* Default reactor mode used for generated hook exports.
|
|
29
|
-
* `display` preserves current behavior.
|
|
30
|
-
*/
|
|
31
|
-
defaultMode?: ReactorMode;
|
|
32
|
-
/**
|
|
33
|
-
* Optional per-canister overrides keyed by canister name.
|
|
34
|
-
* Example: { workflow_engine: "raw" }
|
|
35
|
-
*/
|
|
36
|
-
canisters?: Record<string, ReactorMode>;
|
|
37
|
-
}
|
|
38
25
|
/**
|
|
39
26
|
* Top-level codegen / CLI configuration (stored in `ic-reactor.json`).
|
|
40
27
|
*/
|
|
@@ -51,8 +38,6 @@ interface CodegenConfig {
|
|
|
51
38
|
* Individual canisters can override via `CanisterConfig.clientManagerPath`.
|
|
52
39
|
*/
|
|
53
40
|
clientManagerPath?: string;
|
|
54
|
-
/** Optional reactor mode generation settings */
|
|
55
|
-
reactor?: ReactorGenerationConfig;
|
|
56
41
|
/** Canister configurations, keyed by canister name */
|
|
57
42
|
canisters: Record<string, CanisterConfig>;
|
|
58
43
|
}
|
|
@@ -77,7 +62,7 @@ interface GeneratorResult {
|
|
|
77
62
|
* Pipeline steps (in order):
|
|
78
63
|
* 1. Resolve paths (didFile, outDir)
|
|
79
64
|
* 2. Generate declarations (JS + .d.ts + .did copy)
|
|
80
|
-
* 3. Generate reactor
|
|
65
|
+
* 3. Generate reactor file (index.ts)
|
|
81
66
|
*/
|
|
82
67
|
|
|
83
68
|
interface PipelineOptions {
|
|
@@ -91,7 +76,7 @@ interface PipelineOptions {
|
|
|
91
76
|
/**
|
|
92
77
|
* Global codegen config (for fallback outDir and clientManagerPath).
|
|
93
78
|
*/
|
|
94
|
-
globalConfig: Pick<CodegenConfig, "outDir" | "clientManagerPath"
|
|
79
|
+
globalConfig: Pick<CodegenConfig, "outDir" | "clientManagerPath">;
|
|
95
80
|
}
|
|
96
81
|
interface PipelineResult {
|
|
97
82
|
canisterName: string;
|
|
@@ -219,7 +204,6 @@ declare function declarationsExist(outDir: string, canisterName: string): boolea
|
|
|
219
204
|
* ...
|
|
220
205
|
* } = createActorHooks(backendReactor)
|
|
221
206
|
*/
|
|
222
|
-
|
|
223
207
|
interface ReactorGeneratorOptions {
|
|
224
208
|
/** Canister name (e.g. "backend") */
|
|
225
209
|
canisterName: string;
|
|
@@ -233,21 +217,11 @@ interface ReactorGeneratorOptions {
|
|
|
233
217
|
* Default: "../../clients"
|
|
234
218
|
*/
|
|
235
219
|
clientManagerPath?: string;
|
|
236
|
-
/**
|
|
237
|
-
* Which reactor implementation should back the default exported hooks.
|
|
238
|
-
* Default: "display" (backward compatible)
|
|
239
|
-
*/
|
|
240
|
-
reactorMode?: ReactorMode;
|
|
241
220
|
}
|
|
242
221
|
/**
|
|
243
|
-
* Generate the content of a canister's `index.
|
|
222
|
+
* Generate the content of a canister's `index.ts` reactor file.
|
|
244
223
|
*/
|
|
245
224
|
declare function generateReactorFile(options: ReactorGeneratorOptions): string;
|
|
246
|
-
/**
|
|
247
|
-
* Generate the stable user wrapper `index.ts` for a canister.
|
|
248
|
-
* This file is intended to be created once and preserved across regenerations.
|
|
249
|
-
*/
|
|
250
|
-
declare function generateReactorWrapperFile(options: ReactorGeneratorOptions): string;
|
|
251
225
|
|
|
252
226
|
/**
|
|
253
227
|
* Client Manager Generator
|
|
@@ -272,4 +246,4 @@ interface ClientGeneratorOptions {
|
|
|
272
246
|
*/
|
|
273
247
|
declare function generateClientFile(options?: ClientGeneratorOptions): string;
|
|
274
248
|
|
|
275
|
-
export { type CanisterConfig, type ClientGeneratorOptions, type CodegenConfig, type DeclarationsGeneratorOptions, type DeclarationsGeneratorResult, type GeneratorResult, type MethodInfo, type MethodType, type PipelineOptions, type PipelineResult, type
|
|
249
|
+
export { type CanisterConfig, type ClientGeneratorOptions, type CodegenConfig, type DeclarationsGeneratorOptions, type DeclarationsGeneratorResult, type GeneratorResult, type MethodInfo, type MethodType, type PipelineOptions, type PipelineResult, type ReactorGeneratorOptions, declarationsExist, extractMethods, generateClientFile, generateDeclarations, generateReactorFile, getReactorName, getServiceTypeName, parseDIDFile, runCanisterPipeline, toPascalCase };
|
package/dist/index.d.ts
CHANGED
|
@@ -22,19 +22,6 @@ interface CanisterConfig {
|
|
|
22
22
|
/** Optional fixed canister ID */
|
|
23
23
|
canisterId?: string;
|
|
24
24
|
}
|
|
25
|
-
type ReactorMode = "raw" | "display";
|
|
26
|
-
interface ReactorGenerationConfig {
|
|
27
|
-
/**
|
|
28
|
-
* Default reactor mode used for generated hook exports.
|
|
29
|
-
* `display` preserves current behavior.
|
|
30
|
-
*/
|
|
31
|
-
defaultMode?: ReactorMode;
|
|
32
|
-
/**
|
|
33
|
-
* Optional per-canister overrides keyed by canister name.
|
|
34
|
-
* Example: { workflow_engine: "raw" }
|
|
35
|
-
*/
|
|
36
|
-
canisters?: Record<string, ReactorMode>;
|
|
37
|
-
}
|
|
38
25
|
/**
|
|
39
26
|
* Top-level codegen / CLI configuration (stored in `ic-reactor.json`).
|
|
40
27
|
*/
|
|
@@ -51,8 +38,6 @@ interface CodegenConfig {
|
|
|
51
38
|
* Individual canisters can override via `CanisterConfig.clientManagerPath`.
|
|
52
39
|
*/
|
|
53
40
|
clientManagerPath?: string;
|
|
54
|
-
/** Optional reactor mode generation settings */
|
|
55
|
-
reactor?: ReactorGenerationConfig;
|
|
56
41
|
/** Canister configurations, keyed by canister name */
|
|
57
42
|
canisters: Record<string, CanisterConfig>;
|
|
58
43
|
}
|
|
@@ -77,7 +62,7 @@ interface GeneratorResult {
|
|
|
77
62
|
* Pipeline steps (in order):
|
|
78
63
|
* 1. Resolve paths (didFile, outDir)
|
|
79
64
|
* 2. Generate declarations (JS + .d.ts + .did copy)
|
|
80
|
-
* 3. Generate reactor
|
|
65
|
+
* 3. Generate reactor file (index.ts)
|
|
81
66
|
*/
|
|
82
67
|
|
|
83
68
|
interface PipelineOptions {
|
|
@@ -91,7 +76,7 @@ interface PipelineOptions {
|
|
|
91
76
|
/**
|
|
92
77
|
* Global codegen config (for fallback outDir and clientManagerPath).
|
|
93
78
|
*/
|
|
94
|
-
globalConfig: Pick<CodegenConfig, "outDir" | "clientManagerPath"
|
|
79
|
+
globalConfig: Pick<CodegenConfig, "outDir" | "clientManagerPath">;
|
|
95
80
|
}
|
|
96
81
|
interface PipelineResult {
|
|
97
82
|
canisterName: string;
|
|
@@ -219,7 +204,6 @@ declare function declarationsExist(outDir: string, canisterName: string): boolea
|
|
|
219
204
|
* ...
|
|
220
205
|
* } = createActorHooks(backendReactor)
|
|
221
206
|
*/
|
|
222
|
-
|
|
223
207
|
interface ReactorGeneratorOptions {
|
|
224
208
|
/** Canister name (e.g. "backend") */
|
|
225
209
|
canisterName: string;
|
|
@@ -233,21 +217,11 @@ interface ReactorGeneratorOptions {
|
|
|
233
217
|
* Default: "../../clients"
|
|
234
218
|
*/
|
|
235
219
|
clientManagerPath?: string;
|
|
236
|
-
/**
|
|
237
|
-
* Which reactor implementation should back the default exported hooks.
|
|
238
|
-
* Default: "display" (backward compatible)
|
|
239
|
-
*/
|
|
240
|
-
reactorMode?: ReactorMode;
|
|
241
220
|
}
|
|
242
221
|
/**
|
|
243
|
-
* Generate the content of a canister's `index.
|
|
222
|
+
* Generate the content of a canister's `index.ts` reactor file.
|
|
244
223
|
*/
|
|
245
224
|
declare function generateReactorFile(options: ReactorGeneratorOptions): string;
|
|
246
|
-
/**
|
|
247
|
-
* Generate the stable user wrapper `index.ts` for a canister.
|
|
248
|
-
* This file is intended to be created once and preserved across regenerations.
|
|
249
|
-
*/
|
|
250
|
-
declare function generateReactorWrapperFile(options: ReactorGeneratorOptions): string;
|
|
251
225
|
|
|
252
226
|
/**
|
|
253
227
|
* Client Manager Generator
|
|
@@ -272,4 +246,4 @@ interface ClientGeneratorOptions {
|
|
|
272
246
|
*/
|
|
273
247
|
declare function generateClientFile(options?: ClientGeneratorOptions): string;
|
|
274
248
|
|
|
275
|
-
export { type CanisterConfig, type ClientGeneratorOptions, type CodegenConfig, type DeclarationsGeneratorOptions, type DeclarationsGeneratorResult, type GeneratorResult, type MethodInfo, type MethodType, type PipelineOptions, type PipelineResult, type
|
|
249
|
+
export { type CanisterConfig, type ClientGeneratorOptions, type CodegenConfig, type DeclarationsGeneratorOptions, type DeclarationsGeneratorResult, type GeneratorResult, type MethodInfo, type MethodType, type PipelineOptions, type PipelineResult, type ReactorGeneratorOptions, declarationsExist, extractMethods, generateClientFile, generateDeclarations, generateReactorFile, getReactorName, getServiceTypeName, parseDIDFile, runCanisterPipeline, toPascalCase };
|
package/dist/index.js
CHANGED
|
@@ -79,21 +79,13 @@ function getServiceTypeName(canisterName) {
|
|
|
79
79
|
|
|
80
80
|
// src/generators/reactor.ts
|
|
81
81
|
function generateReactorFile(options) {
|
|
82
|
-
const {
|
|
83
|
-
canisterName,
|
|
84
|
-
didFile,
|
|
85
|
-
clientManagerPath = "../../clients",
|
|
86
|
-
reactorMode = "display"
|
|
87
|
-
} = options;
|
|
82
|
+
const { canisterName, didFile, clientManagerPath = "../../clients" } = options;
|
|
88
83
|
const pascalName = toPascalCase(canisterName);
|
|
89
84
|
const reactorName = getReactorName(canisterName);
|
|
90
85
|
const serviceName = getServiceTypeName(canisterName);
|
|
91
|
-
const rawFactoryName = `create${pascalName}RawReactor`;
|
|
92
|
-
const displayFactoryName = `create${pascalName}DisplayReactor`;
|
|
93
|
-
const defaultFactoryName = reactorMode === "raw" ? rawFactoryName : displayFactoryName;
|
|
94
86
|
const baseName = path2.basename(didFile, ".did");
|
|
95
87
|
const declarationsPath = `./declarations/${baseName}`;
|
|
96
|
-
return `import { DisplayReactor,
|
|
88
|
+
return `import { DisplayReactor, createActorHooks } from "@ic-reactor/react"
|
|
97
89
|
import { clientManager } from "${clientManagerPath}"
|
|
98
90
|
import { idlFactory, type _SERVICE } from "${declarationsPath}"
|
|
99
91
|
|
|
@@ -105,25 +97,11 @@ export type ${serviceName} = _SERVICE
|
|
|
105
97
|
* Auto-generated by @ic-reactor/codegen \u2014 do not edit.
|
|
106
98
|
* Re-run \`ic-reactor generate\` (or the Vite plugin) to regenerate.
|
|
107
99
|
*/
|
|
108
|
-
export
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
})
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function ${displayFactoryName}() {
|
|
117
|
-
return new DisplayReactor<${serviceName}>({
|
|
118
|
-
clientManager,
|
|
119
|
-
idlFactory,
|
|
120
|
-
name: "${canisterName}",
|
|
121
|
-
})
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export const ${reactorName} = ${defaultFactoryName}()
|
|
125
|
-
|
|
126
|
-
export const ${pascalName}ReactorMode = "${reactorMode}" as const
|
|
100
|
+
export const ${reactorName} = new DisplayReactor<${serviceName}>({
|
|
101
|
+
clientManager,
|
|
102
|
+
idlFactory,
|
|
103
|
+
name: "${canisterName}",
|
|
104
|
+
})
|
|
127
105
|
|
|
128
106
|
export const {
|
|
129
107
|
useActorQuery: use${pascalName}Query,
|
|
@@ -135,29 +113,8 @@ export const {
|
|
|
135
113
|
} = createActorHooks(${reactorName})
|
|
136
114
|
`;
|
|
137
115
|
}
|
|
138
|
-
function generateReactorWrapperFile(options) {
|
|
139
|
-
const { canisterName } = options;
|
|
140
|
-
const pascalName = toPascalCase(canisterName);
|
|
141
|
-
return `/**
|
|
142
|
-
* ${pascalName} canister exports
|
|
143
|
-
*
|
|
144
|
-
* This wrapper is created once by @ic-reactor/codegen and is not overwritten.
|
|
145
|
-
* Customize it if you need to swap reactor implementations or compose custom exports.
|
|
146
|
-
*/
|
|
147
|
-
export * from "./index.generated"
|
|
148
|
-
`;
|
|
149
|
-
}
|
|
150
116
|
|
|
151
117
|
// src/pipeline.ts
|
|
152
|
-
function resolveReactorMode(canisterName, globalConfig) {
|
|
153
|
-
return globalConfig.reactor?.canisters?.[canisterName] ?? globalConfig.reactor?.defaultMode ?? "display";
|
|
154
|
-
}
|
|
155
|
-
function isStableWrapperFile(content) {
|
|
156
|
-
return content.includes('export * from "./index.generated"');
|
|
157
|
-
}
|
|
158
|
-
function isLegacyGeneratedIndexFile(content) {
|
|
159
|
-
return content.includes("Auto-generated by @ic-reactor/codegen") && content.includes("createActorHooks(") && !isStableWrapperFile(content);
|
|
160
|
-
}
|
|
161
118
|
async function runCanisterPipeline(options) {
|
|
162
119
|
const { canisterConfig, projectRoot, globalConfig } = options;
|
|
163
120
|
const { name, didFile, clientManagerPath } = canisterConfig;
|
|
@@ -196,41 +153,20 @@ async function runCanisterPipeline(options) {
|
|
|
196
153
|
error: `Declarations step failed: ${err instanceof Error ? err.message : String(err)}`
|
|
197
154
|
};
|
|
198
155
|
}
|
|
199
|
-
const
|
|
200
|
-
const wrapperPath = path3.join(canisterOutDir, "index.ts");
|
|
201
|
-
const reactorMode = resolveReactorMode(name, globalConfig);
|
|
156
|
+
const reactorPath = path3.join(canisterOutDir, "index.ts");
|
|
202
157
|
try {
|
|
203
158
|
const reactorContent = generateReactorFile({
|
|
204
159
|
canisterName: name,
|
|
205
160
|
didFile: resolvedDidFile,
|
|
206
|
-
clientManagerPath: resolvedClientManagerPath
|
|
207
|
-
reactorMode
|
|
208
|
-
});
|
|
209
|
-
const wrapperContent = generateReactorWrapperFile({
|
|
210
|
-
canisterName: name,
|
|
211
|
-
didFile: resolvedDidFile,
|
|
212
|
-
clientManagerPath: resolvedClientManagerPath,
|
|
213
|
-
reactorMode
|
|
161
|
+
clientManagerPath: resolvedClientManagerPath
|
|
214
162
|
});
|
|
215
163
|
fs2.mkdirSync(canisterOutDir, { recursive: true });
|
|
216
|
-
fs2.writeFileSync(
|
|
217
|
-
files.push({ success: true, filePath:
|
|
218
|
-
if (!fs2.existsSync(wrapperPath)) {
|
|
219
|
-
fs2.writeFileSync(wrapperPath, wrapperContent);
|
|
220
|
-
files.push({ success: true, filePath: wrapperPath });
|
|
221
|
-
} else {
|
|
222
|
-
const existingWrapperContent = fs2.readFileSync(wrapperPath, "utf-8");
|
|
223
|
-
if (isLegacyGeneratedIndexFile(existingWrapperContent)) {
|
|
224
|
-
fs2.writeFileSync(wrapperPath, wrapperContent);
|
|
225
|
-
files.push({ success: true, filePath: wrapperPath });
|
|
226
|
-
} else {
|
|
227
|
-
files.push({ success: true, filePath: wrapperPath, skipped: true });
|
|
228
|
-
}
|
|
229
|
-
}
|
|
164
|
+
fs2.writeFileSync(reactorPath, reactorContent);
|
|
165
|
+
files.push({ success: true, filePath: reactorPath });
|
|
230
166
|
} catch (err) {
|
|
231
167
|
files.push({
|
|
232
168
|
success: false,
|
|
233
|
-
filePath:
|
|
169
|
+
filePath: reactorPath,
|
|
234
170
|
error: `Reactor generation failed: ${err instanceof Error ? err.message : String(err)}`
|
|
235
171
|
});
|
|
236
172
|
return {
|
|
@@ -308,7 +244,6 @@ export {
|
|
|
308
244
|
generateClientFile,
|
|
309
245
|
generateDeclarations,
|
|
310
246
|
generateReactorFile,
|
|
311
|
-
generateReactorWrapperFile,
|
|
312
247
|
getReactorName,
|
|
313
248
|
getServiceTypeName,
|
|
314
249
|
parseDIDFile,
|
package/package.json
CHANGED
package/src/generators/index.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type {
|
|
|
11
11
|
DeclarationsGeneratorResult,
|
|
12
12
|
} from "./declarations.js"
|
|
13
13
|
|
|
14
|
-
export { generateReactorFile
|
|
14
|
+
export { generateReactorFile } from "./reactor.js"
|
|
15
15
|
export type { ReactorGeneratorOptions } from "./reactor.js"
|
|
16
16
|
|
|
17
17
|
export { generateClientFile } from "./client.js"
|
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
|
|
23
23
|
import path from "node:path"
|
|
24
24
|
import { toPascalCase, getReactorName, getServiceTypeName } from "../naming.js"
|
|
25
|
-
import type { ReactorMode } from "../types.js"
|
|
26
25
|
|
|
27
26
|
export interface ReactorGeneratorOptions {
|
|
28
27
|
/** Canister name (e.g. "backend") */
|
|
@@ -37,37 +36,23 @@ export interface ReactorGeneratorOptions {
|
|
|
37
36
|
* Default: "../../clients"
|
|
38
37
|
*/
|
|
39
38
|
clientManagerPath?: string
|
|
40
|
-
/**
|
|
41
|
-
* Which reactor implementation should back the default exported hooks.
|
|
42
|
-
* Default: "display" (backward compatible)
|
|
43
|
-
*/
|
|
44
|
-
reactorMode?: ReactorMode
|
|
45
39
|
}
|
|
46
40
|
|
|
47
41
|
/**
|
|
48
|
-
* Generate the content of a canister's `index.
|
|
42
|
+
* Generate the content of a canister's `index.ts` reactor file.
|
|
49
43
|
*/
|
|
50
44
|
export function generateReactorFile(options: ReactorGeneratorOptions): string {
|
|
51
|
-
const {
|
|
52
|
-
canisterName,
|
|
53
|
-
didFile,
|
|
54
|
-
clientManagerPath = "../../clients",
|
|
55
|
-
reactorMode = "display",
|
|
56
|
-
} = options
|
|
45
|
+
const { canisterName, didFile, clientManagerPath = "../../clients" } = options
|
|
57
46
|
|
|
58
47
|
const pascalName = toPascalCase(canisterName)
|
|
59
48
|
const reactorName = getReactorName(canisterName)
|
|
60
49
|
const serviceName = getServiceTypeName(canisterName)
|
|
61
|
-
const rawFactoryName = `create${pascalName}RawReactor`
|
|
62
|
-
const displayFactoryName = `create${pascalName}DisplayReactor`
|
|
63
|
-
const defaultFactoryName =
|
|
64
|
-
reactorMode === "raw" ? rawFactoryName : displayFactoryName
|
|
65
50
|
|
|
66
51
|
// Derive the declarations import path from the .did filename
|
|
67
52
|
const baseName = path.basename(didFile, ".did")
|
|
68
53
|
const declarationsPath = `./declarations/${baseName}`
|
|
69
54
|
|
|
70
|
-
return `import { DisplayReactor,
|
|
55
|
+
return `import { DisplayReactor, createActorHooks } from "@ic-reactor/react"
|
|
71
56
|
import { clientManager } from "${clientManagerPath}"
|
|
72
57
|
import { idlFactory, type _SERVICE } from "${declarationsPath}"
|
|
73
58
|
|
|
@@ -79,25 +64,11 @@ export type ${serviceName} = _SERVICE
|
|
|
79
64
|
* Auto-generated by @ic-reactor/codegen — do not edit.
|
|
80
65
|
* Re-run \`ic-reactor generate\` (or the Vite plugin) to regenerate.
|
|
81
66
|
*/
|
|
82
|
-
export
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export function ${displayFactoryName}() {
|
|
91
|
-
return new DisplayReactor<${serviceName}>({
|
|
92
|
-
clientManager,
|
|
93
|
-
idlFactory,
|
|
94
|
-
name: "${canisterName}",
|
|
95
|
-
})
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export const ${reactorName} = ${defaultFactoryName}()
|
|
99
|
-
|
|
100
|
-
export const ${pascalName}ReactorMode = "${reactorMode}" as const
|
|
67
|
+
export const ${reactorName} = new DisplayReactor<${serviceName}>({
|
|
68
|
+
clientManager,
|
|
69
|
+
idlFactory,
|
|
70
|
+
name: "${canisterName}",
|
|
71
|
+
})
|
|
101
72
|
|
|
102
73
|
export const {
|
|
103
74
|
useActorQuery: use${pascalName}Query,
|
|
@@ -109,23 +80,3 @@ export const {
|
|
|
109
80
|
} = createActorHooks(${reactorName})
|
|
110
81
|
`
|
|
111
82
|
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Generate the stable user wrapper `index.ts` for a canister.
|
|
115
|
-
* This file is intended to be created once and preserved across regenerations.
|
|
116
|
-
*/
|
|
117
|
-
export function generateReactorWrapperFile(
|
|
118
|
-
options: ReactorGeneratorOptions
|
|
119
|
-
): string {
|
|
120
|
-
const { canisterName } = options
|
|
121
|
-
const pascalName = toPascalCase(canisterName)
|
|
122
|
-
|
|
123
|
-
return `/**
|
|
124
|
-
* ${pascalName} canister exports
|
|
125
|
-
*
|
|
126
|
-
* This wrapper is created once by @ic-reactor/codegen and is not overwritten.
|
|
127
|
-
* Customize it if you need to swap reactor implementations or compose custom exports.
|
|
128
|
-
*/
|
|
129
|
-
export * from "./index.generated"
|
|
130
|
-
`
|
|
131
|
-
}
|
package/src/index.ts
CHANGED
|
@@ -6,13 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
// Core Types
|
|
9
|
-
export type {
|
|
10
|
-
CanisterConfig,
|
|
11
|
-
CodegenConfig,
|
|
12
|
-
GeneratorResult,
|
|
13
|
-
ReactorMode,
|
|
14
|
-
ReactorGenerationConfig,
|
|
15
|
-
} from "./types.js"
|
|
9
|
+
export type { CanisterConfig, CodegenConfig, GeneratorResult } from "./types.js"
|
|
16
10
|
|
|
17
11
|
// Pipeline (Primary Entry Point)
|
|
18
12
|
export { runCanisterPipeline } from "./pipeline.js"
|
package/src/pipeline.ts
CHANGED
|
@@ -7,22 +7,14 @@
|
|
|
7
7
|
* Pipeline steps (in order):
|
|
8
8
|
* 1. Resolve paths (didFile, outDir)
|
|
9
9
|
* 2. Generate declarations (JS + .d.ts + .did copy)
|
|
10
|
-
* 3. Generate reactor
|
|
10
|
+
* 3. Generate reactor file (index.ts)
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import fs from "node:fs"
|
|
14
14
|
import path from "node:path"
|
|
15
|
-
import type {
|
|
16
|
-
CanisterConfig,
|
|
17
|
-
CodegenConfig,
|
|
18
|
-
GeneratorResult,
|
|
19
|
-
ReactorMode,
|
|
20
|
-
} from "./types.js"
|
|
15
|
+
import type { CanisterConfig, CodegenConfig, GeneratorResult } from "./types.js"
|
|
21
16
|
import { generateDeclarations } from "./generators/declarations.js"
|
|
22
|
-
import {
|
|
23
|
-
generateReactorFile,
|
|
24
|
-
generateReactorWrapperFile,
|
|
25
|
-
} from "./generators/reactor.js"
|
|
17
|
+
import { generateReactorFile } from "./generators/reactor.js"
|
|
26
18
|
|
|
27
19
|
export interface PipelineOptions {
|
|
28
20
|
/** Canister name and config */
|
|
@@ -35,30 +27,7 @@ export interface PipelineOptions {
|
|
|
35
27
|
/**
|
|
36
28
|
* Global codegen config (for fallback outDir and clientManagerPath).
|
|
37
29
|
*/
|
|
38
|
-
globalConfig: Pick<CodegenConfig, "outDir" | "clientManagerPath"
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function resolveReactorMode(
|
|
42
|
-
canisterName: string,
|
|
43
|
-
globalConfig: Pick<CodegenConfig, "reactor">
|
|
44
|
-
): ReactorMode {
|
|
45
|
-
return (
|
|
46
|
-
globalConfig.reactor?.canisters?.[canisterName] ??
|
|
47
|
-
globalConfig.reactor?.defaultMode ??
|
|
48
|
-
"display"
|
|
49
|
-
)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function isStableWrapperFile(content: string): boolean {
|
|
53
|
-
return content.includes('export * from "./index.generated"')
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function isLegacyGeneratedIndexFile(content: string): boolean {
|
|
57
|
-
return (
|
|
58
|
-
content.includes("Auto-generated by @ic-reactor/codegen") &&
|
|
59
|
-
content.includes("createActorHooks(") &&
|
|
60
|
-
!isStableWrapperFile(content)
|
|
61
|
-
)
|
|
30
|
+
globalConfig: Pick<CodegenConfig, "outDir" | "clientManagerPath">
|
|
62
31
|
}
|
|
63
32
|
|
|
64
33
|
export interface PipelineResult {
|
|
@@ -137,48 +106,25 @@ export async function runCanisterPipeline(
|
|
|
137
106
|
}
|
|
138
107
|
}
|
|
139
108
|
|
|
140
|
-
// ── Step 2: Reactor
|
|
109
|
+
// ── Step 2: Reactor file ───────────────────────────────────────────────────
|
|
141
110
|
|
|
142
|
-
const
|
|
143
|
-
const wrapperPath = path.join(canisterOutDir, "index.ts")
|
|
144
|
-
const reactorMode = resolveReactorMode(name, globalConfig)
|
|
111
|
+
const reactorPath = path.join(canisterOutDir, "index.ts")
|
|
145
112
|
|
|
146
113
|
try {
|
|
147
114
|
const reactorContent = generateReactorFile({
|
|
148
115
|
canisterName: name,
|
|
149
116
|
didFile: resolvedDidFile,
|
|
150
117
|
clientManagerPath: resolvedClientManagerPath,
|
|
151
|
-
reactorMode,
|
|
152
|
-
})
|
|
153
|
-
const wrapperContent = generateReactorWrapperFile({
|
|
154
|
-
canisterName: name,
|
|
155
|
-
didFile: resolvedDidFile,
|
|
156
|
-
clientManagerPath: resolvedClientManagerPath,
|
|
157
|
-
reactorMode,
|
|
158
118
|
})
|
|
159
119
|
|
|
160
120
|
fs.mkdirSync(canisterOutDir, { recursive: true })
|
|
161
|
-
fs.writeFileSync(
|
|
162
|
-
|
|
163
|
-
files.push({ success: true, filePath: generatedReactorPath })
|
|
121
|
+
fs.writeFileSync(reactorPath, reactorContent)
|
|
164
122
|
|
|
165
|
-
|
|
166
|
-
fs.writeFileSync(wrapperPath, wrapperContent)
|
|
167
|
-
files.push({ success: true, filePath: wrapperPath })
|
|
168
|
-
} else {
|
|
169
|
-
const existingWrapperContent = fs.readFileSync(wrapperPath, "utf-8")
|
|
170
|
-
|
|
171
|
-
if (isLegacyGeneratedIndexFile(existingWrapperContent)) {
|
|
172
|
-
fs.writeFileSync(wrapperPath, wrapperContent)
|
|
173
|
-
files.push({ success: true, filePath: wrapperPath })
|
|
174
|
-
} else {
|
|
175
|
-
files.push({ success: true, filePath: wrapperPath, skipped: true })
|
|
176
|
-
}
|
|
177
|
-
}
|
|
123
|
+
files.push({ success: true, filePath: reactorPath })
|
|
178
124
|
} catch (err) {
|
|
179
125
|
files.push({
|
|
180
126
|
success: false,
|
|
181
|
-
filePath:
|
|
127
|
+
filePath: reactorPath,
|
|
182
128
|
error: `Reactor generation failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
183
129
|
})
|
|
184
130
|
|
package/src/types.ts
CHANGED
|
@@ -28,21 +28,6 @@ export interface CanisterConfig {
|
|
|
28
28
|
canisterId?: string
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export type ReactorMode = "raw" | "display"
|
|
32
|
-
|
|
33
|
-
export interface ReactorGenerationConfig {
|
|
34
|
-
/**
|
|
35
|
-
* Default reactor mode used for generated hook exports.
|
|
36
|
-
* `display` preserves current behavior.
|
|
37
|
-
*/
|
|
38
|
-
defaultMode?: ReactorMode
|
|
39
|
-
/**
|
|
40
|
-
* Optional per-canister overrides keyed by canister name.
|
|
41
|
-
* Example: { workflow_engine: "raw" }
|
|
42
|
-
*/
|
|
43
|
-
canisters?: Record<string, ReactorMode>
|
|
44
|
-
}
|
|
45
|
-
|
|
46
31
|
/**
|
|
47
32
|
* Top-level codegen / CLI configuration (stored in `ic-reactor.json`).
|
|
48
33
|
*/
|
|
@@ -59,8 +44,6 @@ export interface CodegenConfig {
|
|
|
59
44
|
* Individual canisters can override via `CanisterConfig.clientManagerPath`.
|
|
60
45
|
*/
|
|
61
46
|
clientManagerPath?: string
|
|
62
|
-
/** Optional reactor mode generation settings */
|
|
63
|
-
reactor?: ReactorGenerationConfig
|
|
64
47
|
/** Canister configurations, keyed by canister name */
|
|
65
48
|
canisters: Record<string, CanisterConfig>
|
|
66
49
|
}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
-
|
|
3
|
-
exports[`Reactor generator > generates a stable wrapper file > stable-wrapper-index 1`] = `
|
|
4
|
-
"/**
|
|
5
|
-
* Backend canister exports
|
|
6
|
-
*
|
|
7
|
-
* This wrapper is created once by @ic-reactor/codegen and is not overwritten.
|
|
8
|
-
* Customize it if you need to swap reactor implementations or compose custom exports.
|
|
9
|
-
*/
|
|
10
|
-
export * from "./index.generated"
|
|
11
|
-
"
|
|
12
|
-
`;
|
|
13
|
-
|
|
14
|
-
exports[`Reactor generator > keeps default behavior as display mode > display-mode-index-generated 1`] = `
|
|
15
|
-
"import { DisplayReactor, Reactor, createActorHooks } from "@ic-reactor/react"
|
|
16
|
-
import { clientManager } from "../../clients"
|
|
17
|
-
import { idlFactory, type _SERVICE } from "./declarations/backend"
|
|
18
|
-
|
|
19
|
-
export type BackendService = _SERVICE
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Backend Reactor
|
|
23
|
-
*
|
|
24
|
-
* Auto-generated by @ic-reactor/codegen — do not edit.
|
|
25
|
-
* Re-run \`ic-reactor generate\` (or the Vite plugin) to regenerate.
|
|
26
|
-
*/
|
|
27
|
-
export function createBackendRawReactor() {
|
|
28
|
-
return new Reactor<BackendService>({
|
|
29
|
-
clientManager,
|
|
30
|
-
idlFactory,
|
|
31
|
-
name: "backend",
|
|
32
|
-
})
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function createBackendDisplayReactor() {
|
|
36
|
-
return new DisplayReactor<BackendService>({
|
|
37
|
-
clientManager,
|
|
38
|
-
idlFactory,
|
|
39
|
-
name: "backend",
|
|
40
|
-
})
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export const backendReactor = createBackendDisplayReactor()
|
|
44
|
-
|
|
45
|
-
export const BackendReactorMode = "display" as const
|
|
46
|
-
|
|
47
|
-
export const {
|
|
48
|
-
useActorQuery: useBackendQuery,
|
|
49
|
-
useActorSuspenseQuery: useBackendSuspenseQuery,
|
|
50
|
-
useActorInfiniteQuery: useBackendInfiniteQuery,
|
|
51
|
-
useActorSuspenseInfiniteQuery: useBackendSuspenseInfiniteQuery,
|
|
52
|
-
useActorMutation: useBackendMutation,
|
|
53
|
-
useActorMethod: useBackendMethod,
|
|
54
|
-
} = createActorHooks(backendReactor)
|
|
55
|
-
"
|
|
56
|
-
`;
|
|
57
|
-
|
|
58
|
-
exports[`Reactor generator > supports raw mode generation > raw-mode-index-generated 1`] = `
|
|
59
|
-
"import { DisplayReactor, Reactor, createActorHooks } from "@ic-reactor/react"
|
|
60
|
-
import { clientManager } from "../../clients"
|
|
61
|
-
import { idlFactory, type _SERVICE } from "./declarations/workflow_engine"
|
|
62
|
-
|
|
63
|
-
export type WorkflowEngineService = _SERVICE
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* WorkflowEngine Reactor
|
|
67
|
-
*
|
|
68
|
-
* Auto-generated by @ic-reactor/codegen — do not edit.
|
|
69
|
-
* Re-run \`ic-reactor generate\` (or the Vite plugin) to regenerate.
|
|
70
|
-
*/
|
|
71
|
-
export function createWorkflowEngineRawReactor() {
|
|
72
|
-
return new Reactor<WorkflowEngineService>({
|
|
73
|
-
clientManager,
|
|
74
|
-
idlFactory,
|
|
75
|
-
name: "workflow_engine",
|
|
76
|
-
})
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function createWorkflowEngineDisplayReactor() {
|
|
80
|
-
return new DisplayReactor<WorkflowEngineService>({
|
|
81
|
-
clientManager,
|
|
82
|
-
idlFactory,
|
|
83
|
-
name: "workflow_engine",
|
|
84
|
-
})
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export const workflowEngineReactor = createWorkflowEngineRawReactor()
|
|
88
|
-
|
|
89
|
-
export const WorkflowEngineReactorMode = "raw" as const
|
|
90
|
-
|
|
91
|
-
export const {
|
|
92
|
-
useActorQuery: useWorkflowEngineQuery,
|
|
93
|
-
useActorSuspenseQuery: useWorkflowEngineSuspenseQuery,
|
|
94
|
-
useActorInfiniteQuery: useWorkflowEngineInfiniteQuery,
|
|
95
|
-
useActorSuspenseInfiniteQuery: useWorkflowEngineSuspenseInfiniteQuery,
|
|
96
|
-
useActorMutation: useWorkflowEngineMutation,
|
|
97
|
-
useActorMethod: useWorkflowEngineMethod,
|
|
98
|
-
} = createActorHooks(workflowEngineReactor)
|
|
99
|
-
"
|
|
100
|
-
`;
|
package/src/pipeline.test.ts
DELETED
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs"
|
|
2
|
-
import os from "node:os"
|
|
3
|
-
import path from "node:path"
|
|
4
|
-
import { afterEach, describe, expect, it } from "vitest"
|
|
5
|
-
import { runCanisterPipeline } from "./pipeline"
|
|
6
|
-
|
|
7
|
-
describe("Codegen pipeline", () => {
|
|
8
|
-
const tempDirs: string[] = []
|
|
9
|
-
|
|
10
|
-
afterEach(() => {
|
|
11
|
-
for (const dir of tempDirs) {
|
|
12
|
-
fs.rmSync(dir, { recursive: true, force: true })
|
|
13
|
-
}
|
|
14
|
-
tempDirs.length = 0
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
function createTempProject() {
|
|
18
|
-
const projectRoot = fs.mkdtempSync(
|
|
19
|
-
path.join(os.tmpdir(), "ic-reactor-codegen-pipeline-")
|
|
20
|
-
)
|
|
21
|
-
tempDirs.push(projectRoot)
|
|
22
|
-
return projectRoot
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function writeDid(projectRoot: string, fileName: string) {
|
|
26
|
-
fs.writeFileSync(
|
|
27
|
-
path.join(projectRoot, fileName),
|
|
28
|
-
`service : {
|
|
29
|
-
greet: (text) -> (text) query;
|
|
30
|
-
}`
|
|
31
|
-
)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
it("applies per-canister reactor mode overrides over the global default", async () => {
|
|
35
|
-
const projectRoot = createTempProject()
|
|
36
|
-
writeDid(projectRoot, "workflow_engine.did")
|
|
37
|
-
|
|
38
|
-
const result = await runCanisterPipeline({
|
|
39
|
-
canisterConfig: {
|
|
40
|
-
name: "workflow_engine",
|
|
41
|
-
didFile: "workflow_engine.did",
|
|
42
|
-
},
|
|
43
|
-
projectRoot,
|
|
44
|
-
globalConfig: {
|
|
45
|
-
outDir: "src/declarations",
|
|
46
|
-
clientManagerPath: "../../clients",
|
|
47
|
-
reactor: {
|
|
48
|
-
defaultMode: "display",
|
|
49
|
-
canisters: {
|
|
50
|
-
workflow_engine: "raw",
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
expect(result.success).toBe(true)
|
|
57
|
-
|
|
58
|
-
const generatedPath = path.join(
|
|
59
|
-
projectRoot,
|
|
60
|
-
"src/declarations/workflow_engine/index.generated.ts"
|
|
61
|
-
)
|
|
62
|
-
const generated = fs.readFileSync(generatedPath, "utf-8")
|
|
63
|
-
|
|
64
|
-
expect(generated).toContain("new Reactor<WorkflowEngineService>")
|
|
65
|
-
expect(generated).toContain(
|
|
66
|
-
'export const WorkflowEngineReactorMode = "raw" as const'
|
|
67
|
-
)
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
it("does not overwrite the wrapper file on regenerate", async () => {
|
|
71
|
-
const projectRoot = createTempProject()
|
|
72
|
-
writeDid(projectRoot, "backend.did")
|
|
73
|
-
|
|
74
|
-
const options = {
|
|
75
|
-
canisterConfig: {
|
|
76
|
-
name: "backend",
|
|
77
|
-
didFile: "backend.did",
|
|
78
|
-
},
|
|
79
|
-
projectRoot,
|
|
80
|
-
globalConfig: {
|
|
81
|
-
outDir: "src/declarations",
|
|
82
|
-
clientManagerPath: "../../clients",
|
|
83
|
-
},
|
|
84
|
-
} as const
|
|
85
|
-
|
|
86
|
-
const first = await runCanisterPipeline(options)
|
|
87
|
-
expect(first.success).toBe(true)
|
|
88
|
-
|
|
89
|
-
const wrapperPath = path.join(
|
|
90
|
-
projectRoot,
|
|
91
|
-
"src/declarations/backend/index.ts"
|
|
92
|
-
)
|
|
93
|
-
fs.writeFileSync(
|
|
94
|
-
wrapperPath,
|
|
95
|
-
`// user wrapper
|
|
96
|
-
export const customBackendWrapper = true
|
|
97
|
-
`
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
const second = await runCanisterPipeline(options)
|
|
101
|
-
expect(second.success).toBe(true)
|
|
102
|
-
|
|
103
|
-
const wrapper = fs.readFileSync(wrapperPath, "utf-8")
|
|
104
|
-
expect(wrapper).toContain("customBackendWrapper = true")
|
|
105
|
-
expect(second.files).toEqual(
|
|
106
|
-
expect.arrayContaining([
|
|
107
|
-
expect.objectContaining({
|
|
108
|
-
filePath: wrapperPath,
|
|
109
|
-
skipped: true,
|
|
110
|
-
success: true,
|
|
111
|
-
}),
|
|
112
|
-
])
|
|
113
|
-
)
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
it("migrates a legacy generated index.ts into a stable wrapper", async () => {
|
|
117
|
-
const projectRoot = createTempProject()
|
|
118
|
-
writeDid(projectRoot, "backend.did")
|
|
119
|
-
|
|
120
|
-
const canisterOutDir = path.join(projectRoot, "src/declarations/backend")
|
|
121
|
-
fs.mkdirSync(canisterOutDir, { recursive: true })
|
|
122
|
-
|
|
123
|
-
// Simulate the pre-wrapper generated index.ts content from older versions.
|
|
124
|
-
fs.writeFileSync(
|
|
125
|
-
path.join(canisterOutDir, "index.ts"),
|
|
126
|
-
`import { DisplayReactor, createActorHooks } from "@ic-reactor/react"
|
|
127
|
-
import { clientManager } from "../../clients"
|
|
128
|
-
import { idlFactory, type _SERVICE } from "./declarations/backend"
|
|
129
|
-
|
|
130
|
-
export type BackendService = _SERVICE
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Backend Reactor
|
|
134
|
-
*
|
|
135
|
-
* Auto-generated by @ic-reactor/codegen — do not edit.
|
|
136
|
-
* Re-run \`ic-reactor generate\` (or the Vite plugin) to regenerate.
|
|
137
|
-
*/
|
|
138
|
-
export const backendReactor = new DisplayReactor<BackendService>({
|
|
139
|
-
clientManager,
|
|
140
|
-
idlFactory,
|
|
141
|
-
name: "backend",
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
export const {
|
|
145
|
-
useActorQuery: useBackendQuery,
|
|
146
|
-
} = createActorHooks(backendReactor)
|
|
147
|
-
`
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
const result = await runCanisterPipeline({
|
|
151
|
-
canisterConfig: {
|
|
152
|
-
name: "backend",
|
|
153
|
-
didFile: "backend.did",
|
|
154
|
-
},
|
|
155
|
-
projectRoot,
|
|
156
|
-
globalConfig: {
|
|
157
|
-
outDir: "src/declarations",
|
|
158
|
-
clientManagerPath: "../../clients",
|
|
159
|
-
},
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
expect(result.success).toBe(true)
|
|
163
|
-
|
|
164
|
-
const wrapperPath = path.join(canisterOutDir, "index.ts")
|
|
165
|
-
const wrapper = fs.readFileSync(wrapperPath, "utf-8")
|
|
166
|
-
expect(wrapper).toContain('export * from "./index.generated"')
|
|
167
|
-
expect(wrapper).not.toContain("createActorHooks(")
|
|
168
|
-
|
|
169
|
-
const generated = fs.readFileSync(
|
|
170
|
-
path.join(canisterOutDir, "index.generated.ts"),
|
|
171
|
-
"utf-8"
|
|
172
|
-
)
|
|
173
|
-
expect(generated).toContain("createBackendDisplayReactor")
|
|
174
|
-
expect(generated).toContain(
|
|
175
|
-
'export const BackendReactorMode = "display" as const'
|
|
176
|
-
)
|
|
177
|
-
})
|
|
178
|
-
})
|
package/src/reactor.test.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest"
|
|
2
|
-
import { generateReactorFile, generateReactorWrapperFile } from "./generators"
|
|
3
|
-
|
|
4
|
-
describe("Reactor generator", () => {
|
|
5
|
-
it("keeps default behavior as display mode", () => {
|
|
6
|
-
const content = generateReactorFile({
|
|
7
|
-
canisterName: "backend",
|
|
8
|
-
didFile: "mock/backend.did",
|
|
9
|
-
clientManagerPath: "../../clients",
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
expect(content).toMatchSnapshot("display-mode-index-generated")
|
|
13
|
-
expect(content).toContain("new DisplayReactor<BackendService>")
|
|
14
|
-
expect(content).toContain(
|
|
15
|
-
'export const BackendReactorMode = "display" as const'
|
|
16
|
-
)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
it("supports raw mode generation", () => {
|
|
20
|
-
const content = generateReactorFile({
|
|
21
|
-
canisterName: "workflow_engine",
|
|
22
|
-
didFile: "mock/workflow_engine.did",
|
|
23
|
-
reactorMode: "raw",
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
expect(content).toMatchSnapshot("raw-mode-index-generated")
|
|
27
|
-
expect(content).toContain("new Reactor<WorkflowEngineService>")
|
|
28
|
-
expect(content).toContain(
|
|
29
|
-
'export const WorkflowEngineReactorMode = "raw" as const'
|
|
30
|
-
)
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
it("generates a stable wrapper file", () => {
|
|
34
|
-
const content = generateReactorWrapperFile({
|
|
35
|
-
canisterName: "backend",
|
|
36
|
-
didFile: "mock/backend.did",
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
expect(content).toMatchSnapshot("stable-wrapper-index")
|
|
40
|
-
expect(content).toContain('export * from "./index.generated"')
|
|
41
|
-
})
|
|
42
|
-
})
|