@ic-reactor/codegen 0.12.0 → 0.13.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/README.md +14 -4
- package/dist/index.cjs +415 -699
- package/dist/index.d.cts +119 -28
- package/dist/index.d.ts +119 -28
- package/dist/index.js +404 -98
- package/package.json +9 -15
- package/src/generators/declarations.ts +164 -21
- package/src/generators/reactor.ts +20 -7
- package/src/index.ts +19 -5
- package/src/pipeline.ts +190 -18
- package/src/validate.ts +407 -0
- package/dist/chunk-VBCR5IVT.js +0 -609
- package/dist/renderer.cjs +0 -639
- package/dist/renderer.d.cts +0 -33
- package/dist/renderer.d.ts +0 -33
- package/dist/renderer.js +0 -14
- package/src/__snapshots__/bindgen.test.ts.snap +0 -18
- package/src/__snapshots__/reactor.test.ts.snap +0 -127
- package/src/bindgen.test.ts +0 -85
- package/src/metadata-rules.json +0 -144
- package/src/metadata.ts +0 -157
- package/src/naming.test.ts +0 -45
- package/src/parser.ts +0 -79
- package/src/pipeline.test.ts +0 -355
- package/src/reactor.test.ts +0 -84
- package/src/renderer.test.ts +0 -573
- package/src/renderer.ts +0 -515
package/dist/index.cjs
CHANGED
|
@@ -30,32 +30,274 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
CANISTER_NAME_PATTERN: () => CANISTER_NAME_PATTERN,
|
|
34
|
+
CODEGEN_TARGETS: () => CODEGEN_TARGETS,
|
|
35
|
+
CodegenConfigError: () => CodegenConfigError,
|
|
36
|
+
REACTOR_CLASS_NAMES: () => REACTOR_CLASS_NAMES,
|
|
37
|
+
assertContainedPath: () => assertContainedPath,
|
|
38
|
+
assertOneOf: () => assertOneOf,
|
|
39
|
+
assertSafeCanisterConfig: () => assertSafeCanisterConfig,
|
|
40
|
+
assertSafeCanisterName: () => assertSafeCanisterName,
|
|
41
|
+
assertSafeModuleSpecifier: () => assertSafeModuleSpecifier,
|
|
33
42
|
declarationsExist: () => declarationsExist,
|
|
34
|
-
extractMethods: () => extractMethods,
|
|
35
43
|
generateClientFile: () => generateClientFile,
|
|
36
|
-
generateCodecDeclarations: () => generateCodecDeclarations,
|
|
37
44
|
generateDeclarations: () => generateDeclarations,
|
|
38
45
|
generateReactorEntryFile: () => generateReactorEntryFile,
|
|
39
46
|
generateReactorFile: () => generateReactorFile,
|
|
40
47
|
getReactorName: () => getReactorName,
|
|
41
48
|
getServiceTypeName: () => getServiceTypeName,
|
|
42
|
-
|
|
49
|
+
resolveContainedOutDir: () => resolveContainedOutDir,
|
|
50
|
+
resolveDeclarationsBaseName: () => resolveDeclarationsBaseName,
|
|
43
51
|
runCanisterPipeline: () => runCanisterPipeline,
|
|
44
52
|
toPascalCase: () => toPascalCase
|
|
45
53
|
});
|
|
46
54
|
module.exports = __toCommonJS(index_exports);
|
|
47
55
|
|
|
48
56
|
// src/pipeline.ts
|
|
49
|
-
var
|
|
57
|
+
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
50
58
|
var import_node_path3 = __toESM(require("path"), 1);
|
|
51
59
|
|
|
52
60
|
// src/generators/declarations.ts
|
|
53
61
|
var import_parser = require("@ic-reactor/parser");
|
|
54
|
-
var
|
|
62
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
63
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
64
|
+
|
|
65
|
+
// src/validate.ts
|
|
55
66
|
var import_node_fs = __toESM(require("fs"), 1);
|
|
67
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
68
|
+
|
|
69
|
+
// src/naming.ts
|
|
70
|
+
var import_change_case = require("change-case");
|
|
71
|
+
function toPascalCase(str) {
|
|
72
|
+
return (0, import_change_case.pascalCase)(str);
|
|
73
|
+
}
|
|
74
|
+
function toCamelCase(str) {
|
|
75
|
+
return (0, import_change_case.camelCase)(str);
|
|
76
|
+
}
|
|
77
|
+
function getReactorName(canisterName) {
|
|
78
|
+
return `${toCamelCase(canisterName)}Reactor`;
|
|
79
|
+
}
|
|
80
|
+
function getServiceTypeName(canisterName) {
|
|
81
|
+
return `${toPascalCase(canisterName)}Service`;
|
|
82
|
+
}
|
|
83
|
+
function getHookPrefix(canisterName) {
|
|
84
|
+
return toPascalCase(canisterName);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/validate.ts
|
|
88
|
+
var CodegenConfigError = class extends Error {
|
|
89
|
+
name = "CodegenConfigError";
|
|
90
|
+
constructor(message) {
|
|
91
|
+
super(message);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
var CANISTER_NAME_PATTERN = /^[A-Za-z0-9_.-]+$/;
|
|
95
|
+
var IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
96
|
+
var MAX_CANISTER_NAME_LENGTH = 64;
|
|
97
|
+
var HAS_URI_SCHEME = /^(?:[A-Za-z][A-Za-z0-9+.-]*:|\/\/)/;
|
|
98
|
+
var BREAKS_OUT_OF_LITERAL = /["'`\\\u0000-\u001f\u2028\u2029]/;
|
|
99
|
+
function assertSafeCanisterName(name) {
|
|
100
|
+
if (typeof name !== "string" || name.length === 0) {
|
|
101
|
+
throw new CodegenConfigError(
|
|
102
|
+
`Invalid canister name: expected a non-empty string, received ${name === void 0 ? "undefined" : JSON.stringify(name)}. Check the "canisters" entries in your ic-reactor.json (or the plugin's "canisters" option).`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
if (name.length > MAX_CANISTER_NAME_LENGTH) {
|
|
106
|
+
throw new CodegenConfigError(
|
|
107
|
+
`Invalid canister name ${JSON.stringify(name)}: must be at most ${MAX_CANISTER_NAME_LENGTH} characters.`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
if (!CANISTER_NAME_PATTERN.test(name)) {
|
|
111
|
+
throw new CodegenConfigError(
|
|
112
|
+
`Invalid canister name ${JSON.stringify(name)}: may contain only letters, digits, "_", "." and "-" (${CANISTER_NAME_PATTERN.source}). Canister names become directory names, so path separators, quotes and whitespace are not allowed.`
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
if (name === "." || name === "..") {
|
|
116
|
+
throw new CodegenConfigError(
|
|
117
|
+
`Invalid canister name ${JSON.stringify(name)}: refers to a directory, not a canister.`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
if (toPascalCase(name).length === 0) {
|
|
121
|
+
throw new CodegenConfigError(
|
|
122
|
+
`Invalid canister name ${JSON.stringify(name)}: contains no letters or digits, so it collapses to an empty identifier in generated code.`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
const derived = [
|
|
126
|
+
["reactor constant", getReactorName(name)],
|
|
127
|
+
["service type", getServiceTypeName(name)],
|
|
128
|
+
["hook name", `use${getHookPrefix(name)}Query`]
|
|
129
|
+
];
|
|
130
|
+
for (const [what, identifier] of derived) {
|
|
131
|
+
if (!IDENTIFIER_PATTERN.test(identifier)) {
|
|
132
|
+
throw new CodegenConfigError(
|
|
133
|
+
`Invalid canister name ${JSON.stringify(name)}: it derives the ${what} ${JSON.stringify(identifier)}, which is not a valid TypeScript identifier. Rename the canister so it does not begin with a digit.`
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function assertSafeModuleSpecifier(label, specifier) {
|
|
139
|
+
if (typeof specifier !== "string" || specifier.length === 0) {
|
|
140
|
+
throw new CodegenConfigError(
|
|
141
|
+
`Invalid ${label}: expected a non-empty string, received ${specifier === void 0 ? "undefined" : JSON.stringify(specifier)}.`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
if (BREAKS_OUT_OF_LITERAL.test(specifier)) {
|
|
145
|
+
throw new CodegenConfigError(
|
|
146
|
+
`Invalid ${label} ${JSON.stringify(specifier)}: must not contain quotes, backslashes or control characters.`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
if (/^\s|\s$/.test(specifier)) {
|
|
150
|
+
throw new CodegenConfigError(
|
|
151
|
+
`Invalid ${label} ${JSON.stringify(specifier)}: must not begin or end with whitespace.`
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
if (HAS_URI_SCHEME.test(specifier.trim())) {
|
|
155
|
+
throw new CodegenConfigError(
|
|
156
|
+
`Invalid ${label} ${JSON.stringify(specifier)}: must be a relative path ("./\u2026", "../\u2026") or a bare package name. URLs are not allowed \u2014 the generated file imports from this specifier.`
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function resolveDeclarationsBaseName(didFile) {
|
|
161
|
+
if (typeof didFile !== "string" || didFile.length === 0) {
|
|
162
|
+
throw new CodegenConfigError(
|
|
163
|
+
`Invalid didFile: expected a non-empty string, received ${didFile === void 0 ? "undefined" : JSON.stringify(didFile)}.`
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
const baseName = import_node_path.default.basename(didFile, ".did");
|
|
167
|
+
if (baseName === "" || baseName === "." || baseName === "..") {
|
|
168
|
+
throw new CodegenConfigError(
|
|
169
|
+
`Invalid didFile ${JSON.stringify(didFile)}: its file name ${JSON.stringify(baseName)} refers to a directory, not a Candid file. Generated declarations are named after the .did file, so this would emit an import of a directory.`
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
assertSafeModuleSpecifier(
|
|
173
|
+
`declarations import derived from didFile ${JSON.stringify(didFile)}`,
|
|
174
|
+
`./declarations/${baseName}`
|
|
175
|
+
);
|
|
176
|
+
return baseName;
|
|
177
|
+
}
|
|
178
|
+
var REACTOR_CLASS_NAMES = [
|
|
179
|
+
"Reactor",
|
|
180
|
+
"DisplayReactor",
|
|
181
|
+
"CandidReactor",
|
|
182
|
+
"CandidDisplayReactor",
|
|
183
|
+
"MetadataDisplayReactor"
|
|
184
|
+
];
|
|
185
|
+
var CODEGEN_TARGETS = ["react", "core"];
|
|
186
|
+
function assertOneOf(label, value, allowed) {
|
|
187
|
+
if (typeof value !== "string" || !allowed.includes(value)) {
|
|
188
|
+
throw new CodegenConfigError(
|
|
189
|
+
`Invalid ${label} ${JSON.stringify(value)}: must be one of ${allowed.map((a) => JSON.stringify(a)).join(", ")}.`
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function realpathAllowingMissing(target) {
|
|
194
|
+
let current = import_node_path.default.resolve(target);
|
|
195
|
+
const missing = [];
|
|
196
|
+
for (; ; ) {
|
|
197
|
+
try {
|
|
198
|
+
return import_node_path.default.join(import_node_fs.default.realpathSync(current), ...missing);
|
|
199
|
+
} catch {
|
|
200
|
+
const parent = import_node_path.default.dirname(current);
|
|
201
|
+
if (parent === current) return import_node_path.default.resolve(target);
|
|
202
|
+
missing.unshift(import_node_path.default.basename(current));
|
|
203
|
+
current = parent;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function assertContainedPath(label, resolved, projectRoot, original = resolved) {
|
|
208
|
+
const relative = import_node_path.default.relative(
|
|
209
|
+
realpathAllowingMissing(projectRoot),
|
|
210
|
+
realpathAllowingMissing(resolved)
|
|
211
|
+
);
|
|
212
|
+
const [firstSegment] = relative.split(/[\\/]/);
|
|
213
|
+
if (firstSegment === ".." || import_node_path.default.isAbsolute(relative)) {
|
|
214
|
+
throw new CodegenConfigError(
|
|
215
|
+
`Invalid ${label} ${JSON.stringify(original)}: resolves to ${JSON.stringify(resolved)}, which is outside the project root ${JSON.stringify(import_node_path.default.resolve(projectRoot))}. Generated output must stay inside the project \u2014 generated directories are deleted and rewritten on every run.`
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function resolveContainedOutDir(label, outDir, projectRoot) {
|
|
220
|
+
if (typeof outDir !== "string" || outDir.length === 0) {
|
|
221
|
+
throw new CodegenConfigError(
|
|
222
|
+
`Invalid ${label}: expected a non-empty string, received ${outDir === void 0 ? "undefined" : JSON.stringify(outDir)}.`
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
const resolved = import_node_path.default.isAbsolute(outDir) ? import_node_path.default.resolve(outDir) : import_node_path.default.resolve(projectRoot, outDir);
|
|
226
|
+
assertContainedPath(label, resolved, projectRoot, outDir);
|
|
227
|
+
return resolved;
|
|
228
|
+
}
|
|
229
|
+
function assertSafeCanisterConfig(options) {
|
|
230
|
+
const {
|
|
231
|
+
name,
|
|
232
|
+
canisterOutDir,
|
|
233
|
+
globalOutDir,
|
|
234
|
+
clientManagerPath,
|
|
235
|
+
projectRoot,
|
|
236
|
+
mode,
|
|
237
|
+
target
|
|
238
|
+
} = options;
|
|
239
|
+
assertSafeCanisterName(name);
|
|
240
|
+
assertSafeModuleSpecifier("clientManagerPath", clientManagerPath);
|
|
241
|
+
if (mode != null) assertOneOf("mode", mode, REACTOR_CLASS_NAMES);
|
|
242
|
+
if (target != null) assertOneOf("target", target, CODEGEN_TARGETS);
|
|
243
|
+
const outDir = canisterOutDir != null ? resolveContainedOutDir(
|
|
244
|
+
`outDir for canister ${JSON.stringify(name)}`,
|
|
245
|
+
canisterOutDir,
|
|
246
|
+
projectRoot
|
|
247
|
+
) : import_node_path.default.join(
|
|
248
|
+
resolveContainedOutDir("outDir", globalOutDir, projectRoot),
|
|
249
|
+
name
|
|
250
|
+
);
|
|
251
|
+
assertContainedPath(
|
|
252
|
+
`output directory for canister ${JSON.stringify(name)}`,
|
|
253
|
+
outDir,
|
|
254
|
+
projectRoot
|
|
255
|
+
);
|
|
256
|
+
return { name, outDir, clientManagerPath };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// src/generators/declarations.ts
|
|
260
|
+
function replaceDirectory(from, to) {
|
|
261
|
+
if (!import_node_fs2.default.existsSync(to)) {
|
|
262
|
+
import_node_fs2.default.renameSync(from, to);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const displaced = import_node_fs2.default.mkdtempSync(
|
|
266
|
+
import_node_path2.default.join(import_node_path2.default.dirname(to), `.${import_node_path2.default.basename(to)}.old-`)
|
|
267
|
+
);
|
|
268
|
+
import_node_fs2.default.rmdirSync(displaced);
|
|
269
|
+
import_node_fs2.default.renameSync(to, displaced);
|
|
270
|
+
try {
|
|
271
|
+
import_node_fs2.default.renameSync(from, to);
|
|
272
|
+
} catch (error) {
|
|
273
|
+
import_node_fs2.default.renameSync(displaced, to);
|
|
274
|
+
throw error;
|
|
275
|
+
}
|
|
276
|
+
import_node_fs2.default.rmSync(displaced, { recursive: true, force: true });
|
|
277
|
+
}
|
|
278
|
+
var HAS_IDL_FACTORY = /\bexport\s+const\s+idlFactory\b/;
|
|
279
|
+
var OWNER_FILE = ".ic-reactor-owner";
|
|
56
280
|
async function generateDeclarations(options) {
|
|
57
281
|
const { didFile, outDir, canisterName } = options;
|
|
58
|
-
|
|
282
|
+
const declarationsDir = import_node_path2.default.join(outDir, "declarations");
|
|
283
|
+
let baseName;
|
|
284
|
+
try {
|
|
285
|
+
baseName = resolveDeclarationsBaseName(didFile);
|
|
286
|
+
} catch (error) {
|
|
287
|
+
if (error instanceof CodegenConfigError) {
|
|
288
|
+
return {
|
|
289
|
+
success: false,
|
|
290
|
+
declarationsDir: "",
|
|
291
|
+
files: [],
|
|
292
|
+
error: `[${canisterName}] ${error.message}`
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
throw error;
|
|
296
|
+
}
|
|
297
|
+
let didStat;
|
|
298
|
+
try {
|
|
299
|
+
didStat = import_node_fs2.default.statSync(didFile);
|
|
300
|
+
} catch {
|
|
59
301
|
return {
|
|
60
302
|
success: false,
|
|
61
303
|
declarationsDir: "",
|
|
@@ -63,25 +305,39 @@ async function generateDeclarations(options) {
|
|
|
63
305
|
error: `DID file not found: ${didFile}`
|
|
64
306
|
};
|
|
65
307
|
}
|
|
66
|
-
|
|
67
|
-
|
|
308
|
+
if (!didStat.isFile()) {
|
|
309
|
+
return {
|
|
310
|
+
success: false,
|
|
311
|
+
declarationsDir: "",
|
|
312
|
+
files: [],
|
|
313
|
+
error: `[${canisterName}] DID path is not a regular file: ${didFile}`
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
let staging;
|
|
68
317
|
try {
|
|
69
|
-
const didContent =
|
|
70
|
-
if (!import_node_fs.default.existsSync(outDir)) {
|
|
71
|
-
import_node_fs.default.mkdirSync(outDir, { recursive: true });
|
|
72
|
-
}
|
|
73
|
-
if (import_node_fs.default.existsSync(declarationsDir)) {
|
|
74
|
-
import_node_fs.default.rmSync(declarationsDir, { recursive: true, force: true });
|
|
75
|
-
}
|
|
76
|
-
import_node_fs.default.mkdirSync(declarationsDir, { recursive: true });
|
|
318
|
+
const didContent = import_node_fs2.default.readFileSync(didFile, "utf-8");
|
|
77
319
|
const jsContent = (0, import_parser.didToJs)(didContent);
|
|
78
320
|
const tsContent = (0, import_parser.didToTs)(didContent);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
321
|
+
if (!HAS_IDL_FACTORY.test(jsContent)) {
|
|
322
|
+
return {
|
|
323
|
+
success: false,
|
|
324
|
+
declarationsDir,
|
|
325
|
+
files: [],
|
|
326
|
+
error: `[${canisterName}] ${didFile} produces no idlFactory, so there is no service to generate against. Point this canister at the .did file that declares its service.`
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
import_node_fs2.default.mkdirSync(outDir, { recursive: true });
|
|
330
|
+
import_node_fs2.default.writeFileSync(import_node_path2.default.join(outDir, OWNER_FILE), `${canisterName}
|
|
331
|
+
`);
|
|
332
|
+
staging = import_node_fs2.default.mkdtempSync(import_node_path2.default.join(outDir, ".declarations.tmp-"));
|
|
333
|
+
const jsPath = import_node_path2.default.join(declarationsDir, `${baseName}.js`);
|
|
334
|
+
const dtsPath = import_node_path2.default.join(declarationsDir, `${baseName}.d.ts`);
|
|
335
|
+
const didCopyPath = import_node_path2.default.join(declarationsDir, `${baseName}.did`);
|
|
336
|
+
import_node_fs2.default.writeFileSync(import_node_path2.default.join(staging, `${baseName}.js`), jsContent);
|
|
337
|
+
import_node_fs2.default.writeFileSync(import_node_path2.default.join(staging, `${baseName}.d.ts`), tsContent);
|
|
338
|
+
import_node_fs2.default.writeFileSync(import_node_path2.default.join(staging, `${baseName}.did`), didContent);
|
|
339
|
+
replaceDirectory(staging, declarationsDir);
|
|
340
|
+
staging = void 0;
|
|
85
341
|
return {
|
|
86
342
|
success: true,
|
|
87
343
|
declarationsDir,
|
|
@@ -99,29 +355,24 @@ async function generateDeclarations(options) {
|
|
|
99
355
|
files: [],
|
|
100
356
|
error: `[${canisterName}] Failed to generate declarations: ${message}`
|
|
101
357
|
};
|
|
358
|
+
} finally {
|
|
359
|
+
if (staging) import_node_fs2.default.rmSync(staging, { recursive: true, force: true });
|
|
102
360
|
}
|
|
103
361
|
}
|
|
104
|
-
function declarationsExist(outDir, canisterName) {
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return (0, import_change_case.camelCase)(str);
|
|
119
|
-
}
|
|
120
|
-
function getReactorName(canisterName) {
|
|
121
|
-
return `${toCamelCase(canisterName)}Reactor`;
|
|
122
|
-
}
|
|
123
|
-
function getServiceTypeName(canisterName) {
|
|
124
|
-
return `${toPascalCase(canisterName)}Service`;
|
|
362
|
+
function declarationsExist(outDir, canisterName, didFile) {
|
|
363
|
+
const declarationsDir = import_node_path2.default.join(outDir, "declarations");
|
|
364
|
+
if (didFile !== void 0) {
|
|
365
|
+
const baseName = import_node_path2.default.basename(didFile, ".did");
|
|
366
|
+
return import_node_fs2.default.existsSync(import_node_path2.default.join(declarationsDir, `${baseName}.d.ts`));
|
|
367
|
+
}
|
|
368
|
+
if (import_node_fs2.default.existsSync(import_node_path2.default.join(declarationsDir, `${canisterName}.d.ts`))) {
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
try {
|
|
372
|
+
return import_node_fs2.default.readdirSync(declarationsDir).some((entry) => entry.endsWith(".d.ts"));
|
|
373
|
+
} catch {
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
125
376
|
}
|
|
126
377
|
|
|
127
378
|
// src/generators/reactor.ts
|
|
@@ -134,6 +385,10 @@ function getReactorClassImportSource(reactorClass, runtimeTarget) {
|
|
|
134
385
|
case "CandidDisplayReactor":
|
|
135
386
|
case "MetadataDisplayReactor":
|
|
136
387
|
return "@ic-reactor/candid";
|
|
388
|
+
default:
|
|
389
|
+
throw new Error(
|
|
390
|
+
`Unknown reactor class ${JSON.stringify(reactorClass)}. Expected one of: Reactor, DisplayReactor, CandidReactor, CandidDisplayReactor, MetadataDisplayReactor.`
|
|
391
|
+
);
|
|
137
392
|
}
|
|
138
393
|
}
|
|
139
394
|
function generateReactorFile(options) {
|
|
@@ -148,7 +403,7 @@ function generateReactorFile(options) {
|
|
|
148
403
|
const pascalName = toPascalCase(canisterName);
|
|
149
404
|
const reactorName = getReactorName(canisterName);
|
|
150
405
|
const serviceName = getServiceTypeName(canisterName);
|
|
151
|
-
const baseName =
|
|
406
|
+
const baseName = resolveDeclarationsBaseName(didFile);
|
|
152
407
|
const declarationsPath = `./declarations/${baseName}`;
|
|
153
408
|
const reactorImportSource = getReactorClassImportSource(
|
|
154
409
|
reactorClass,
|
|
@@ -167,9 +422,9 @@ export const {
|
|
|
167
422
|
useActorMethod: use${pascalName}Method,
|
|
168
423
|
} = createActorHooks(${reactorName})
|
|
169
424
|
` : "";
|
|
170
|
-
return `${runtimeTarget === "react" ? 'import { createActorHooks } from "@ic-reactor/react"\n' : ""}import { ${reactorClass} } from
|
|
171
|
-
import { clientManager } from
|
|
172
|
-
import { idlFactory, type _SERVICE } from
|
|
425
|
+
return `${runtimeTarget === "react" ? 'import { createActorHooks } from "@ic-reactor/react"\n' : ""}import { ${reactorClass} } from ${JSON.stringify(reactorImportSource)}
|
|
426
|
+
import { clientManager } from ${JSON.stringify(clientManagerPath)}
|
|
427
|
+
import { idlFactory, type _SERVICE } from ${JSON.stringify(declarationsPath)}
|
|
173
428
|
|
|
174
429
|
export type ${serviceName} = _SERVICE
|
|
175
430
|
|
|
@@ -185,7 +440,7 @@ export type ${serviceName} = _SERVICE
|
|
|
185
440
|
export const ${reactorName} = new ${reactorClass}<${serviceName}>({
|
|
186
441
|
clientManager,
|
|
187
442
|
idlFactory,
|
|
188
|
-
${canisterIdLine} name:
|
|
443
|
+
${canisterIdLine} name: ${JSON.stringify(canisterName)},
|
|
189
444
|
})${hookExports || "\n"}`;
|
|
190
445
|
}
|
|
191
446
|
function generateReactorEntryFile() {
|
|
@@ -218,8 +473,48 @@ function resolveRuntimeTarget(canisterConfig, globalConfig) {
|
|
|
218
473
|
function normalizeFileContent(content) {
|
|
219
474
|
return content.replace(/\r\n/g, "\n").trim();
|
|
220
475
|
}
|
|
221
|
-
|
|
222
|
-
|
|
476
|
+
var GENERATED_MARKER = "Auto-generated by @ic-reactor/codegen";
|
|
477
|
+
var GENERATED_CANISTER_NAME = /^ {2}name: "([A-Za-z0-9_.-]+)",$/m;
|
|
478
|
+
var EXPORT_STATEMENT = /^export\b.*$/gm;
|
|
479
|
+
function isLegacyGeneratedIndexFile(content, canisterName) {
|
|
480
|
+
if (!content.includes(GENERATED_MARKER)) return false;
|
|
481
|
+
const reactorName = getReactorName(canisterName);
|
|
482
|
+
const serviceName = getServiceTypeName(canisterName);
|
|
483
|
+
if (!content.includes(`export const ${reactorName} = new `)) return false;
|
|
484
|
+
if (!content.includes(`= createActorHooks(${reactorName})`)) return false;
|
|
485
|
+
const allowed = [
|
|
486
|
+
`export type ${serviceName} = _SERVICE`,
|
|
487
|
+
`export const ${reactorName} = new `,
|
|
488
|
+
// Opens the destructured hook block; its members are not export statements.
|
|
489
|
+
"export const {"
|
|
490
|
+
];
|
|
491
|
+
const statements = normalizeFileContent(content).match(EXPORT_STATEMENT) ?? [];
|
|
492
|
+
return statements.every(
|
|
493
|
+
(statement) => allowed.some((prefix) => statement.startsWith(prefix))
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
function backUpFile(filePath) {
|
|
497
|
+
let backupPath = `${filePath}.bak`;
|
|
498
|
+
for (let n = 2; import_node_fs3.default.existsSync(backupPath); n += 1) {
|
|
499
|
+
backupPath = `${filePath}.bak.${n}`;
|
|
500
|
+
}
|
|
501
|
+
import_node_fs3.default.copyFileSync(filePath, backupPath);
|
|
502
|
+
return backupPath;
|
|
503
|
+
}
|
|
504
|
+
function findOutDirOwner(outDir) {
|
|
505
|
+
try {
|
|
506
|
+
const owner = import_node_fs3.default.readFileSync(import_node_path3.default.join(outDir, OWNER_FILE), "utf-8").trim();
|
|
507
|
+
if (owner) return owner;
|
|
508
|
+
} catch {
|
|
509
|
+
}
|
|
510
|
+
let content;
|
|
511
|
+
try {
|
|
512
|
+
content = import_node_fs3.default.readFileSync(import_node_path3.default.join(outDir, "index.generated.ts"), "utf-8");
|
|
513
|
+
} catch {
|
|
514
|
+
return void 0;
|
|
515
|
+
}
|
|
516
|
+
if (!content.includes(GENERATED_MARKER)) return void 0;
|
|
517
|
+
return GENERATED_CANISTER_NAME.exec(content)?.[1];
|
|
223
518
|
}
|
|
224
519
|
function isManagedEntryWrapper(content, expectedEntryContent) {
|
|
225
520
|
return normalizeFileContent(content) === normalizeFileContent(expectedEntryContent);
|
|
@@ -233,8 +528,30 @@ async function runCanisterPipeline(options) {
|
|
|
233
528
|
} = options;
|
|
234
529
|
const { name, didFile, clientManagerPath } = canisterConfig;
|
|
235
530
|
const files = [];
|
|
531
|
+
let validated;
|
|
532
|
+
try {
|
|
533
|
+
validated = assertSafeCanisterConfig({
|
|
534
|
+
name,
|
|
535
|
+
canisterOutDir: canisterConfig.outDir,
|
|
536
|
+
globalOutDir: globalConfig.outDir,
|
|
537
|
+
clientManagerPath: clientManagerPath ?? globalConfig.clientManagerPath ?? "../../clients",
|
|
538
|
+
projectRoot,
|
|
539
|
+
mode: canisterConfig.mode,
|
|
540
|
+
target: canisterConfig.target ?? globalConfig.target
|
|
541
|
+
});
|
|
542
|
+
} catch (err) {
|
|
543
|
+
if (err instanceof CodegenConfigError) {
|
|
544
|
+
return {
|
|
545
|
+
canisterName: typeof name === "string" ? name : String(name),
|
|
546
|
+
success: false,
|
|
547
|
+
files,
|
|
548
|
+
error: err.message
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
throw err;
|
|
552
|
+
}
|
|
236
553
|
const resolvedDidFile = import_node_path3.default.isAbsolute(didFile) ? didFile : import_node_path3.default.resolve(projectRoot, didFile);
|
|
237
|
-
if (!
|
|
554
|
+
if (!import_node_fs3.default.existsSync(resolvedDidFile)) {
|
|
238
555
|
return {
|
|
239
556
|
canisterName: name,
|
|
240
557
|
success: false,
|
|
@@ -242,8 +559,30 @@ async function runCanisterPipeline(options) {
|
|
|
242
559
|
error: `DID file not found: ${resolvedDidFile}`
|
|
243
560
|
};
|
|
244
561
|
}
|
|
245
|
-
|
|
246
|
-
|
|
562
|
+
try {
|
|
563
|
+
resolveDeclarationsBaseName(resolvedDidFile);
|
|
564
|
+
} catch (err) {
|
|
565
|
+
if (err instanceof CodegenConfigError) {
|
|
566
|
+
return {
|
|
567
|
+
canisterName: name,
|
|
568
|
+
success: false,
|
|
569
|
+
files,
|
|
570
|
+
error: `[${name}] ${err.message}`
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
throw err;
|
|
574
|
+
}
|
|
575
|
+
const canisterOutDir = validated.outDir;
|
|
576
|
+
const owner = findOutDirOwner(canisterOutDir);
|
|
577
|
+
if (owner !== void 0 && owner !== name) {
|
|
578
|
+
return {
|
|
579
|
+
canisterName: name,
|
|
580
|
+
success: false,
|
|
581
|
+
files,
|
|
582
|
+
error: `[${name}] Output directory ${canisterOutDir} was generated for canister "${owner}". Two canisters cannot share an outDir \u2014 each run replaces the declarations directory and index.generated.ts, so they would overwrite each other. Give each canister its own "outDir". If you renamed "${owner}" to "${name}", delete that directory and regenerate.`
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
const resolvedClientManagerPath = validated.clientManagerPath;
|
|
247
586
|
try {
|
|
248
587
|
const declResult = await generateDeclarations({
|
|
249
588
|
didFile: resolvedDidFile,
|
|
@@ -288,16 +627,21 @@ async function runCanisterPipeline(options) {
|
|
|
288
627
|
reactorClass
|
|
289
628
|
});
|
|
290
629
|
const entryContent = generateReactorEntryFile();
|
|
291
|
-
|
|
292
|
-
|
|
630
|
+
import_node_fs3.default.mkdirSync(canisterOutDir, { recursive: true });
|
|
631
|
+
import_node_fs3.default.writeFileSync(reactorPath, reactorContent);
|
|
293
632
|
files.push({ success: true, filePath: reactorPath });
|
|
294
|
-
if (!
|
|
295
|
-
|
|
633
|
+
if (!import_node_fs3.default.existsSync(entryPath)) {
|
|
634
|
+
import_node_fs3.default.writeFileSync(entryPath, entryContent);
|
|
296
635
|
files.push({ success: true, filePath: entryPath });
|
|
297
636
|
} else {
|
|
298
|
-
const existingEntryContent =
|
|
299
|
-
if (
|
|
300
|
-
|
|
637
|
+
const existingEntryContent = import_node_fs3.default.readFileSync(entryPath, "utf-8");
|
|
638
|
+
if (isManagedEntryWrapper(existingEntryContent, entryContent)) {
|
|
639
|
+
import_node_fs3.default.writeFileSync(entryPath, entryContent);
|
|
640
|
+
files.push({ success: true, filePath: entryPath });
|
|
641
|
+
} else if (isLegacyGeneratedIndexFile(existingEntryContent, name)) {
|
|
642
|
+
const backupPath = backUpFile(entryPath);
|
|
643
|
+
import_node_fs3.default.writeFileSync(entryPath, entryContent);
|
|
644
|
+
files.push({ success: true, filePath: backupPath });
|
|
301
645
|
files.push({ success: true, filePath: entryPath });
|
|
302
646
|
} else {
|
|
303
647
|
files.push({ success: true, filePath: entryPath, skipped: true });
|
|
@@ -323,40 +667,6 @@ async function runCanisterPipeline(options) {
|
|
|
323
667
|
};
|
|
324
668
|
}
|
|
325
669
|
|
|
326
|
-
// src/parser.ts
|
|
327
|
-
var import_parser2 = require("@ic-reactor/parser");
|
|
328
|
-
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
329
|
-
function extractMethods(didContent) {
|
|
330
|
-
try {
|
|
331
|
-
const jsContent = (0, import_parser2.didToJs)(didContent);
|
|
332
|
-
const methods = [];
|
|
333
|
-
const serviceMatch = /IDL\.Service\(\{([\s\S]*?)\}\)/.exec(jsContent);
|
|
334
|
-
if (!serviceMatch) return methods;
|
|
335
|
-
const serviceBody = serviceMatch[1];
|
|
336
|
-
const methodRegex = /['"]([\w]+)['"]\s*:\s*IDL\.Func\(\s*\[(.*?)\],\s*\[.*?\],\s*\[(.*?)\]\)/g;
|
|
337
|
-
let match;
|
|
338
|
-
while ((match = methodRegex.exec(serviceBody)) !== null) {
|
|
339
|
-
const [, name, args, annotations] = match;
|
|
340
|
-
methods.push({
|
|
341
|
-
name,
|
|
342
|
-
type: annotations.includes("'query'") ? "query" : "mutation",
|
|
343
|
-
hasArgs: args.trim().length > 0
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
return methods;
|
|
347
|
-
} catch (error) {
|
|
348
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
349
|
-
throw new Error(`Failed to parse Candid: ${msg}`);
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
function parseDIDFile(didFilePath) {
|
|
353
|
-
if (!import_node_fs3.default.existsSync(didFilePath)) {
|
|
354
|
-
throw new Error(`DID file not found: ${didFilePath}`);
|
|
355
|
-
}
|
|
356
|
-
const content = import_node_fs3.default.readFileSync(didFilePath, "utf-8");
|
|
357
|
-
return extractMethods(content);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
670
|
// src/generators/client.ts
|
|
361
671
|
function generateClientFile(options = {}) {
|
|
362
672
|
const { queryClientPath } = options;
|
|
@@ -377,620 +687,26 @@ export const clientManager = new ClientManager({
|
|
|
377
687
|
})
|
|
378
688
|
`;
|
|
379
689
|
}
|
|
380
|
-
|
|
381
|
-
// src/metadata-rules.json
|
|
382
|
-
var metadata_rules_default = {
|
|
383
|
-
defaultValidationMessages: {
|
|
384
|
-
minimum: {
|
|
385
|
-
template: "Must be at least {value}"
|
|
386
|
-
},
|
|
387
|
-
maximum: {
|
|
388
|
-
template: "Must be at most {value}"
|
|
389
|
-
},
|
|
390
|
-
minLength: {
|
|
391
|
-
template: "Must be at least {value} character{plural}"
|
|
392
|
-
},
|
|
393
|
-
maxLength: {
|
|
394
|
-
template: "Must be at most {value} character{plural}"
|
|
395
|
-
}
|
|
396
|
-
},
|
|
397
|
-
email: {
|
|
398
|
-
helper: "email",
|
|
399
|
-
regex: "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$",
|
|
400
|
-
jsonSchemaFormat: "email",
|
|
401
|
-
errorMessage: "Must be a valid email address"
|
|
402
|
-
},
|
|
403
|
-
"date-time": {
|
|
404
|
-
helper: "dateTime",
|
|
405
|
-
regex: "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|[+-](?:[01]\\d|2[0-3]):[0-5]\\d))$",
|
|
406
|
-
jsonSchemaFormat: "date-time",
|
|
407
|
-
errorMessage: "Must be a valid ISO datetime"
|
|
408
|
-
},
|
|
409
|
-
datetime: {
|
|
410
|
-
helper: "datetime",
|
|
411
|
-
regex: "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|[+-](?:[01]\\d|2[0-3]):[0-5]\\d))$",
|
|
412
|
-
jsonSchemaFormat: "date-time",
|
|
413
|
-
errorMessage: "Must be a valid ISO datetime"
|
|
414
|
-
},
|
|
415
|
-
date: {
|
|
416
|
-
helper: "date",
|
|
417
|
-
regex: "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
|
|
418
|
-
jsonSchemaFormat: "date",
|
|
419
|
-
errorMessage: "Must be a valid ISO date"
|
|
420
|
-
},
|
|
421
|
-
time: {
|
|
422
|
-
helper: "time",
|
|
423
|
-
regex: "^(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?$",
|
|
424
|
-
errorMessage: "Must be a valid ISO time"
|
|
425
|
-
},
|
|
426
|
-
duration: {
|
|
427
|
-
helper: "duration",
|
|
428
|
-
regex: "^P(?:(\\d+W)|(?!.*W)(?=\\d|T\\d)(\\d+Y)?(\\d+M)?(\\d+D)?(T(?=\\d)(\\d+H)?(\\d+M)?(\\d+([.,]\\d+)?S)?)?)$",
|
|
429
|
-
jsonSchemaFormat: "duration",
|
|
430
|
-
errorMessage: "Must be a valid ISO duration"
|
|
431
|
-
},
|
|
432
|
-
url: {
|
|
433
|
-
helper: "url",
|
|
434
|
-
regex: "^[a-zA-Z][a-zA-Z\\d+.-]*:.+",
|
|
435
|
-
jsonSchemaFormat: "uri",
|
|
436
|
-
errorMessage: "Must be a valid URL"
|
|
437
|
-
},
|
|
438
|
-
uri: {
|
|
439
|
-
helper: "uri",
|
|
440
|
-
regex: "^[a-zA-Z][a-zA-Z\\d+.-]*:.+",
|
|
441
|
-
jsonSchemaFormat: "uri",
|
|
442
|
-
errorMessage: "Must be a valid URI"
|
|
443
|
-
},
|
|
444
|
-
httpsUrl: {
|
|
445
|
-
helper: "httpsUrl",
|
|
446
|
-
regex: "^https://.+",
|
|
447
|
-
jsonSchemaFormat: "uri",
|
|
448
|
-
errorMessage: "Must be a valid HTTPS URL"
|
|
449
|
-
},
|
|
450
|
-
ipv4: {
|
|
451
|
-
helper: "ipv4",
|
|
452
|
-
regex: "^(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(?:\\.|$)){4}$",
|
|
453
|
-
jsonSchemaFormat: "ipv4",
|
|
454
|
-
errorMessage: "Must be a valid IPv4 address"
|
|
455
|
-
},
|
|
456
|
-
ipv6: {
|
|
457
|
-
helper: "ipv6",
|
|
458
|
-
regex: "^((?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}|::1|::|(?:[0-9A-Fa-f]{1,4}:){1,7}:|(?:[0-9A-Fa-f]{1,4}:){1,6}:[0-9A-Fa-f]{1,4}|(?:[0-9A-Fa-f]{1,4}:){1,5}(?::[0-9A-Fa-f]{1,4}){1,2}|(?:[0-9A-Fa-f]{1,4}:){1,4}(?::[0-9A-Fa-f]{1,4}){1,3}|(?:[0-9A-Fa-f]{1,4}:){1,3}(?::[0-9A-Fa-f]{1,4}){1,4}|(?:[0-9A-Fa-f]{1,4}:){1,2}(?::[0-9A-Fa-f]{1,4}){1,5}|[0-9A-Fa-f]{1,4}:(?:(?::[0-9A-Fa-f]{1,4}){1,6}))$",
|
|
459
|
-
jsonSchemaFormat: "ipv6",
|
|
460
|
-
errorMessage: "Must be a valid IPv6 address"
|
|
461
|
-
},
|
|
462
|
-
uuid: {
|
|
463
|
-
helper: "uuid",
|
|
464
|
-
regex: "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$",
|
|
465
|
-
jsonSchemaFormat: "uuid",
|
|
466
|
-
errorMessage: "Must be a valid UUID"
|
|
467
|
-
},
|
|
468
|
-
guid: {
|
|
469
|
-
helper: "guid",
|
|
470
|
-
regex: "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$",
|
|
471
|
-
jsonSchemaFormat: "uuid",
|
|
472
|
-
errorMessage: "Must be a valid GUID"
|
|
473
|
-
},
|
|
474
|
-
base64: {
|
|
475
|
-
helper: "base64",
|
|
476
|
-
regex: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$",
|
|
477
|
-
contentEncoding: "base64",
|
|
478
|
-
errorMessage: "Must be valid base64"
|
|
479
|
-
},
|
|
480
|
-
base64url: {
|
|
481
|
-
helper: "base64url",
|
|
482
|
-
regex: "^[A-Za-z0-9_-]+$",
|
|
483
|
-
errorMessage: "Must be valid base64url"
|
|
484
|
-
},
|
|
485
|
-
cuid: {
|
|
486
|
-
helper: "cuid",
|
|
487
|
-
regex: "^c[a-z0-9]{24}$",
|
|
488
|
-
errorMessage: "Must be a valid CUID"
|
|
489
|
-
},
|
|
490
|
-
cuid2: {
|
|
491
|
-
helper: "cuid2",
|
|
492
|
-
regex: "^[a-z][a-z0-9]*$",
|
|
493
|
-
errorMessage: "Must be a valid CUID2"
|
|
494
|
-
},
|
|
495
|
-
ulid: {
|
|
496
|
-
helper: "ulid",
|
|
497
|
-
regex: "^[0-9A-HJKMNP-TV-Z]{26}$",
|
|
498
|
-
errorMessage: "Must be a valid ULID"
|
|
499
|
-
},
|
|
500
|
-
nanoid: {
|
|
501
|
-
helper: "nanoid",
|
|
502
|
-
regex: "^[A-Za-z0-9_-]{21}$",
|
|
503
|
-
errorMessage: "Must be a valid nanoid"
|
|
504
|
-
},
|
|
505
|
-
emoji: {
|
|
506
|
-
helper: "emoji",
|
|
507
|
-
regex: "^\\p{Extended_Pictographic}+$",
|
|
508
|
-
errorMessage: "Must contain only emoji characters"
|
|
509
|
-
},
|
|
510
|
-
cidrv4: {
|
|
511
|
-
helper: "cidrv4",
|
|
512
|
-
regex: "^(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)/(?:3[0-2]|[12]?\\d)$",
|
|
513
|
-
errorMessage: "Must be a valid IPv4 CIDR range"
|
|
514
|
-
},
|
|
515
|
-
cidrv6: {
|
|
516
|
-
helper: "cidrv6",
|
|
517
|
-
regex: "^[0-9A-Fa-f:]+/(?:12[0-8]|1[01]\\d|\\d?\\d)$",
|
|
518
|
-
errorMessage: "Must be a valid IPv6 CIDR range"
|
|
519
|
-
},
|
|
520
|
-
mac: {
|
|
521
|
-
helper: "mac",
|
|
522
|
-
regex: "^(?:[0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$",
|
|
523
|
-
errorMessage: "Must be a valid MAC address"
|
|
524
|
-
}
|
|
525
|
-
};
|
|
526
|
-
|
|
527
|
-
// src/metadata.ts
|
|
528
|
-
var metadataRulesFile = metadata_rules_default;
|
|
529
|
-
var defaultValidationMessages = metadataRulesFile.defaultValidationMessages ?? {};
|
|
530
|
-
var rawRuleEntries = Object.entries(metadata_rules_default).filter(
|
|
531
|
-
([type]) => type !== "defaultValidationMessages"
|
|
532
|
-
);
|
|
533
|
-
var BUILT_IN_JSDOC_FORMAT_TYPES = Object.fromEntries(
|
|
534
|
-
rawRuleEntries.map(([type, rule]) => [
|
|
535
|
-
type,
|
|
536
|
-
{
|
|
537
|
-
regex: rule.regex,
|
|
538
|
-
jsonSchemaFormat: rule.jsonSchemaFormat,
|
|
539
|
-
contentEncoding: rule.contentEncoding,
|
|
540
|
-
errorMessage: rule.errorMessage
|
|
541
|
-
}
|
|
542
|
-
])
|
|
543
|
-
);
|
|
544
|
-
var BUILT_IN_FORMAT_HELPERS = Object.fromEntries(
|
|
545
|
-
rawRuleEntries.filter(([, rule]) => rule.helper).map(([type, rule]) => [type, rule.helper])
|
|
546
|
-
);
|
|
547
|
-
function normalizeFormatDefinition(definition) {
|
|
548
|
-
if (!definition) return void 0;
|
|
549
|
-
return typeof definition === "string" ? { regex: definition } : definition;
|
|
550
|
-
}
|
|
551
|
-
function formatDefinitionFor(type, options) {
|
|
552
|
-
const builtIn = BUILT_IN_JSDOC_FORMAT_TYPES[type];
|
|
553
|
-
const custom = normalizeFormatDefinition(
|
|
554
|
-
options.customJSDocFormatTypes?.[type]
|
|
555
|
-
);
|
|
556
|
-
if (!custom) return builtIn;
|
|
557
|
-
return {
|
|
558
|
-
...builtIn,
|
|
559
|
-
...custom,
|
|
560
|
-
errorMessage: custom.errorMessage ?? builtIn?.errorMessage
|
|
561
|
-
};
|
|
562
|
-
}
|
|
563
|
-
function stripUndefined(value) {
|
|
564
|
-
return Object.fromEntries(
|
|
565
|
-
Object.entries(value).filter(([, entry]) => entry !== void 0)
|
|
566
|
-
);
|
|
567
|
-
}
|
|
568
|
-
function defaultBoundMessage(kind, value) {
|
|
569
|
-
const template = defaultValidationMessages[kind]?.template ?? (kind === "minimum" ? "Must be at least {value}" : kind === "maximum" ? "Must be at most {value}" : kind === "minLength" ? "Must be at least {value} character{plural}" : "Must be at most {value} character{plural}");
|
|
570
|
-
return template.replace("{value}", value).replace("{plural}", value === "1" ? "" : "s");
|
|
571
|
-
}
|
|
572
|
-
function withDefaultBoundMessage(bound, kind) {
|
|
573
|
-
if (!bound || bound.message !== void 0) return bound;
|
|
574
|
-
return {
|
|
575
|
-
...bound,
|
|
576
|
-
message: defaultBoundMessage(kind, bound.value)
|
|
577
|
-
};
|
|
578
|
-
}
|
|
579
|
-
function normalizeValidationMetadata(validation, options) {
|
|
580
|
-
const normalized = {
|
|
581
|
-
...validation,
|
|
582
|
-
minimum: withDefaultBoundMessage(validation.minimum, "minimum"),
|
|
583
|
-
maximum: withDefaultBoundMessage(validation.maximum, "maximum"),
|
|
584
|
-
minLength: withDefaultBoundMessage(validation.minLength, "minLength"),
|
|
585
|
-
maxLength: withDefaultBoundMessage(validation.maxLength, "maxLength")
|
|
586
|
-
};
|
|
587
|
-
const format = validation.format;
|
|
588
|
-
const formatDefinition = format ? formatDefinitionFor(format.type, options) : void 0;
|
|
589
|
-
if (format && formatDefinition) {
|
|
590
|
-
normalized.format = stripUndefined({
|
|
591
|
-
...format,
|
|
592
|
-
regex: formatDefinition.regex,
|
|
593
|
-
jsonSchemaFormat: formatDefinition.jsonSchemaFormat,
|
|
594
|
-
contentEncoding: formatDefinition.contentEncoding,
|
|
595
|
-
errorMessage: format.message ?? formatDefinition.errorMessage
|
|
596
|
-
});
|
|
597
|
-
} else if (format) {
|
|
598
|
-
normalized.format = format;
|
|
599
|
-
}
|
|
600
|
-
return normalized;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
// src/renderer.ts
|
|
604
|
-
var reservedWords = /* @__PURE__ */ new Set([
|
|
605
|
-
"break",
|
|
606
|
-
"case",
|
|
607
|
-
"catch",
|
|
608
|
-
"class",
|
|
609
|
-
"const",
|
|
610
|
-
"continue",
|
|
611
|
-
"debugger",
|
|
612
|
-
"default",
|
|
613
|
-
"delete",
|
|
614
|
-
"do",
|
|
615
|
-
"else",
|
|
616
|
-
"export",
|
|
617
|
-
"extends",
|
|
618
|
-
"false",
|
|
619
|
-
"finally",
|
|
620
|
-
"for",
|
|
621
|
-
"function",
|
|
622
|
-
"if",
|
|
623
|
-
"import",
|
|
624
|
-
"in",
|
|
625
|
-
"instanceof",
|
|
626
|
-
"new",
|
|
627
|
-
"null",
|
|
628
|
-
"return",
|
|
629
|
-
"super",
|
|
630
|
-
"switch",
|
|
631
|
-
"this",
|
|
632
|
-
"throw",
|
|
633
|
-
"true",
|
|
634
|
-
"try",
|
|
635
|
-
"typeof",
|
|
636
|
-
"var",
|
|
637
|
-
"void",
|
|
638
|
-
"while",
|
|
639
|
-
"with",
|
|
640
|
-
"yield",
|
|
641
|
-
"let",
|
|
642
|
-
"package",
|
|
643
|
-
"private",
|
|
644
|
-
"protected",
|
|
645
|
-
"public",
|
|
646
|
-
"static"
|
|
647
|
-
]);
|
|
648
|
-
function isValidIdentifier(name) {
|
|
649
|
-
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) && !reservedWords.has(name);
|
|
650
|
-
}
|
|
651
|
-
function assertIdentifier(name, label) {
|
|
652
|
-
if (!isValidIdentifier(name)) {
|
|
653
|
-
throw new Error(`${label} must be a valid TypeScript identifier: ${name}`);
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
function propertyName(name) {
|
|
657
|
-
return isValidIdentifier(name) ? name : JSON.stringify(name);
|
|
658
|
-
}
|
|
659
|
-
function normalizeOptions(options = {}) {
|
|
660
|
-
return typeof options === "string" ? { serviceExportName: options } : options;
|
|
661
|
-
}
|
|
662
|
-
function toServiceExportName(canisterName) {
|
|
663
|
-
return canisterName.replace(/[-\s]+/g, "_").toUpperCase();
|
|
664
|
-
}
|
|
665
|
-
function resolveServiceExportName(options, declaredTypeNames) {
|
|
666
|
-
if (options.serviceExportName) return options.serviceExportName;
|
|
667
|
-
if (options.canisterName) {
|
|
668
|
-
let name = toServiceExportName(options.canisterName);
|
|
669
|
-
if (declaredTypeNames.has(name)) {
|
|
670
|
-
name = `${name}_SERVICE`;
|
|
671
|
-
}
|
|
672
|
-
return name;
|
|
673
|
-
}
|
|
674
|
-
return "_SERVICE";
|
|
675
|
-
}
|
|
676
|
-
function hasMetadata(metadata) {
|
|
677
|
-
return metadata != null && Object.keys(metadata).length > 0;
|
|
678
|
-
}
|
|
679
|
-
function stripUndefined2(value) {
|
|
680
|
-
return Object.fromEntries(
|
|
681
|
-
Object.entries(value).filter(([, entry]) => entry !== void 0)
|
|
682
|
-
);
|
|
683
|
-
}
|
|
684
|
-
function isEmptyObject(value) {
|
|
685
|
-
return value != null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 0;
|
|
686
|
-
}
|
|
687
|
-
function textFormatHelperFor(expression, metadata, options) {
|
|
688
|
-
const format = metadata.validation?.format;
|
|
689
|
-
if (!format || expression !== "c.text()") return void 0;
|
|
690
|
-
if (options.customJSDocFormatTypes?.[format.type]) {
|
|
691
|
-
return void 0;
|
|
692
|
-
}
|
|
693
|
-
return BUILT_IN_FORMAT_HELPERS[format.type];
|
|
694
|
-
}
|
|
695
|
-
function hasOnlyDescriptionDocs(docs, description) {
|
|
696
|
-
return docs != null && description != null && docs.length === 1 && docs[0] === description;
|
|
697
|
-
}
|
|
698
|
-
function metadataForRender(metadata, options) {
|
|
699
|
-
if (!metadata.validation) {
|
|
700
|
-
return metadata;
|
|
701
|
-
}
|
|
702
|
-
return {
|
|
703
|
-
...metadata,
|
|
704
|
-
validation: normalizeValidationMetadata(metadata.validation, {
|
|
705
|
-
customJSDocFormatTypes: options.customJSDocFormatTypes
|
|
706
|
-
})
|
|
707
|
-
};
|
|
708
|
-
}
|
|
709
|
-
function applyMetadata(expression, metadata, options) {
|
|
710
|
-
if (!hasMetadata(metadata)) return expression;
|
|
711
|
-
const textFormatHelper = textFormatHelperFor(expression, metadata, options);
|
|
712
|
-
const textFormatMessage = metadata.validation?.format?.message;
|
|
713
|
-
const renderedMetadata = metadataForRender(metadata, options);
|
|
714
|
-
const { description, ...metadataRest } = renderedMetadata;
|
|
715
|
-
const rest = { ...metadataRest };
|
|
716
|
-
let result = textFormatHelper ? `c.${textFormatHelper}(${textFormatMessage ? JSON.stringify(textFormatMessage) : ""})` : expression;
|
|
717
|
-
if (textFormatHelper) {
|
|
718
|
-
delete rest.docs;
|
|
719
|
-
if (rest.validation) {
|
|
720
|
-
const { format: _format, ...validationRest } = rest.validation;
|
|
721
|
-
rest.validation = stripUndefined2(validationRest);
|
|
722
|
-
if (isEmptyObject(rest.validation)) {
|
|
723
|
-
delete rest.validation;
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
} else if (hasOnlyDescriptionDocs(rest.docs, description)) {
|
|
727
|
-
delete rest.docs;
|
|
728
|
-
}
|
|
729
|
-
if (description) {
|
|
730
|
-
result += `.describe(${JSON.stringify(description)})`;
|
|
731
|
-
}
|
|
732
|
-
if (Object.keys(rest).length > 0) {
|
|
733
|
-
result += `.meta(${JSON.stringify(rest)})`;
|
|
734
|
-
}
|
|
735
|
-
return result;
|
|
736
|
-
}
|
|
737
|
-
function getReferencedNames(type) {
|
|
738
|
-
const refs = [];
|
|
739
|
-
function visit(node) {
|
|
740
|
-
switch (node.kind) {
|
|
741
|
-
case "reference":
|
|
742
|
-
refs.push(node.name);
|
|
743
|
-
break;
|
|
744
|
-
case "opt":
|
|
745
|
-
case "vec":
|
|
746
|
-
visit(node.type);
|
|
747
|
-
break;
|
|
748
|
-
case "record":
|
|
749
|
-
case "variant":
|
|
750
|
-
for (const field of node.fields) {
|
|
751
|
-
visit(field.type);
|
|
752
|
-
}
|
|
753
|
-
break;
|
|
754
|
-
case "tuple":
|
|
755
|
-
for (const item of node.types) {
|
|
756
|
-
visit(item);
|
|
757
|
-
}
|
|
758
|
-
break;
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
visit(type);
|
|
762
|
-
return refs;
|
|
763
|
-
}
|
|
764
|
-
function sortDeclarations(declarations) {
|
|
765
|
-
const sorted = [];
|
|
766
|
-
const visited = /* @__PURE__ */ new Set();
|
|
767
|
-
const visiting = [];
|
|
768
|
-
const declarationByName = new Map(
|
|
769
|
-
declarations.map((decl) => [decl.name, decl])
|
|
770
|
-
);
|
|
771
|
-
function visit(name) {
|
|
772
|
-
if (visited.has(name)) return;
|
|
773
|
-
const cycleStart = visiting.indexOf(name);
|
|
774
|
-
if (cycleStart !== -1) {
|
|
775
|
-
const cycle = [...visiting.slice(cycleStart), name].join(" -> ");
|
|
776
|
-
throw new Error(`Recursive Candid types are not supported yet: ${cycle}`);
|
|
777
|
-
}
|
|
778
|
-
const declaration = declarationByName.get(name);
|
|
779
|
-
if (!declaration) return;
|
|
780
|
-
visiting.push(name);
|
|
781
|
-
for (const dependency of getReferencedNames(declaration.type)) {
|
|
782
|
-
visit(dependency);
|
|
783
|
-
}
|
|
784
|
-
visiting.pop();
|
|
785
|
-
visited.add(name);
|
|
786
|
-
sorted.push(declaration);
|
|
787
|
-
}
|
|
788
|
-
for (const declaration of declarations) {
|
|
789
|
-
visit(declaration.name);
|
|
790
|
-
}
|
|
791
|
-
return sorted;
|
|
792
|
-
}
|
|
793
|
-
function renderType(type, indent = "", options = {}) {
|
|
794
|
-
const nextIndent = `${indent} `;
|
|
795
|
-
let expression;
|
|
796
|
-
switch (type.kind) {
|
|
797
|
-
case "null":
|
|
798
|
-
expression = "c.null()";
|
|
799
|
-
break;
|
|
800
|
-
case "bool":
|
|
801
|
-
expression = "c.bool()";
|
|
802
|
-
break;
|
|
803
|
-
case "nat":
|
|
804
|
-
expression = "c.nat()";
|
|
805
|
-
break;
|
|
806
|
-
case "int":
|
|
807
|
-
expression = "c.int()";
|
|
808
|
-
break;
|
|
809
|
-
case "nat8":
|
|
810
|
-
expression = "c.nat8()";
|
|
811
|
-
break;
|
|
812
|
-
case "nat16":
|
|
813
|
-
expression = "c.nat16()";
|
|
814
|
-
break;
|
|
815
|
-
case "nat32":
|
|
816
|
-
expression = "c.nat32()";
|
|
817
|
-
break;
|
|
818
|
-
case "nat64":
|
|
819
|
-
expression = "c.nat64()";
|
|
820
|
-
break;
|
|
821
|
-
case "int8":
|
|
822
|
-
expression = "c.int8()";
|
|
823
|
-
break;
|
|
824
|
-
case "int16":
|
|
825
|
-
expression = "c.int16()";
|
|
826
|
-
break;
|
|
827
|
-
case "int32":
|
|
828
|
-
expression = "c.int32()";
|
|
829
|
-
break;
|
|
830
|
-
case "int64":
|
|
831
|
-
expression = "c.int64()";
|
|
832
|
-
break;
|
|
833
|
-
case "float32":
|
|
834
|
-
expression = "c.float32()";
|
|
835
|
-
break;
|
|
836
|
-
case "float64":
|
|
837
|
-
expression = "c.float64()";
|
|
838
|
-
break;
|
|
839
|
-
case "text":
|
|
840
|
-
expression = "c.text()";
|
|
841
|
-
break;
|
|
842
|
-
case "reserved":
|
|
843
|
-
expression = "c.reserved()";
|
|
844
|
-
break;
|
|
845
|
-
case "empty":
|
|
846
|
-
expression = "c.empty()";
|
|
847
|
-
break;
|
|
848
|
-
case "principal":
|
|
849
|
-
expression = "c.principal()";
|
|
850
|
-
break;
|
|
851
|
-
case "blob":
|
|
852
|
-
expression = "c.blob()";
|
|
853
|
-
break;
|
|
854
|
-
case "reference":
|
|
855
|
-
assertIdentifier(type.name, "Type reference");
|
|
856
|
-
expression = type.name;
|
|
857
|
-
break;
|
|
858
|
-
case "opt":
|
|
859
|
-
expression = `c.opt(${renderType(type.type, indent, options)})`;
|
|
860
|
-
break;
|
|
861
|
-
case "vec":
|
|
862
|
-
expression = `c.vec(${renderType(type.type, indent, options)})`;
|
|
863
|
-
break;
|
|
864
|
-
case "record": {
|
|
865
|
-
if (type.fields.length === 0) {
|
|
866
|
-
expression = "c.record({})";
|
|
867
|
-
} else {
|
|
868
|
-
const fields = type.fields.map((field) => {
|
|
869
|
-
const fieldExpression = applyMetadata(
|
|
870
|
-
renderType(field.type, nextIndent, options),
|
|
871
|
-
field.metadata,
|
|
872
|
-
options
|
|
873
|
-
);
|
|
874
|
-
return `${nextIndent}${propertyName(field.name)}: ${fieldExpression},`;
|
|
875
|
-
}).join("\n");
|
|
876
|
-
expression = `c.record({
|
|
877
|
-
${fields}
|
|
878
|
-
${indent}})`;
|
|
879
|
-
}
|
|
880
|
-
break;
|
|
881
|
-
}
|
|
882
|
-
case "variant": {
|
|
883
|
-
if (type.fields.length === 0) {
|
|
884
|
-
expression = "c.variant({})";
|
|
885
|
-
} else {
|
|
886
|
-
const fields = type.fields.map((field) => {
|
|
887
|
-
const fieldExpression = applyMetadata(
|
|
888
|
-
renderType(field.type, nextIndent, options),
|
|
889
|
-
field.metadata,
|
|
890
|
-
options
|
|
891
|
-
);
|
|
892
|
-
return `${nextIndent}${propertyName(field.name)}: ${fieldExpression},`;
|
|
893
|
-
}).join("\n");
|
|
894
|
-
expression = `c.variant({
|
|
895
|
-
${fields}
|
|
896
|
-
${indent}})`;
|
|
897
|
-
}
|
|
898
|
-
break;
|
|
899
|
-
}
|
|
900
|
-
case "tuple":
|
|
901
|
-
expression = `c.tuple([${type.types.map((item) => renderType(item, indent, options)).join(", ")}])`;
|
|
902
|
-
break;
|
|
903
|
-
case "func":
|
|
904
|
-
case "service":
|
|
905
|
-
case "class":
|
|
906
|
-
case "unknown":
|
|
907
|
-
case "knot":
|
|
908
|
-
case "future":
|
|
909
|
-
expression = `/* c.${type.kind} is not supported */ c.reserved()`;
|
|
910
|
-
break;
|
|
911
|
-
}
|
|
912
|
-
return applyMetadata(expression, type.metadata, options);
|
|
913
|
-
}
|
|
914
|
-
function renderMethodReturn(method, options) {
|
|
915
|
-
if (method.mode === "oneway") return "";
|
|
916
|
-
if (method.returns.length === 0) return "";
|
|
917
|
-
if (method.returns.length === 1) {
|
|
918
|
-
return `, ${renderType(method.returns[0], " ", options)}`;
|
|
919
|
-
}
|
|
920
|
-
return `, [${method.returns.map((returnType) => renderType(returnType, " ", options)).join(", ")}]`;
|
|
921
|
-
}
|
|
922
|
-
function generateCodecDeclarations(schema, optionsOrServiceExportName = {}) {
|
|
923
|
-
const options = normalizeOptions(optionsOrServiceExportName);
|
|
924
|
-
const lines = ['import { c } from "@ic-reactor/cod"', ""];
|
|
925
|
-
for (const declaration of sortDeclarations(schema.types)) {
|
|
926
|
-
assertIdentifier(declaration.name, "Type declaration name");
|
|
927
|
-
lines.push(
|
|
928
|
-
`export const ${declaration.name} = ${applyMetadata(
|
|
929
|
-
renderType(declaration.type, "", options),
|
|
930
|
-
declaration.metadata,
|
|
931
|
-
options
|
|
932
|
-
)}`
|
|
933
|
-
);
|
|
934
|
-
lines.push(
|
|
935
|
-
`export type ${declaration.name} = c.infer<typeof ${declaration.name}>`
|
|
936
|
-
);
|
|
937
|
-
lines.push("");
|
|
938
|
-
}
|
|
939
|
-
if (schema.service) {
|
|
940
|
-
const includeCompatibilityExports = options.includeCompatibilityExports ?? false;
|
|
941
|
-
const declaredTypeNames = new Set(schema.types.map((t) => t.name));
|
|
942
|
-
const serviceExportName = resolveServiceExportName(
|
|
943
|
-
options,
|
|
944
|
-
declaredTypeNames
|
|
945
|
-
);
|
|
946
|
-
assertIdentifier(serviceExportName, "Service export name");
|
|
947
|
-
const methods = schema.service.methods.map((method) => {
|
|
948
|
-
const args = method.args.map((arg) => renderType(arg, " ", options)).join(", ");
|
|
949
|
-
const methodExpression = `c.${method.mode}([${args}]${renderMethodReturn(
|
|
950
|
-
method,
|
|
951
|
-
options
|
|
952
|
-
)})`;
|
|
953
|
-
return ` ${propertyName(method.name)}: ${applyMetadata(
|
|
954
|
-
methodExpression,
|
|
955
|
-
method.metadata,
|
|
956
|
-
options
|
|
957
|
-
)},`;
|
|
958
|
-
}).join("\n");
|
|
959
|
-
const serviceExpression = methods.length > 0 ? `c.service({
|
|
960
|
-
${methods}
|
|
961
|
-
})` : "c.service({})";
|
|
962
|
-
lines.push(
|
|
963
|
-
`export const ${serviceExportName} = ${applyMetadata(
|
|
964
|
-
serviceExpression,
|
|
965
|
-
schema.service.metadata,
|
|
966
|
-
options
|
|
967
|
-
)}`
|
|
968
|
-
);
|
|
969
|
-
lines.push("");
|
|
970
|
-
if (includeCompatibilityExports) {
|
|
971
|
-
lines.push(`export const idlFactory = ${serviceExportName}.idlFactory`);
|
|
972
|
-
lines.push(
|
|
973
|
-
`export type _SERVICE = c.ServiceOf<typeof ${serviceExportName}>`
|
|
974
|
-
);
|
|
975
|
-
lines.push("");
|
|
976
|
-
lines.push(`export const manifest = ${serviceExportName}.manifest()`);
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
return `${lines.join("\n").trimEnd()}
|
|
980
|
-
`;
|
|
981
|
-
}
|
|
982
690
|
// Annotate the CommonJS export names for ESM import in node:
|
|
983
691
|
0 && (module.exports = {
|
|
692
|
+
CANISTER_NAME_PATTERN,
|
|
693
|
+
CODEGEN_TARGETS,
|
|
694
|
+
CodegenConfigError,
|
|
695
|
+
REACTOR_CLASS_NAMES,
|
|
696
|
+
assertContainedPath,
|
|
697
|
+
assertOneOf,
|
|
698
|
+
assertSafeCanisterConfig,
|
|
699
|
+
assertSafeCanisterName,
|
|
700
|
+
assertSafeModuleSpecifier,
|
|
984
701
|
declarationsExist,
|
|
985
|
-
extractMethods,
|
|
986
702
|
generateClientFile,
|
|
987
|
-
generateCodecDeclarations,
|
|
988
703
|
generateDeclarations,
|
|
989
704
|
generateReactorEntryFile,
|
|
990
705
|
generateReactorFile,
|
|
991
706
|
getReactorName,
|
|
992
707
|
getServiceTypeName,
|
|
993
|
-
|
|
708
|
+
resolveContainedOutDir,
|
|
709
|
+
resolveDeclarationsBaseName,
|
|
994
710
|
runCanisterPipeline,
|
|
995
711
|
toPascalCase
|
|
996
712
|
});
|