@rexeus/typeweaver 0.10.4 → 0.10.5
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/dist/{cli-C-s7e7_U.mjs → cli-BVUW7VcY.mjs} +147 -31
- package/dist/cli.cjs +147 -31
- package/dist/cli.mjs +147 -31
- package/dist/cli.mjs.map +1 -1
- package/dist/entry.mjs +1 -1
- package/package.json +8 -8
|
@@ -9,12 +9,52 @@ import os from "node:os";
|
|
|
9
9
|
import { build } from "rolldown";
|
|
10
10
|
import { createHash } from "node:crypto";
|
|
11
11
|
import { HttpMethod, HttpStatusCode } from "@rexeus/typeweaver-core";
|
|
12
|
+
//#region src/errors/InvalidConfigExportError.ts
|
|
13
|
+
var InvalidConfigExportError = class extends Error {
|
|
14
|
+
name = "InvalidConfigExportError";
|
|
15
|
+
constructor(configPath, reason) {
|
|
16
|
+
super(getInvalidConfigExportMessage(configPath, reason));
|
|
17
|
+
this.configPath = configPath;
|
|
18
|
+
this.reason = reason;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const getInvalidConfigExportMessage = (configPath, reason) => {
|
|
22
|
+
switch (reason) {
|
|
23
|
+
case "both-default-and-named-config": return `Configuration file '${configPath}' must choose one export style: use either 'export default' or 'export const config = ...', but not both.`;
|
|
24
|
+
case "default-namespace-wrapper": return `Configuration file '${configPath}' default export must be the config object itself, not a module namespace-like wrapper. Export the config directly with 'export default { ... }' or use 'export const config = ...'.`;
|
|
25
|
+
case "missing-config-export": return `Configuration file '${configPath}' must export its config via 'export default' or 'export const config = ...'.`;
|
|
26
|
+
case "non-object-config": return `Configuration file '${configPath}' must export a config object via 'export default' or 'export const config = ...'.`;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/errors/UnsupportedConfigExtensionError.ts
|
|
31
|
+
var UnsupportedConfigExtensionError = class extends Error {
|
|
32
|
+
name = "UnsupportedConfigExtensionError";
|
|
33
|
+
constructor(configPath, extension, supportedExtensions) {
|
|
34
|
+
super(`Unsupported config file extension '${extension}' for '${configPath}'. TypeWeaver accepts only these config extensions: ${supportedExtensions.join(", ")}.`);
|
|
35
|
+
this.configPath = configPath;
|
|
36
|
+
this.extension = extension;
|
|
37
|
+
this.supportedExtensions = supportedExtensions;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/errors/UnsupportedTypeScriptConfigError.ts
|
|
42
|
+
var UnsupportedTypeScriptConfigError = class extends Error {
|
|
43
|
+
name = "UnsupportedTypeScriptConfigError";
|
|
44
|
+
constructor(configPath, extension) {
|
|
45
|
+
super(`TypeScript config files are not supported: '${configPath}' uses '${extension}'. Use a JavaScript config file with one of these extensions: .js, .mjs, or .cjs.`);
|
|
46
|
+
this.configPath = configPath;
|
|
47
|
+
this.extension = extension;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
//#endregion
|
|
12
51
|
//#region src/configLoader.ts
|
|
13
|
-
const SUPPORTED_CONFIG_EXTENSIONS =
|
|
52
|
+
const SUPPORTED_CONFIG_EXTENSIONS = [
|
|
14
53
|
".js",
|
|
15
54
|
".mjs",
|
|
16
55
|
".cjs"
|
|
17
|
-
]
|
|
56
|
+
];
|
|
57
|
+
const SUPPORTED_CONFIG_EXTENSION_SET = new Set(SUPPORTED_CONFIG_EXTENSIONS);
|
|
18
58
|
const UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS = new Set([
|
|
19
59
|
".ts",
|
|
20
60
|
".mts",
|
|
@@ -25,25 +65,25 @@ const getResolvedConfigPath = (configPath, currentWorkingDirectory = process.cwd
|
|
|
25
65
|
};
|
|
26
66
|
const assertSupportedConfigPath = (configPath) => {
|
|
27
67
|
const extension = path.extname(configPath).toLowerCase();
|
|
28
|
-
if (UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS.has(extension)) throw new
|
|
29
|
-
if (!
|
|
68
|
+
if (UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS.has(extension)) throw new UnsupportedTypeScriptConfigError(configPath, extension);
|
|
69
|
+
if (!SUPPORTED_CONFIG_EXTENSION_SET.has(extension)) throw new UnsupportedConfigExtensionError(configPath, extension, SUPPORTED_CONFIG_EXTENSIONS);
|
|
30
70
|
};
|
|
31
71
|
const loadConfig = async (configPath) => {
|
|
32
72
|
assertSupportedConfigPath(configPath);
|
|
33
73
|
const loadedConfig = getConfigExport(await import(pathToFileURL(path.resolve(configPath)).toString()), configPath);
|
|
34
|
-
if (!isConfigObject(loadedConfig)) throw new
|
|
74
|
+
if (!isConfigObject(loadedConfig)) throw new InvalidConfigExportError(configPath, "non-object-config");
|
|
35
75
|
return loadedConfig;
|
|
36
76
|
};
|
|
37
77
|
const getConfigExport = (configModule, configPath) => {
|
|
38
78
|
const hasDefaultExport = Object.hasOwn(configModule, "default");
|
|
39
79
|
const hasNamedConfigExport = Object.hasOwn(configModule, "config");
|
|
40
|
-
if (hasDefaultExport && hasNamedConfigExport) throw new
|
|
80
|
+
if (hasDefaultExport && hasNamedConfigExport) throw new InvalidConfigExportError(configPath, "both-default-and-named-config");
|
|
41
81
|
if (hasDefaultExport) {
|
|
42
|
-
if (isNamespaceLikeConfigExport(configModule.default)) throw new
|
|
82
|
+
if (isNamespaceLikeConfigExport(configModule.default)) throw new InvalidConfigExportError(configPath, "default-namespace-wrapper");
|
|
43
83
|
return configModule.default;
|
|
44
84
|
}
|
|
45
85
|
if (hasNamedConfigExport) return configModule.config;
|
|
46
|
-
throw new
|
|
86
|
+
throw new InvalidConfigExportError(configPath, "missing-config-export");
|
|
47
87
|
};
|
|
48
88
|
const isConfigObject = (value) => {
|
|
49
89
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -53,6 +93,35 @@ const isNamespaceLikeConfigExport = (value) => {
|
|
|
53
93
|
return Object.hasOwn(value, "default") || Object.hasOwn(value, "config");
|
|
54
94
|
};
|
|
55
95
|
//#endregion
|
|
96
|
+
//#region src/generators/errors/UnsafeCleanTargetError.ts
|
|
97
|
+
var UnsafeCleanTargetError = class extends Error {
|
|
98
|
+
name = "UnsafeCleanTargetError";
|
|
99
|
+
resolvedOutputDir;
|
|
100
|
+
currentWorkingDirectory;
|
|
101
|
+
protectedWorkspaceRoot;
|
|
102
|
+
filesystemRoot;
|
|
103
|
+
constructor(outputDir, reason, diagnostics = {}) {
|
|
104
|
+
super(getUnsafeCleanTargetMessage(outputDir, reason, diagnostics));
|
|
105
|
+
this.outputDir = outputDir;
|
|
106
|
+
this.reason = reason;
|
|
107
|
+
this.resolvedOutputDir = diagnostics.resolvedOutputDir;
|
|
108
|
+
this.currentWorkingDirectory = diagnostics.currentWorkingDirectory;
|
|
109
|
+
this.protectedWorkspaceRoot = diagnostics.protectedWorkspaceRoot;
|
|
110
|
+
this.filesystemRoot = diagnostics.filesystemRoot;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const getUnsafeCleanTargetMessage = (outputDir, reason, diagnostics) => {
|
|
114
|
+
const targetDescription = `Refusing to clean '${outputDir}'`;
|
|
115
|
+
const suffix = "Use a dedicated generated output directory instead.";
|
|
116
|
+
switch (reason) {
|
|
117
|
+
case "empty-path": return `Refusing to clean an empty output directory path. ${suffix}`;
|
|
118
|
+
case "filesystem-root": return `${targetDescription} because it resolves to the filesystem root '${diagnostics.filesystemRoot ?? diagnostics.resolvedOutputDir ?? outputDir}'. ${suffix}`;
|
|
119
|
+
case "current-working-directory": return `${targetDescription} because it resolves to the current working directory '${diagnostics.currentWorkingDirectory ?? diagnostics.resolvedOutputDir ?? outputDir}'. ${suffix}`;
|
|
120
|
+
case "workspace-root": return `${targetDescription} because it resolves to the protected workspace root '${diagnostics.protectedWorkspaceRoot ?? diagnostics.resolvedOutputDir ?? outputDir}'. ${suffix}`;
|
|
121
|
+
case "ancestor-of-current-working-directory": return `${targetDescription} because it resolves to an ancestor directory of the current working directory '${diagnostics.currentWorkingDirectory ?? ""}'. ${suffix}`;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
//#endregion
|
|
56
125
|
//#region src/generators/formatter.ts
|
|
57
126
|
async function formatCode(outputDir, startDir) {
|
|
58
127
|
const format = await loadFormatter();
|
|
@@ -254,6 +323,17 @@ function reportSuccessfulLoads(successful) {
|
|
|
254
323
|
}
|
|
255
324
|
}
|
|
256
325
|
//#endregion
|
|
326
|
+
//#region src/generators/spec/errors/SpecBundleOutputMissingError.ts
|
|
327
|
+
var SpecBundleOutputMissingError = class extends Error {
|
|
328
|
+
name = "SpecBundleOutputMissingError";
|
|
329
|
+
constructor(inputFile, bundledSpecFile, specOutputDir) {
|
|
330
|
+
super(`Spec bundling completed but did not create the expected output '${bundledSpecFile}' for entrypoint '${inputFile}'. Expected the bundle inside '${specOutputDir}'.`);
|
|
331
|
+
this.inputFile = inputFile;
|
|
332
|
+
this.bundledSpecFile = bundledSpecFile;
|
|
333
|
+
this.specOutputDir = specOutputDir;
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
//#endregion
|
|
257
337
|
//#region src/generators/spec/specBundler.ts
|
|
258
338
|
const WINDOWS_ABSOLUTE_PATH_PATTERN = /^[A-Za-z]:[\\/]/;
|
|
259
339
|
const WINDOWS_UNC_PATH_PATTERN = /^\\\\/;
|
|
@@ -267,7 +347,7 @@ function createWrapperImportSpecifier(wrapperFile, inputFile) {
|
|
|
267
347
|
if (relativeInputFile.startsWith(".") || relativeInputFile.startsWith("..")) return relativeInputFile;
|
|
268
348
|
return `./${relativeInputFile}`;
|
|
269
349
|
}
|
|
270
|
-
async function bundle(config) {
|
|
350
|
+
async function bundle(config, deps = {}) {
|
|
271
351
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "typeweaver-spec-loader-"));
|
|
272
352
|
const wrapperFile = path.join(tempDir, "spec-entrypoint.ts");
|
|
273
353
|
const bundledSpecFile = path.join(config.specOutputDir, "spec.js");
|
|
@@ -283,7 +363,7 @@ async function bundle(config) {
|
|
|
283
363
|
""
|
|
284
364
|
].join("\n"));
|
|
285
365
|
try {
|
|
286
|
-
await build({
|
|
366
|
+
await (deps.build ?? build)({
|
|
287
367
|
cwd: tempDir,
|
|
288
368
|
input: wrapperFile,
|
|
289
369
|
treeshake: true,
|
|
@@ -303,7 +383,7 @@ async function bundle(config) {
|
|
|
303
383
|
force: true
|
|
304
384
|
});
|
|
305
385
|
}
|
|
306
|
-
if (!fs.existsSync(bundledSpecFile)) throw new
|
|
386
|
+
if (!(deps.existsSync ?? fs.existsSync)(bundledSpecFile)) throw new SpecBundleOutputMissingError(config.inputFile, bundledSpecFile, config.specOutputDir);
|
|
307
387
|
return bundledSpecFile;
|
|
308
388
|
}
|
|
309
389
|
function resolveBundledInputFile(inputFile) {
|
|
@@ -385,17 +465,32 @@ function writeSpecDeclarationFile(specOutputDir) {
|
|
|
385
465
|
const moduleDir$1 = path.dirname(fileURLToPath(import.meta.url));
|
|
386
466
|
const assertSafeCleanTarget = (outputDir, currentWorkingDirectory) => {
|
|
387
467
|
const trimmedOutputDir = outputDir.trim();
|
|
388
|
-
if (trimmedOutputDir.length === 0) throw new
|
|
468
|
+
if (trimmedOutputDir.length === 0) throw new UnsafeCleanTargetError(outputDir, "empty-path");
|
|
389
469
|
const resolvedWorkingDirectory = path.resolve(currentWorkingDirectory);
|
|
390
470
|
const canonicalWorkingDirectory = fs.realpathSync.native(resolvedWorkingDirectory);
|
|
391
471
|
const resolvedOutputDir = path.resolve(resolvedWorkingDirectory, trimmedOutputDir);
|
|
392
472
|
const canonicalOutputDir = canonicalizePathForContainment(resolvedOutputDir);
|
|
393
|
-
|
|
394
|
-
if (
|
|
473
|
+
const filesystemRoot = path.parse(canonicalOutputDir).root;
|
|
474
|
+
if (canonicalOutputDir === filesystemRoot) throw new UnsafeCleanTargetError(outputDir, "filesystem-root", {
|
|
475
|
+
resolvedOutputDir,
|
|
476
|
+
currentWorkingDirectory: resolvedWorkingDirectory,
|
|
477
|
+
filesystemRoot
|
|
478
|
+
});
|
|
479
|
+
if (resolvedOutputDir === resolvedWorkingDirectory || canonicalOutputDir === canonicalWorkingDirectory) throw new UnsafeCleanTargetError(outputDir, "current-working-directory", {
|
|
480
|
+
resolvedOutputDir,
|
|
481
|
+
currentWorkingDirectory: resolvedWorkingDirectory
|
|
482
|
+
});
|
|
395
483
|
const protectedWorkspaceRoots = [findProtectedWorkspaceRoot(resolvedWorkingDirectory), findProtectedWorkspaceRoot(canonicalWorkingDirectory)].filter((root) => root !== void 0);
|
|
396
484
|
const protectedWorkspaceRootTarget = protectedWorkspaceRoots.find((protectedWorkspaceRoot) => resolvedOutputDir === protectedWorkspaceRoot || canonicalOutputDir === fs.realpathSync.native(protectedWorkspaceRoot));
|
|
397
|
-
if (protectedWorkspaceRootTarget !== void 0) throw new
|
|
398
|
-
|
|
485
|
+
if (protectedWorkspaceRootTarget !== void 0) throw new UnsafeCleanTargetError(outputDir, "workspace-root", {
|
|
486
|
+
resolvedOutputDir,
|
|
487
|
+
currentWorkingDirectory: resolvedWorkingDirectory,
|
|
488
|
+
protectedWorkspaceRoot: protectedWorkspaceRootTarget
|
|
489
|
+
});
|
|
490
|
+
if (protectedWorkspaceRoots.length > 0 && (isSameOrDescendantOf(resolvedWorkingDirectory, resolvedOutputDir) || isSameOrDescendantOf(canonicalWorkingDirectory, canonicalOutputDir))) throw new UnsafeCleanTargetError(outputDir, "ancestor-of-current-working-directory", {
|
|
491
|
+
resolvedOutputDir,
|
|
492
|
+
currentWorkingDirectory: resolvedWorkingDirectory
|
|
493
|
+
});
|
|
399
494
|
};
|
|
400
495
|
/**
|
|
401
496
|
* Main generator for typeweaver
|
|
@@ -508,6 +603,40 @@ const isSameOrDescendantOf = (directory, ancestor) => {
|
|
|
508
603
|
return relativePath === "" || !escapesAncestor && !path.isAbsolute(relativePath);
|
|
509
604
|
};
|
|
510
605
|
//#endregion
|
|
606
|
+
//#region src/errors/MissingGenerateOptionError.ts
|
|
607
|
+
var MissingGenerateOptionError = class extends Error {
|
|
608
|
+
name = "MissingGenerateOptionError";
|
|
609
|
+
constructor(optionName, flag, configKey) {
|
|
610
|
+
super(`Missing required generate option '${optionName}'. Pass ${flag} or set '${configKey}' in the TypeWeaver config file.`);
|
|
611
|
+
this.optionName = optionName;
|
|
612
|
+
this.flag = flag;
|
|
613
|
+
this.configKey = configKey;
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
//#endregion
|
|
617
|
+
//#region src/resolveGenerateOptions.ts
|
|
618
|
+
const resolveGenerateOptions = (options, config, currentWorkingDirectory) => {
|
|
619
|
+
const inputPath = options.input ?? config.input;
|
|
620
|
+
const outputDir = options.output ?? config.output;
|
|
621
|
+
if (!inputPath) throw new MissingGenerateOptionError("input", "--input", "input");
|
|
622
|
+
if (!outputDir) throw new MissingGenerateOptionError("output", "--output", "output");
|
|
623
|
+
const resolvedInputPath = path.isAbsolute(inputPath) ? inputPath : path.join(currentWorkingDirectory, inputPath);
|
|
624
|
+
const resolvedOutputDir = path.isAbsolute(outputDir) ? outputDir : path.join(currentWorkingDirectory, outputDir);
|
|
625
|
+
const finalConfig = {
|
|
626
|
+
input: resolvedInputPath,
|
|
627
|
+
output: resolvedOutputDir,
|
|
628
|
+
format: options.format ?? config.format ?? true,
|
|
629
|
+
clean: options.clean ?? config.clean ?? true
|
|
630
|
+
};
|
|
631
|
+
if (options.plugins) finalConfig.plugins = options.plugins.split(",").map((plugin) => plugin.trim());
|
|
632
|
+
else if (config.plugins) finalConfig.plugins = config.plugins;
|
|
633
|
+
return {
|
|
634
|
+
inputPath: resolvedInputPath,
|
|
635
|
+
outputDir: resolvedOutputDir,
|
|
636
|
+
config: finalConfig
|
|
637
|
+
};
|
|
638
|
+
};
|
|
639
|
+
//#endregion
|
|
511
640
|
//#region src/cli.ts
|
|
512
641
|
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
513
642
|
const packageJson = JSON.parse(fs.readFileSync(path.join(moduleDir, "../package.json"), "utf-8"));
|
|
@@ -527,21 +656,8 @@ program.command("generate").description("Generate types, validators, and clients
|
|
|
527
656
|
process.exit(1);
|
|
528
657
|
}
|
|
529
658
|
}
|
|
530
|
-
const
|
|
531
|
-
|
|
532
|
-
if (!inputPath) throw new Error("No input spec entrypoint provided. Use --input or specify in config file.");
|
|
533
|
-
if (!outputDir) throw new Error("No output directory provided. Use --output or specify in config file.");
|
|
534
|
-
const resolvedInputPath = path.isAbsolute(inputPath) ? inputPath : path.join(execDir, inputPath);
|
|
535
|
-
const resolvedOutputDir = path.isAbsolute(outputDir) ? outputDir : path.join(execDir, outputDir);
|
|
536
|
-
const finalConfig = {
|
|
537
|
-
input: resolvedInputPath,
|
|
538
|
-
output: resolvedOutputDir,
|
|
539
|
-
format: options.format ?? config.format ?? true,
|
|
540
|
-
clean: options.clean ?? config.clean ?? true
|
|
541
|
-
};
|
|
542
|
-
if (options.plugins) finalConfig.plugins = options.plugins.split(",").map((p) => p.trim());
|
|
543
|
-
else if (config.plugins) finalConfig.plugins = config.plugins;
|
|
544
|
-
return new Generator().generate(resolvedInputPath, resolvedOutputDir, finalConfig, execDir);
|
|
659
|
+
const resolvedGenerateOptions = resolveGenerateOptions(options, config, execDir);
|
|
660
|
+
return new Generator().generate(resolvedGenerateOptions.inputPath, resolvedGenerateOptions.outputDir, resolvedGenerateOptions.config, execDir);
|
|
545
661
|
});
|
|
546
662
|
program.command("init").description("Initialize a new typeweaver project (coming soon)").action(() => {
|
|
547
663
|
console.log("The init command is coming soon!");
|
package/dist/cli.cjs
CHANGED
|
@@ -33,12 +33,52 @@ node_os = __toESM(node_os);
|
|
|
33
33
|
let rolldown = require("rolldown");
|
|
34
34
|
let node_crypto = require("node:crypto");
|
|
35
35
|
let _rexeus_typeweaver_core = require("@rexeus/typeweaver-core");
|
|
36
|
+
//#region src/errors/InvalidConfigExportError.ts
|
|
37
|
+
var InvalidConfigExportError = class extends Error {
|
|
38
|
+
name = "InvalidConfigExportError";
|
|
39
|
+
constructor(configPath, reason) {
|
|
40
|
+
super(getInvalidConfigExportMessage(configPath, reason));
|
|
41
|
+
this.configPath = configPath;
|
|
42
|
+
this.reason = reason;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const getInvalidConfigExportMessage = (configPath, reason) => {
|
|
46
|
+
switch (reason) {
|
|
47
|
+
case "both-default-and-named-config": return `Configuration file '${configPath}' must choose one export style: use either 'export default' or 'export const config = ...', but not both.`;
|
|
48
|
+
case "default-namespace-wrapper": return `Configuration file '${configPath}' default export must be the config object itself, not a module namespace-like wrapper. Export the config directly with 'export default { ... }' or use 'export const config = ...'.`;
|
|
49
|
+
case "missing-config-export": return `Configuration file '${configPath}' must export its config via 'export default' or 'export const config = ...'.`;
|
|
50
|
+
case "non-object-config": return `Configuration file '${configPath}' must export a config object via 'export default' or 'export const config = ...'.`;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region src/errors/UnsupportedConfigExtensionError.ts
|
|
55
|
+
var UnsupportedConfigExtensionError = class extends Error {
|
|
56
|
+
name = "UnsupportedConfigExtensionError";
|
|
57
|
+
constructor(configPath, extension, supportedExtensions) {
|
|
58
|
+
super(`Unsupported config file extension '${extension}' for '${configPath}'. TypeWeaver accepts only these config extensions: ${supportedExtensions.join(", ")}.`);
|
|
59
|
+
this.configPath = configPath;
|
|
60
|
+
this.extension = extension;
|
|
61
|
+
this.supportedExtensions = supportedExtensions;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
//#endregion
|
|
65
|
+
//#region src/errors/UnsupportedTypeScriptConfigError.ts
|
|
66
|
+
var UnsupportedTypeScriptConfigError = class extends Error {
|
|
67
|
+
name = "UnsupportedTypeScriptConfigError";
|
|
68
|
+
constructor(configPath, extension) {
|
|
69
|
+
super(`TypeScript config files are not supported: '${configPath}' uses '${extension}'. Use a JavaScript config file with one of these extensions: .js, .mjs, or .cjs.`);
|
|
70
|
+
this.configPath = configPath;
|
|
71
|
+
this.extension = extension;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
//#endregion
|
|
36
75
|
//#region src/configLoader.ts
|
|
37
|
-
const SUPPORTED_CONFIG_EXTENSIONS =
|
|
76
|
+
const SUPPORTED_CONFIG_EXTENSIONS = [
|
|
38
77
|
".js",
|
|
39
78
|
".mjs",
|
|
40
79
|
".cjs"
|
|
41
|
-
]
|
|
80
|
+
];
|
|
81
|
+
const SUPPORTED_CONFIG_EXTENSION_SET = new Set(SUPPORTED_CONFIG_EXTENSIONS);
|
|
42
82
|
const UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS = new Set([
|
|
43
83
|
".ts",
|
|
44
84
|
".mts",
|
|
@@ -49,25 +89,25 @@ const getResolvedConfigPath = (configPath, currentWorkingDirectory = process.cwd
|
|
|
49
89
|
};
|
|
50
90
|
const assertSupportedConfigPath = (configPath) => {
|
|
51
91
|
const extension = node_path.default.extname(configPath).toLowerCase();
|
|
52
|
-
if (UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS.has(extension)) throw new
|
|
53
|
-
if (!
|
|
92
|
+
if (UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS.has(extension)) throw new UnsupportedTypeScriptConfigError(configPath, extension);
|
|
93
|
+
if (!SUPPORTED_CONFIG_EXTENSION_SET.has(extension)) throw new UnsupportedConfigExtensionError(configPath, extension, SUPPORTED_CONFIG_EXTENSIONS);
|
|
54
94
|
};
|
|
55
95
|
const loadConfig = async (configPath) => {
|
|
56
96
|
assertSupportedConfigPath(configPath);
|
|
57
97
|
const loadedConfig = getConfigExport(await import((0, node_url.pathToFileURL)(node_path.default.resolve(configPath)).toString()), configPath);
|
|
58
|
-
if (!isConfigObject(loadedConfig)) throw new
|
|
98
|
+
if (!isConfigObject(loadedConfig)) throw new InvalidConfigExportError(configPath, "non-object-config");
|
|
59
99
|
return loadedConfig;
|
|
60
100
|
};
|
|
61
101
|
const getConfigExport = (configModule, configPath) => {
|
|
62
102
|
const hasDefaultExport = Object.hasOwn(configModule, "default");
|
|
63
103
|
const hasNamedConfigExport = Object.hasOwn(configModule, "config");
|
|
64
|
-
if (hasDefaultExport && hasNamedConfigExport) throw new
|
|
104
|
+
if (hasDefaultExport && hasNamedConfigExport) throw new InvalidConfigExportError(configPath, "both-default-and-named-config");
|
|
65
105
|
if (hasDefaultExport) {
|
|
66
|
-
if (isNamespaceLikeConfigExport(configModule.default)) throw new
|
|
106
|
+
if (isNamespaceLikeConfigExport(configModule.default)) throw new InvalidConfigExportError(configPath, "default-namespace-wrapper");
|
|
67
107
|
return configModule.default;
|
|
68
108
|
}
|
|
69
109
|
if (hasNamedConfigExport) return configModule.config;
|
|
70
|
-
throw new
|
|
110
|
+
throw new InvalidConfigExportError(configPath, "missing-config-export");
|
|
71
111
|
};
|
|
72
112
|
const isConfigObject = (value) => {
|
|
73
113
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -77,6 +117,35 @@ const isNamespaceLikeConfigExport = (value) => {
|
|
|
77
117
|
return Object.hasOwn(value, "default") || Object.hasOwn(value, "config");
|
|
78
118
|
};
|
|
79
119
|
//#endregion
|
|
120
|
+
//#region src/generators/errors/UnsafeCleanTargetError.ts
|
|
121
|
+
var UnsafeCleanTargetError = class extends Error {
|
|
122
|
+
name = "UnsafeCleanTargetError";
|
|
123
|
+
resolvedOutputDir;
|
|
124
|
+
currentWorkingDirectory;
|
|
125
|
+
protectedWorkspaceRoot;
|
|
126
|
+
filesystemRoot;
|
|
127
|
+
constructor(outputDir, reason, diagnostics = {}) {
|
|
128
|
+
super(getUnsafeCleanTargetMessage(outputDir, reason, diagnostics));
|
|
129
|
+
this.outputDir = outputDir;
|
|
130
|
+
this.reason = reason;
|
|
131
|
+
this.resolvedOutputDir = diagnostics.resolvedOutputDir;
|
|
132
|
+
this.currentWorkingDirectory = diagnostics.currentWorkingDirectory;
|
|
133
|
+
this.protectedWorkspaceRoot = diagnostics.protectedWorkspaceRoot;
|
|
134
|
+
this.filesystemRoot = diagnostics.filesystemRoot;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
const getUnsafeCleanTargetMessage = (outputDir, reason, diagnostics) => {
|
|
138
|
+
const targetDescription = `Refusing to clean '${outputDir}'`;
|
|
139
|
+
const suffix = "Use a dedicated generated output directory instead.";
|
|
140
|
+
switch (reason) {
|
|
141
|
+
case "empty-path": return `Refusing to clean an empty output directory path. ${suffix}`;
|
|
142
|
+
case "filesystem-root": return `${targetDescription} because it resolves to the filesystem root '${diagnostics.filesystemRoot ?? diagnostics.resolvedOutputDir ?? outputDir}'. ${suffix}`;
|
|
143
|
+
case "current-working-directory": return `${targetDescription} because it resolves to the current working directory '${diagnostics.currentWorkingDirectory ?? diagnostics.resolvedOutputDir ?? outputDir}'. ${suffix}`;
|
|
144
|
+
case "workspace-root": return `${targetDescription} because it resolves to the protected workspace root '${diagnostics.protectedWorkspaceRoot ?? diagnostics.resolvedOutputDir ?? outputDir}'. ${suffix}`;
|
|
145
|
+
case "ancestor-of-current-working-directory": return `${targetDescription} because it resolves to an ancestor directory of the current working directory '${diagnostics.currentWorkingDirectory ?? ""}'. ${suffix}`;
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
//#endregion
|
|
80
149
|
//#region src/generators/formatter.ts
|
|
81
150
|
async function formatCode(outputDir, startDir) {
|
|
82
151
|
const format = await loadFormatter();
|
|
@@ -278,6 +347,17 @@ function reportSuccessfulLoads(successful) {
|
|
|
278
347
|
}
|
|
279
348
|
}
|
|
280
349
|
//#endregion
|
|
350
|
+
//#region src/generators/spec/errors/SpecBundleOutputMissingError.ts
|
|
351
|
+
var SpecBundleOutputMissingError = class extends Error {
|
|
352
|
+
name = "SpecBundleOutputMissingError";
|
|
353
|
+
constructor(inputFile, bundledSpecFile, specOutputDir) {
|
|
354
|
+
super(`Spec bundling completed but did not create the expected output '${bundledSpecFile}' for entrypoint '${inputFile}'. Expected the bundle inside '${specOutputDir}'.`);
|
|
355
|
+
this.inputFile = inputFile;
|
|
356
|
+
this.bundledSpecFile = bundledSpecFile;
|
|
357
|
+
this.specOutputDir = specOutputDir;
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
//#endregion
|
|
281
361
|
//#region src/generators/spec/specBundler.ts
|
|
282
362
|
const WINDOWS_ABSOLUTE_PATH_PATTERN = /^[A-Za-z]:[\\/]/;
|
|
283
363
|
const WINDOWS_UNC_PATH_PATTERN = /^\\\\/;
|
|
@@ -291,7 +371,7 @@ function createWrapperImportSpecifier(wrapperFile, inputFile) {
|
|
|
291
371
|
if (relativeInputFile.startsWith(".") || relativeInputFile.startsWith("..")) return relativeInputFile;
|
|
292
372
|
return `./${relativeInputFile}`;
|
|
293
373
|
}
|
|
294
|
-
async function bundle(config) {
|
|
374
|
+
async function bundle(config, deps = {}) {
|
|
295
375
|
const tempDir = node_fs.default.mkdtempSync(node_path.default.join(node_os.default.tmpdir(), "typeweaver-spec-loader-"));
|
|
296
376
|
const wrapperFile = node_path.default.join(tempDir, "spec-entrypoint.ts");
|
|
297
377
|
const bundledSpecFile = node_path.default.join(config.specOutputDir, "spec.js");
|
|
@@ -307,7 +387,7 @@ async function bundle(config) {
|
|
|
307
387
|
""
|
|
308
388
|
].join("\n"));
|
|
309
389
|
try {
|
|
310
|
-
await (
|
|
390
|
+
await (deps.build ?? rolldown.build)({
|
|
311
391
|
cwd: tempDir,
|
|
312
392
|
input: wrapperFile,
|
|
313
393
|
treeshake: true,
|
|
@@ -327,7 +407,7 @@ async function bundle(config) {
|
|
|
327
407
|
force: true
|
|
328
408
|
});
|
|
329
409
|
}
|
|
330
|
-
if (!node_fs.default.existsSync(bundledSpecFile)) throw new
|
|
410
|
+
if (!(deps.existsSync ?? node_fs.default.existsSync)(bundledSpecFile)) throw new SpecBundleOutputMissingError(config.inputFile, bundledSpecFile, config.specOutputDir);
|
|
331
411
|
return bundledSpecFile;
|
|
332
412
|
}
|
|
333
413
|
function resolveBundledInputFile(inputFile) {
|
|
@@ -409,17 +489,32 @@ function writeSpecDeclarationFile(specOutputDir) {
|
|
|
409
489
|
const moduleDir$1 = node_path.default.dirname((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
|
|
410
490
|
const assertSafeCleanTarget = (outputDir, currentWorkingDirectory) => {
|
|
411
491
|
const trimmedOutputDir = outputDir.trim();
|
|
412
|
-
if (trimmedOutputDir.length === 0) throw new
|
|
492
|
+
if (trimmedOutputDir.length === 0) throw new UnsafeCleanTargetError(outputDir, "empty-path");
|
|
413
493
|
const resolvedWorkingDirectory = node_path.default.resolve(currentWorkingDirectory);
|
|
414
494
|
const canonicalWorkingDirectory = node_fs.default.realpathSync.native(resolvedWorkingDirectory);
|
|
415
495
|
const resolvedOutputDir = node_path.default.resolve(resolvedWorkingDirectory, trimmedOutputDir);
|
|
416
496
|
const canonicalOutputDir = canonicalizePathForContainment(resolvedOutputDir);
|
|
417
|
-
|
|
418
|
-
if (
|
|
497
|
+
const filesystemRoot = node_path.default.parse(canonicalOutputDir).root;
|
|
498
|
+
if (canonicalOutputDir === filesystemRoot) throw new UnsafeCleanTargetError(outputDir, "filesystem-root", {
|
|
499
|
+
resolvedOutputDir,
|
|
500
|
+
currentWorkingDirectory: resolvedWorkingDirectory,
|
|
501
|
+
filesystemRoot
|
|
502
|
+
});
|
|
503
|
+
if (resolvedOutputDir === resolvedWorkingDirectory || canonicalOutputDir === canonicalWorkingDirectory) throw new UnsafeCleanTargetError(outputDir, "current-working-directory", {
|
|
504
|
+
resolvedOutputDir,
|
|
505
|
+
currentWorkingDirectory: resolvedWorkingDirectory
|
|
506
|
+
});
|
|
419
507
|
const protectedWorkspaceRoots = [findProtectedWorkspaceRoot(resolvedWorkingDirectory), findProtectedWorkspaceRoot(canonicalWorkingDirectory)].filter((root) => root !== void 0);
|
|
420
508
|
const protectedWorkspaceRootTarget = protectedWorkspaceRoots.find((protectedWorkspaceRoot) => resolvedOutputDir === protectedWorkspaceRoot || canonicalOutputDir === node_fs.default.realpathSync.native(protectedWorkspaceRoot));
|
|
421
|
-
if (protectedWorkspaceRootTarget !== void 0) throw new
|
|
422
|
-
|
|
509
|
+
if (protectedWorkspaceRootTarget !== void 0) throw new UnsafeCleanTargetError(outputDir, "workspace-root", {
|
|
510
|
+
resolvedOutputDir,
|
|
511
|
+
currentWorkingDirectory: resolvedWorkingDirectory,
|
|
512
|
+
protectedWorkspaceRoot: protectedWorkspaceRootTarget
|
|
513
|
+
});
|
|
514
|
+
if (protectedWorkspaceRoots.length > 0 && (isSameOrDescendantOf(resolvedWorkingDirectory, resolvedOutputDir) || isSameOrDescendantOf(canonicalWorkingDirectory, canonicalOutputDir))) throw new UnsafeCleanTargetError(outputDir, "ancestor-of-current-working-directory", {
|
|
515
|
+
resolvedOutputDir,
|
|
516
|
+
currentWorkingDirectory: resolvedWorkingDirectory
|
|
517
|
+
});
|
|
423
518
|
};
|
|
424
519
|
/**
|
|
425
520
|
* Main generator for typeweaver
|
|
@@ -532,6 +627,40 @@ const isSameOrDescendantOf = (directory, ancestor) => {
|
|
|
532
627
|
return relativePath === "" || !escapesAncestor && !node_path.default.isAbsolute(relativePath);
|
|
533
628
|
};
|
|
534
629
|
//#endregion
|
|
630
|
+
//#region src/errors/MissingGenerateOptionError.ts
|
|
631
|
+
var MissingGenerateOptionError = class extends Error {
|
|
632
|
+
name = "MissingGenerateOptionError";
|
|
633
|
+
constructor(optionName, flag, configKey) {
|
|
634
|
+
super(`Missing required generate option '${optionName}'. Pass ${flag} or set '${configKey}' in the TypeWeaver config file.`);
|
|
635
|
+
this.optionName = optionName;
|
|
636
|
+
this.flag = flag;
|
|
637
|
+
this.configKey = configKey;
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
//#endregion
|
|
641
|
+
//#region src/resolveGenerateOptions.ts
|
|
642
|
+
const resolveGenerateOptions = (options, config, currentWorkingDirectory) => {
|
|
643
|
+
const inputPath = options.input ?? config.input;
|
|
644
|
+
const outputDir = options.output ?? config.output;
|
|
645
|
+
if (!inputPath) throw new MissingGenerateOptionError("input", "--input", "input");
|
|
646
|
+
if (!outputDir) throw new MissingGenerateOptionError("output", "--output", "output");
|
|
647
|
+
const resolvedInputPath = node_path.default.isAbsolute(inputPath) ? inputPath : node_path.default.join(currentWorkingDirectory, inputPath);
|
|
648
|
+
const resolvedOutputDir = node_path.default.isAbsolute(outputDir) ? outputDir : node_path.default.join(currentWorkingDirectory, outputDir);
|
|
649
|
+
const finalConfig = {
|
|
650
|
+
input: resolvedInputPath,
|
|
651
|
+
output: resolvedOutputDir,
|
|
652
|
+
format: options.format ?? config.format ?? true,
|
|
653
|
+
clean: options.clean ?? config.clean ?? true
|
|
654
|
+
};
|
|
655
|
+
if (options.plugins) finalConfig.plugins = options.plugins.split(",").map((plugin) => plugin.trim());
|
|
656
|
+
else if (config.plugins) finalConfig.plugins = config.plugins;
|
|
657
|
+
return {
|
|
658
|
+
inputPath: resolvedInputPath,
|
|
659
|
+
outputDir: resolvedOutputDir,
|
|
660
|
+
config: finalConfig
|
|
661
|
+
};
|
|
662
|
+
};
|
|
663
|
+
//#endregion
|
|
535
664
|
//#region src/cli.ts
|
|
536
665
|
const moduleDir = node_path.default.dirname((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
|
|
537
666
|
const packageJson = JSON.parse(node_fs.default.readFileSync(node_path.default.join(moduleDir, "../package.json"), "utf-8"));
|
|
@@ -551,21 +680,8 @@ program.command("generate").description("Generate types, validators, and clients
|
|
|
551
680
|
process.exit(1);
|
|
552
681
|
}
|
|
553
682
|
}
|
|
554
|
-
const
|
|
555
|
-
|
|
556
|
-
if (!inputPath) throw new Error("No input spec entrypoint provided. Use --input or specify in config file.");
|
|
557
|
-
if (!outputDir) throw new Error("No output directory provided. Use --output or specify in config file.");
|
|
558
|
-
const resolvedInputPath = node_path.default.isAbsolute(inputPath) ? inputPath : node_path.default.join(execDir, inputPath);
|
|
559
|
-
const resolvedOutputDir = node_path.default.isAbsolute(outputDir) ? outputDir : node_path.default.join(execDir, outputDir);
|
|
560
|
-
const finalConfig = {
|
|
561
|
-
input: resolvedInputPath,
|
|
562
|
-
output: resolvedOutputDir,
|
|
563
|
-
format: options.format ?? config.format ?? true,
|
|
564
|
-
clean: options.clean ?? config.clean ?? true
|
|
565
|
-
};
|
|
566
|
-
if (options.plugins) finalConfig.plugins = options.plugins.split(",").map((p) => p.trim());
|
|
567
|
-
else if (config.plugins) finalConfig.plugins = config.plugins;
|
|
568
|
-
return new Generator().generate(resolvedInputPath, resolvedOutputDir, finalConfig, execDir);
|
|
683
|
+
const resolvedGenerateOptions = resolveGenerateOptions(options, config, execDir);
|
|
684
|
+
return new Generator().generate(resolvedGenerateOptions.inputPath, resolvedGenerateOptions.outputDir, resolvedGenerateOptions.config, execDir);
|
|
569
685
|
});
|
|
570
686
|
program.command("init").description("Initialize a new typeweaver project (coming soon)").action(() => {
|
|
571
687
|
console.log("The init command is coming soon!");
|
package/dist/cli.mjs
CHANGED
|
@@ -8,12 +8,52 @@ import os from "node:os";
|
|
|
8
8
|
import { build } from "rolldown";
|
|
9
9
|
import { createHash } from "node:crypto";
|
|
10
10
|
import { HttpMethod, HttpStatusCode } from "@rexeus/typeweaver-core";
|
|
11
|
+
//#region src/errors/InvalidConfigExportError.ts
|
|
12
|
+
var InvalidConfigExportError = class extends Error {
|
|
13
|
+
name = "InvalidConfigExportError";
|
|
14
|
+
constructor(configPath, reason) {
|
|
15
|
+
super(getInvalidConfigExportMessage(configPath, reason));
|
|
16
|
+
this.configPath = configPath;
|
|
17
|
+
this.reason = reason;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const getInvalidConfigExportMessage = (configPath, reason) => {
|
|
21
|
+
switch (reason) {
|
|
22
|
+
case "both-default-and-named-config": return `Configuration file '${configPath}' must choose one export style: use either 'export default' or 'export const config = ...', but not both.`;
|
|
23
|
+
case "default-namespace-wrapper": return `Configuration file '${configPath}' default export must be the config object itself, not a module namespace-like wrapper. Export the config directly with 'export default { ... }' or use 'export const config = ...'.`;
|
|
24
|
+
case "missing-config-export": return `Configuration file '${configPath}' must export its config via 'export default' or 'export const config = ...'.`;
|
|
25
|
+
case "non-object-config": return `Configuration file '${configPath}' must export a config object via 'export default' or 'export const config = ...'.`;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/errors/UnsupportedConfigExtensionError.ts
|
|
30
|
+
var UnsupportedConfigExtensionError = class extends Error {
|
|
31
|
+
name = "UnsupportedConfigExtensionError";
|
|
32
|
+
constructor(configPath, extension, supportedExtensions) {
|
|
33
|
+
super(`Unsupported config file extension '${extension}' for '${configPath}'. TypeWeaver accepts only these config extensions: ${supportedExtensions.join(", ")}.`);
|
|
34
|
+
this.configPath = configPath;
|
|
35
|
+
this.extension = extension;
|
|
36
|
+
this.supportedExtensions = supportedExtensions;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/errors/UnsupportedTypeScriptConfigError.ts
|
|
41
|
+
var UnsupportedTypeScriptConfigError = class extends Error {
|
|
42
|
+
name = "UnsupportedTypeScriptConfigError";
|
|
43
|
+
constructor(configPath, extension) {
|
|
44
|
+
super(`TypeScript config files are not supported: '${configPath}' uses '${extension}'. Use a JavaScript config file with one of these extensions: .js, .mjs, or .cjs.`);
|
|
45
|
+
this.configPath = configPath;
|
|
46
|
+
this.extension = extension;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
//#endregion
|
|
11
50
|
//#region src/configLoader.ts
|
|
12
|
-
const SUPPORTED_CONFIG_EXTENSIONS =
|
|
51
|
+
const SUPPORTED_CONFIG_EXTENSIONS = [
|
|
13
52
|
".js",
|
|
14
53
|
".mjs",
|
|
15
54
|
".cjs"
|
|
16
|
-
]
|
|
55
|
+
];
|
|
56
|
+
const SUPPORTED_CONFIG_EXTENSION_SET = new Set(SUPPORTED_CONFIG_EXTENSIONS);
|
|
17
57
|
const UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS = new Set([
|
|
18
58
|
".ts",
|
|
19
59
|
".mts",
|
|
@@ -24,25 +64,25 @@ const getResolvedConfigPath = (configPath, currentWorkingDirectory = process.cwd
|
|
|
24
64
|
};
|
|
25
65
|
const assertSupportedConfigPath = (configPath) => {
|
|
26
66
|
const extension = path.extname(configPath).toLowerCase();
|
|
27
|
-
if (UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS.has(extension)) throw new
|
|
28
|
-
if (!
|
|
67
|
+
if (UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS.has(extension)) throw new UnsupportedTypeScriptConfigError(configPath, extension);
|
|
68
|
+
if (!SUPPORTED_CONFIG_EXTENSION_SET.has(extension)) throw new UnsupportedConfigExtensionError(configPath, extension, SUPPORTED_CONFIG_EXTENSIONS);
|
|
29
69
|
};
|
|
30
70
|
const loadConfig = async (configPath) => {
|
|
31
71
|
assertSupportedConfigPath(configPath);
|
|
32
72
|
const loadedConfig = getConfigExport(await import(pathToFileURL(path.resolve(configPath)).toString()), configPath);
|
|
33
|
-
if (!isConfigObject(loadedConfig)) throw new
|
|
73
|
+
if (!isConfigObject(loadedConfig)) throw new InvalidConfigExportError(configPath, "non-object-config");
|
|
34
74
|
return loadedConfig;
|
|
35
75
|
};
|
|
36
76
|
const getConfigExport = (configModule, configPath) => {
|
|
37
77
|
const hasDefaultExport = Object.hasOwn(configModule, "default");
|
|
38
78
|
const hasNamedConfigExport = Object.hasOwn(configModule, "config");
|
|
39
|
-
if (hasDefaultExport && hasNamedConfigExport) throw new
|
|
79
|
+
if (hasDefaultExport && hasNamedConfigExport) throw new InvalidConfigExportError(configPath, "both-default-and-named-config");
|
|
40
80
|
if (hasDefaultExport) {
|
|
41
|
-
if (isNamespaceLikeConfigExport(configModule.default)) throw new
|
|
81
|
+
if (isNamespaceLikeConfigExport(configModule.default)) throw new InvalidConfigExportError(configPath, "default-namespace-wrapper");
|
|
42
82
|
return configModule.default;
|
|
43
83
|
}
|
|
44
84
|
if (hasNamedConfigExport) return configModule.config;
|
|
45
|
-
throw new
|
|
85
|
+
throw new InvalidConfigExportError(configPath, "missing-config-export");
|
|
46
86
|
};
|
|
47
87
|
const isConfigObject = (value) => {
|
|
48
88
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -52,6 +92,35 @@ const isNamespaceLikeConfigExport = (value) => {
|
|
|
52
92
|
return Object.hasOwn(value, "default") || Object.hasOwn(value, "config");
|
|
53
93
|
};
|
|
54
94
|
//#endregion
|
|
95
|
+
//#region src/generators/errors/UnsafeCleanTargetError.ts
|
|
96
|
+
var UnsafeCleanTargetError = class extends Error {
|
|
97
|
+
name = "UnsafeCleanTargetError";
|
|
98
|
+
resolvedOutputDir;
|
|
99
|
+
currentWorkingDirectory;
|
|
100
|
+
protectedWorkspaceRoot;
|
|
101
|
+
filesystemRoot;
|
|
102
|
+
constructor(outputDir, reason, diagnostics = {}) {
|
|
103
|
+
super(getUnsafeCleanTargetMessage(outputDir, reason, diagnostics));
|
|
104
|
+
this.outputDir = outputDir;
|
|
105
|
+
this.reason = reason;
|
|
106
|
+
this.resolvedOutputDir = diagnostics.resolvedOutputDir;
|
|
107
|
+
this.currentWorkingDirectory = diagnostics.currentWorkingDirectory;
|
|
108
|
+
this.protectedWorkspaceRoot = diagnostics.protectedWorkspaceRoot;
|
|
109
|
+
this.filesystemRoot = diagnostics.filesystemRoot;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
const getUnsafeCleanTargetMessage = (outputDir, reason, diagnostics) => {
|
|
113
|
+
const targetDescription = `Refusing to clean '${outputDir}'`;
|
|
114
|
+
const suffix = "Use a dedicated generated output directory instead.";
|
|
115
|
+
switch (reason) {
|
|
116
|
+
case "empty-path": return `Refusing to clean an empty output directory path. ${suffix}`;
|
|
117
|
+
case "filesystem-root": return `${targetDescription} because it resolves to the filesystem root '${diagnostics.filesystemRoot ?? diagnostics.resolvedOutputDir ?? outputDir}'. ${suffix}`;
|
|
118
|
+
case "current-working-directory": return `${targetDescription} because it resolves to the current working directory '${diagnostics.currentWorkingDirectory ?? diagnostics.resolvedOutputDir ?? outputDir}'. ${suffix}`;
|
|
119
|
+
case "workspace-root": return `${targetDescription} because it resolves to the protected workspace root '${diagnostics.protectedWorkspaceRoot ?? diagnostics.resolvedOutputDir ?? outputDir}'. ${suffix}`;
|
|
120
|
+
case "ancestor-of-current-working-directory": return `${targetDescription} because it resolves to an ancestor directory of the current working directory '${diagnostics.currentWorkingDirectory ?? ""}'. ${suffix}`;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
//#endregion
|
|
55
124
|
//#region src/generators/formatter.ts
|
|
56
125
|
async function formatCode(outputDir, startDir) {
|
|
57
126
|
const format = await loadFormatter();
|
|
@@ -253,6 +322,17 @@ function reportSuccessfulLoads(successful) {
|
|
|
253
322
|
}
|
|
254
323
|
}
|
|
255
324
|
//#endregion
|
|
325
|
+
//#region src/generators/spec/errors/SpecBundleOutputMissingError.ts
|
|
326
|
+
var SpecBundleOutputMissingError = class extends Error {
|
|
327
|
+
name = "SpecBundleOutputMissingError";
|
|
328
|
+
constructor(inputFile, bundledSpecFile, specOutputDir) {
|
|
329
|
+
super(`Spec bundling completed but did not create the expected output '${bundledSpecFile}' for entrypoint '${inputFile}'. Expected the bundle inside '${specOutputDir}'.`);
|
|
330
|
+
this.inputFile = inputFile;
|
|
331
|
+
this.bundledSpecFile = bundledSpecFile;
|
|
332
|
+
this.specOutputDir = specOutputDir;
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
//#endregion
|
|
256
336
|
//#region src/generators/spec/specBundler.ts
|
|
257
337
|
const WINDOWS_ABSOLUTE_PATH_PATTERN = /^[A-Za-z]:[\\/]/;
|
|
258
338
|
const WINDOWS_UNC_PATH_PATTERN = /^\\\\/;
|
|
@@ -266,7 +346,7 @@ function createWrapperImportSpecifier(wrapperFile, inputFile) {
|
|
|
266
346
|
if (relativeInputFile.startsWith(".") || relativeInputFile.startsWith("..")) return relativeInputFile;
|
|
267
347
|
return `./${relativeInputFile}`;
|
|
268
348
|
}
|
|
269
|
-
async function bundle(config) {
|
|
349
|
+
async function bundle(config, deps = {}) {
|
|
270
350
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "typeweaver-spec-loader-"));
|
|
271
351
|
const wrapperFile = path.join(tempDir, "spec-entrypoint.ts");
|
|
272
352
|
const bundledSpecFile = path.join(config.specOutputDir, "spec.js");
|
|
@@ -282,7 +362,7 @@ async function bundle(config) {
|
|
|
282
362
|
""
|
|
283
363
|
].join("\n"));
|
|
284
364
|
try {
|
|
285
|
-
await build({
|
|
365
|
+
await (deps.build ?? build)({
|
|
286
366
|
cwd: tempDir,
|
|
287
367
|
input: wrapperFile,
|
|
288
368
|
treeshake: true,
|
|
@@ -302,7 +382,7 @@ async function bundle(config) {
|
|
|
302
382
|
force: true
|
|
303
383
|
});
|
|
304
384
|
}
|
|
305
|
-
if (!fs.existsSync(bundledSpecFile)) throw new
|
|
385
|
+
if (!(deps.existsSync ?? fs.existsSync)(bundledSpecFile)) throw new SpecBundleOutputMissingError(config.inputFile, bundledSpecFile, config.specOutputDir);
|
|
306
386
|
return bundledSpecFile;
|
|
307
387
|
}
|
|
308
388
|
function resolveBundledInputFile(inputFile) {
|
|
@@ -384,17 +464,32 @@ function writeSpecDeclarationFile(specOutputDir) {
|
|
|
384
464
|
const moduleDir$1 = path.dirname(fileURLToPath(import.meta.url));
|
|
385
465
|
const assertSafeCleanTarget = (outputDir, currentWorkingDirectory) => {
|
|
386
466
|
const trimmedOutputDir = outputDir.trim();
|
|
387
|
-
if (trimmedOutputDir.length === 0) throw new
|
|
467
|
+
if (trimmedOutputDir.length === 0) throw new UnsafeCleanTargetError(outputDir, "empty-path");
|
|
388
468
|
const resolvedWorkingDirectory = path.resolve(currentWorkingDirectory);
|
|
389
469
|
const canonicalWorkingDirectory = fs.realpathSync.native(resolvedWorkingDirectory);
|
|
390
470
|
const resolvedOutputDir = path.resolve(resolvedWorkingDirectory, trimmedOutputDir);
|
|
391
471
|
const canonicalOutputDir = canonicalizePathForContainment(resolvedOutputDir);
|
|
392
|
-
|
|
393
|
-
if (
|
|
472
|
+
const filesystemRoot = path.parse(canonicalOutputDir).root;
|
|
473
|
+
if (canonicalOutputDir === filesystemRoot) throw new UnsafeCleanTargetError(outputDir, "filesystem-root", {
|
|
474
|
+
resolvedOutputDir,
|
|
475
|
+
currentWorkingDirectory: resolvedWorkingDirectory,
|
|
476
|
+
filesystemRoot
|
|
477
|
+
});
|
|
478
|
+
if (resolvedOutputDir === resolvedWorkingDirectory || canonicalOutputDir === canonicalWorkingDirectory) throw new UnsafeCleanTargetError(outputDir, "current-working-directory", {
|
|
479
|
+
resolvedOutputDir,
|
|
480
|
+
currentWorkingDirectory: resolvedWorkingDirectory
|
|
481
|
+
});
|
|
394
482
|
const protectedWorkspaceRoots = [findProtectedWorkspaceRoot(resolvedWorkingDirectory), findProtectedWorkspaceRoot(canonicalWorkingDirectory)].filter((root) => root !== void 0);
|
|
395
483
|
const protectedWorkspaceRootTarget = protectedWorkspaceRoots.find((protectedWorkspaceRoot) => resolvedOutputDir === protectedWorkspaceRoot || canonicalOutputDir === fs.realpathSync.native(protectedWorkspaceRoot));
|
|
396
|
-
if (protectedWorkspaceRootTarget !== void 0) throw new
|
|
397
|
-
|
|
484
|
+
if (protectedWorkspaceRootTarget !== void 0) throw new UnsafeCleanTargetError(outputDir, "workspace-root", {
|
|
485
|
+
resolvedOutputDir,
|
|
486
|
+
currentWorkingDirectory: resolvedWorkingDirectory,
|
|
487
|
+
protectedWorkspaceRoot: protectedWorkspaceRootTarget
|
|
488
|
+
});
|
|
489
|
+
if (protectedWorkspaceRoots.length > 0 && (isSameOrDescendantOf(resolvedWorkingDirectory, resolvedOutputDir) || isSameOrDescendantOf(canonicalWorkingDirectory, canonicalOutputDir))) throw new UnsafeCleanTargetError(outputDir, "ancestor-of-current-working-directory", {
|
|
490
|
+
resolvedOutputDir,
|
|
491
|
+
currentWorkingDirectory: resolvedWorkingDirectory
|
|
492
|
+
});
|
|
398
493
|
};
|
|
399
494
|
/**
|
|
400
495
|
* Main generator for typeweaver
|
|
@@ -507,6 +602,40 @@ const isSameOrDescendantOf = (directory, ancestor) => {
|
|
|
507
602
|
return relativePath === "" || !escapesAncestor && !path.isAbsolute(relativePath);
|
|
508
603
|
};
|
|
509
604
|
//#endregion
|
|
605
|
+
//#region src/errors/MissingGenerateOptionError.ts
|
|
606
|
+
var MissingGenerateOptionError = class extends Error {
|
|
607
|
+
name = "MissingGenerateOptionError";
|
|
608
|
+
constructor(optionName, flag, configKey) {
|
|
609
|
+
super(`Missing required generate option '${optionName}'. Pass ${flag} or set '${configKey}' in the TypeWeaver config file.`);
|
|
610
|
+
this.optionName = optionName;
|
|
611
|
+
this.flag = flag;
|
|
612
|
+
this.configKey = configKey;
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
//#endregion
|
|
616
|
+
//#region src/resolveGenerateOptions.ts
|
|
617
|
+
const resolveGenerateOptions = (options, config, currentWorkingDirectory) => {
|
|
618
|
+
const inputPath = options.input ?? config.input;
|
|
619
|
+
const outputDir = options.output ?? config.output;
|
|
620
|
+
if (!inputPath) throw new MissingGenerateOptionError("input", "--input", "input");
|
|
621
|
+
if (!outputDir) throw new MissingGenerateOptionError("output", "--output", "output");
|
|
622
|
+
const resolvedInputPath = path.isAbsolute(inputPath) ? inputPath : path.join(currentWorkingDirectory, inputPath);
|
|
623
|
+
const resolvedOutputDir = path.isAbsolute(outputDir) ? outputDir : path.join(currentWorkingDirectory, outputDir);
|
|
624
|
+
const finalConfig = {
|
|
625
|
+
input: resolvedInputPath,
|
|
626
|
+
output: resolvedOutputDir,
|
|
627
|
+
format: options.format ?? config.format ?? true,
|
|
628
|
+
clean: options.clean ?? config.clean ?? true
|
|
629
|
+
};
|
|
630
|
+
if (options.plugins) finalConfig.plugins = options.plugins.split(",").map((plugin) => plugin.trim());
|
|
631
|
+
else if (config.plugins) finalConfig.plugins = config.plugins;
|
|
632
|
+
return {
|
|
633
|
+
inputPath: resolvedInputPath,
|
|
634
|
+
outputDir: resolvedOutputDir,
|
|
635
|
+
config: finalConfig
|
|
636
|
+
};
|
|
637
|
+
};
|
|
638
|
+
//#endregion
|
|
510
639
|
//#region src/cli.ts
|
|
511
640
|
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
512
641
|
const packageJson = JSON.parse(fs.readFileSync(path.join(moduleDir, "../package.json"), "utf-8"));
|
|
@@ -526,21 +655,8 @@ program.command("generate").description("Generate types, validators, and clients
|
|
|
526
655
|
process.exit(1);
|
|
527
656
|
}
|
|
528
657
|
}
|
|
529
|
-
const
|
|
530
|
-
|
|
531
|
-
if (!inputPath) throw new Error("No input spec entrypoint provided. Use --input or specify in config file.");
|
|
532
|
-
if (!outputDir) throw new Error("No output directory provided. Use --output or specify in config file.");
|
|
533
|
-
const resolvedInputPath = path.isAbsolute(inputPath) ? inputPath : path.join(execDir, inputPath);
|
|
534
|
-
const resolvedOutputDir = path.isAbsolute(outputDir) ? outputDir : path.join(execDir, outputDir);
|
|
535
|
-
const finalConfig = {
|
|
536
|
-
input: resolvedInputPath,
|
|
537
|
-
output: resolvedOutputDir,
|
|
538
|
-
format: options.format ?? config.format ?? true,
|
|
539
|
-
clean: options.clean ?? config.clean ?? true
|
|
540
|
-
};
|
|
541
|
-
if (options.plugins) finalConfig.plugins = options.plugins.split(",").map((p) => p.trim());
|
|
542
|
-
else if (config.plugins) finalConfig.plugins = config.plugins;
|
|
543
|
-
return new Generator().generate(resolvedInputPath, resolvedOutputDir, finalConfig, execDir);
|
|
658
|
+
const resolvedGenerateOptions = resolveGenerateOptions(options, config, execDir);
|
|
659
|
+
return new Generator().generate(resolvedGenerateOptions.inputPath, resolvedGenerateOptions.outputDir, resolvedGenerateOptions.config, execDir);
|
|
544
660
|
});
|
|
545
661
|
program.command("init").description("Initialize a new typeweaver project (coming soon)").action(() => {
|
|
546
662
|
console.log("The init command is coming soon!");
|
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":["moduleDir"],"sources":["../src/configLoader.ts","../src/generators/formatter.ts","../src/generators/indexFileGenerator.ts","../src/generators/errors/PluginLoadingFailure.ts","../src/generators/pluginLoader.ts","../src/generators/spec/specBundler.ts","../src/generators/spec/InvalidSpecEntrypointError.ts","../src/generators/spec/specGuards.ts","../src/generators/spec/specImporter.ts","../src/generators/specLoader.ts","../src/generators/Generator.ts","../src/cli.ts"],"sourcesContent":["import path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport type { TypeweaverConfig } from \"@rexeus/typeweaver-gen\";\n\nconst SUPPORTED_CONFIG_EXTENSIONS = new Set([\".js\", \".mjs\", \".cjs\"]);\nconst UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS = new Set([\n \".ts\",\n \".mts\",\n \".cts\",\n]);\n\nexport const getResolvedConfigPath = (\n configPath: string,\n currentWorkingDirectory: string = process.cwd()\n): string => {\n return path.isAbsolute(configPath)\n ? configPath\n : path.resolve(currentWorkingDirectory, configPath);\n};\n\nexport const assertSupportedConfigPath = (configPath: string): void => {\n const extension = path.extname(configPath).toLowerCase();\n\n if (UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS.has(extension)) {\n throw new Error(\n `TypeScript config files are no longer supported: '${configPath}'. Convert the config to .js, .mjs, or .cjs, or compile it before passing --config.`\n );\n }\n\n if (!SUPPORTED_CONFIG_EXTENSIONS.has(extension)) {\n throw new Error(\n `Unsupported config file extension for '${configPath}'. TypeWeaver only accepts .js, .mjs, or .cjs config files.`\n );\n }\n};\n\nexport const loadConfig = async (\n configPath: string\n): Promise<Partial<TypeweaverConfig>> => {\n assertSupportedConfigPath(configPath);\n\n const resolvedPath = path.resolve(configPath);\n const configUrl = pathToFileURL(resolvedPath).toString();\n const configModule = await import(configUrl);\n const loadedConfig = getConfigExport(configModule, configPath);\n\n if (!isConfigObject(loadedConfig)) {\n throw new Error(\n `Configuration file '${configPath}' must export a config object via 'export default' or 'export const config = ...'.`\n );\n }\n\n return loadedConfig;\n};\n\nconst getConfigExport = (\n configModule: Record<string, unknown>,\n configPath: string\n): unknown => {\n const hasDefaultExport = Object.hasOwn(configModule, \"default\");\n const hasNamedConfigExport = Object.hasOwn(configModule, \"config\");\n\n if (hasDefaultExport && hasNamedConfigExport) {\n throw new Error(\n `Configuration file '${configPath}' must choose a single export style: either 'export default' or 'export const config = ...', but not both.`\n );\n }\n\n if (hasDefaultExport) {\n if (isNamespaceLikeConfigExport(configModule.default)) {\n throw new Error(\n `Configuration file '${configPath}' default export must be the config object itself, not a module namespace-like wrapper. Export the config directly with 'export default { ... }' or use 'export const config = ...'.`\n );\n }\n\n return configModule.default;\n }\n\n if (hasNamedConfigExport) {\n return configModule.config;\n }\n\n throw new Error(\n `Configuration file '${configPath}' must export its config via 'export default' or 'export const config = ...'.`\n );\n};\n\nconst isConfigObject = (value: unknown): value is Partial<TypeweaverConfig> => {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n};\n\nconst isNamespaceLikeConfigExport = (value: unknown): boolean => {\n if (!isConfigObject(value)) {\n return false;\n }\n\n return Object.hasOwn(value, \"default\") || Object.hasOwn(value, \"config\");\n};\n","import fs from \"node:fs\";\nimport path from \"node:path\";\n\ntype FormatFn = (filename: string, source: string) => Promise<{ code: string }>;\n\nexport async function formatCode(\n outputDir: string,\n startDir?: string\n): Promise<void> {\n const format = await loadFormatter();\n if (!format) {\n return;\n }\n\n const targetDir = startDir ?? outputDir;\n await formatDirectory(targetDir, format);\n}\n\nasync function loadFormatter(): Promise<FormatFn | undefined> {\n try {\n const oxfmt = await import(\"oxfmt\");\n return oxfmt.format;\n } catch {\n console.warn(\n \"oxfmt not installed - skipping formatting. Install with: npm install -D oxfmt\"\n );\n return undefined;\n }\n}\n\nasync function formatDirectory(\n targetDir: string,\n format: FormatFn\n): Promise<void> {\n const contents = fs.readdirSync(targetDir, { withFileTypes: true });\n\n for (const content of contents) {\n if (content.isFile()) {\n const filePath = path.join(targetDir, content.name);\n const unformatted = fs.readFileSync(filePath, \"utf8\");\n const { code } = await format(filePath, unformatted);\n fs.writeFileSync(filePath, code);\n } else if (content.isDirectory()) {\n await formatDirectory(path.join(targetDir, content.name), format);\n }\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { renderTemplate } from \"@rexeus/typeweaver-gen\";\nimport type { GeneratorContext } from \"@rexeus/typeweaver-gen\";\n\nexport type IndexFileGenerationContext = Pick<\n GeneratorContext,\n \"outputDir\" | \"getGeneratedFiles\"\n>;\n\nexport function generateIndexFiles(\n templateDir: string,\n context: IndexFileGenerationContext\n): void {\n const templateFilePath = path.join(templateDir, \"Index.ejs\");\n const template = fs.readFileSync(templateFilePath, \"utf8\");\n\n const generatedFiles = context.getGeneratedFiles();\n const groups = new Map<string, Set<string>>();\n const rootFiles = new Set<string>();\n const existingBarrels = new Set<string>();\n\n for (const file of generatedFiles) {\n const normalizedFile = file.replace(/\\\\/g, \"/\");\n const withJsExt = normalizedFile.replace(/\\.ts$/, \".js\");\n const stripped = normalizedFile.replace(/\\.ts$/, \"\");\n const firstSlash = stripped.indexOf(\"/\");\n\n if (stripped === \"index\") {\n continue;\n }\n\n if (firstSlash === -1) {\n rootFiles.add(`./${withJsExt}`);\n continue;\n }\n\n const firstSegment = stripped.slice(0, firstSlash);\n\n if (stripped === \"lib/index\") {\n existingBarrels.add(\"lib\");\n continue;\n }\n\n if (firstSegment === \"lib\") {\n const secondSlash = stripped.indexOf(\"/\", firstSlash + 1);\n const groupKey =\n secondSlash === -1 ? stripped : stripped.slice(0, secondSlash);\n\n const entryName = stripped.slice(groupKey.length + 1);\n\n if (entryName === \"index\") {\n existingBarrels.add(groupKey);\n } else {\n if (!groups.has(groupKey)) {\n groups.set(groupKey, new Set());\n }\n groups.get(groupKey)!.add(`./${entryName}.js`);\n }\n } else {\n const entryName = stripped.slice(firstSlash + 1);\n\n if (entryName === \"index\") {\n existingBarrels.add(firstSegment);\n } else {\n if (!groups.has(firstSegment)) {\n groups.set(firstSegment, new Set());\n }\n groups.get(firstSegment)!.add(`./${entryName}.js`);\n }\n }\n }\n\n for (const [groupKey, entries] of groups) {\n if (existingBarrels.has(groupKey)) {\n continue;\n }\n\n const domainBarrelContent = renderTemplate(template, {\n indexPaths: Array.from(entries).sort(),\n });\n\n const domainIndexPath = path.join(context.outputDir, groupKey, \"index.ts\");\n fs.mkdirSync(path.dirname(domainIndexPath), { recursive: true });\n fs.writeFileSync(domainIndexPath, domainBarrelContent);\n }\n\n const rootIndexPaths = new Set<string>(rootFiles);\n for (const groupKey of groups.keys()) {\n rootIndexPaths.add(`./${groupKey}/index.js`);\n }\n for (const barrelKey of existingBarrels) {\n rootIndexPaths.add(`./${barrelKey}/index.js`);\n }\n\n const rootContent = renderTemplate(template, {\n indexPaths: Array.from(rootIndexPaths).sort(),\n });\n\n fs.writeFileSync(path.join(context.outputDir, \"index.ts\"), rootContent);\n}\n","export type PluginLoadError = {\n readonly pluginName: string;\n readonly attempts: readonly {\n readonly path: string;\n readonly error: string;\n }[];\n};\n\nexport class PluginLoadingFailure extends Error implements PluginLoadError {\n public constructor(\n public readonly pluginName: string,\n public readonly attempts: readonly {\n readonly path: string;\n readonly error: string;\n }[]\n ) {\n super(`Failed to load plugin '${pluginName}'`);\n Object.setPrototypeOf(this, PluginLoadingFailure.prototype);\n }\n}\n","import path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport type {\n PluginConfig,\n PluginConstructor,\n TypeweaverConfig,\n TypeweaverPlugin,\n} from \"@rexeus/typeweaver-gen\";\nimport { PluginLoadingFailure } from \"./errors/PluginLoadingFailure.js\";\nimport type { PluginLoadError } from \"./errors/PluginLoadingFailure.js\";\n\nexport type PluginResolutionStrategy = \"npm\" | \"local\" | \"scoped\";\n\nexport type PluginRegistrar = {\n readonly register: (plugin: TypeweaverPlugin, config?: unknown) => void;\n};\n\nexport type PluginLoadResult = {\n readonly plugin: TypeweaverPlugin;\n readonly source: string;\n readonly config?: PluginConfig;\n};\n\ntype PluginCandidate = {\n readonly exportName: string;\n readonly constructor: PluginConstructor;\n};\n\ntype LoadResult<T, E> =\n | { success: true; value: T }\n | { success: false; error: E };\n\nexport async function loadPlugins(\n registry: PluginRegistrar,\n requiredPlugins: readonly TypeweaverPlugin[],\n strategies: readonly PluginResolutionStrategy[],\n config?: TypeweaverConfig\n): Promise<void> {\n for (const requiredPlugin of requiredPlugins) {\n registry.register(requiredPlugin);\n }\n\n if (!config?.plugins) {\n return;\n }\n\n const successful: PluginLoadResult[] = [];\n\n for (const plugin of config.plugins) {\n const pluginName = typeof plugin === \"string\" ? plugin : plugin[0];\n const pluginConfig = typeof plugin === \"string\" ? undefined : plugin[1];\n const result = await loadPlugin(pluginName, strategies, pluginConfig);\n\n if (result.success === false) {\n throw new PluginLoadingFailure(\n result.error.pluginName,\n result.error.attempts\n );\n }\n\n successful.push(result.value);\n registry.register(result.value.plugin, result.value.config);\n }\n\n reportSuccessfulLoads(successful);\n}\n\nasync function loadPlugin(\n pluginName: string,\n strategies: readonly PluginResolutionStrategy[],\n pluginConfig?: PluginConfig\n): Promise<LoadResult<PluginLoadResult, PluginLoadError>> {\n const possiblePaths = generatePluginPaths(pluginName, strategies);\n const attempts: { path: string; error: string }[] = [];\n\n for (const possiblePath of possiblePaths) {\n try {\n const pluginPackage = await import(possiblePath);\n const plugin = createPluginInstance(pluginPackage, pluginConfig);\n if (plugin.success) {\n return {\n success: true,\n value: {\n plugin: plugin.value,\n source: possiblePath,\n config: pluginConfig,\n },\n };\n }\n attempts.push({\n path: possiblePath,\n error: plugin.error,\n });\n } catch (error) {\n attempts.push({\n path: possiblePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n return {\n success: false,\n error: {\n pluginName,\n attempts,\n },\n };\n}\n\nfunction createPluginInstance(\n pluginModule: Record<string, unknown>,\n pluginConfig?: PluginConfig\n): LoadResult<TypeweaverPlugin, string> {\n const candidates = findPluginConstructorCandidates(pluginModule);\n if (candidates.length === 0) {\n return {\n success: false,\n error: \"No plugin constructor export found\",\n };\n }\n\n const errors: string[] = [];\n for (const candidate of candidates) {\n try {\n const plugin = new candidate.constructor(pluginConfig);\n if (isTypeweaverPlugin(plugin)) {\n return {\n success: true,\n value: plugin,\n };\n }\n\n errors.push(\n `Export '${candidate.exportName}' did not produce a valid plugin with a string name`\n );\n } catch (error) {\n errors.push(\n `Export '${candidate.exportName}' could not be instantiated: ${formatError(error)}`\n );\n }\n }\n\n return {\n success: false,\n error: errors.join(\"; \"),\n };\n}\n\nfunction findPluginConstructorCandidates(\n pluginModule: Record<string, unknown>\n): PluginCandidate[] {\n const candidates: PluginCandidate[] = [];\n\n for (const [key, value] of Object.entries(pluginModule)) {\n if (key !== \"default\" && typeof value === \"function\") {\n candidates.push({\n exportName: key,\n constructor: value as PluginConstructor,\n });\n }\n }\n\n // Fall back to default export for third-party plugin compatibility\n const defaultExport = pluginModule.default;\n if (typeof defaultExport === \"function\") {\n candidates.push({\n exportName: \"default\",\n constructor: defaultExport as PluginConstructor,\n });\n }\n\n return candidates;\n}\n\nfunction isTypeweaverPlugin(value: unknown): value is TypeweaverPlugin {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { readonly name?: unknown }).name === \"string\" &&\n (value as { readonly name: string }).name.length > 0\n );\n}\n\nfunction formatError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction generatePluginPaths(\n pluginName: string,\n strategies: readonly PluginResolutionStrategy[]\n): string[] {\n const paths: string[] = [];\n\n for (const strategy of strategies) {\n switch (strategy) {\n case \"npm\":\n paths.push(`@rexeus/typeweaver-${pluginName}`);\n paths.push(`@rexeus/${pluginName}`);\n break;\n case \"local\":\n paths.push(toLocalImportSpecifier(pluginName));\n break;\n case \"scoped\":\n paths.push(pluginName);\n break;\n }\n }\n\n return paths;\n}\n\nfunction toLocalImportSpecifier(pluginName: string): string {\n if (pluginName.startsWith(\"file:\")) {\n return pluginName;\n }\n\n if (path.isAbsolute(pluginName)) {\n return pathToFileURL(pluginName).href;\n }\n\n return pluginName;\n}\n\nfunction reportSuccessfulLoads(successful: PluginLoadResult[]): void {\n if (successful.length > 0) {\n console.info(`Successfully loaded ${successful.length} plugin(s):`);\n for (const result of successful) {\n console.info(` - ${result.plugin.name} (from ${result.source})`);\n }\n }\n}\n","import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { build } from \"rolldown\";\n\nconst WINDOWS_ABSOLUTE_PATH_PATTERN = /^[A-Za-z]:[\\\\/]/;\nconst WINDOWS_UNC_PATH_PATTERN = /^\\\\\\\\/;\n\nexport type SpecBundlerConfig = {\n readonly inputFile: string;\n readonly specOutputDir: string;\n};\n\nexport function createWrapperImportSpecifier(\n wrapperFile: string,\n inputFile: string\n): string {\n const absoluteInputFile = resolveBundledInputFile(inputFile);\n const useWindowsPathSemantics = usesWindowsPathSemantics(\n wrapperFile,\n absoluteInputFile\n );\n const pathModule = useWindowsPathSemantics ? path.win32 : path.posix;\n const wrapperDir = useWindowsPathSemantics\n ? pathModule.dirname(wrapperFile)\n : resolveRealFilePath(pathModule.dirname(wrapperFile));\n const resolvedInputFile = useWindowsPathSemantics\n ? absoluteInputFile\n : resolveRealFilePath(absoluteInputFile);\n const relativeInputFile = pathModule\n .relative(wrapperDir, resolvedInputFile)\n .replaceAll(pathModule.sep, \"/\");\n\n if (relativeInputFile.startsWith(\".\") || relativeInputFile.startsWith(\"..\")) {\n return relativeInputFile;\n }\n\n return `./${relativeInputFile}`;\n}\n\nexport async function bundle(config: SpecBundlerConfig): Promise<string> {\n const tempDir = fs.mkdtempSync(\n path.join(os.tmpdir(), \"typeweaver-spec-loader-\")\n );\n const wrapperFile = path.join(tempDir, \"spec-entrypoint.ts\");\n const bundledSpecFile = path.join(config.specOutputDir, \"spec.js\");\n const wrapperImportSpecifier = createWrapperImportSpecifier(\n wrapperFile,\n config.inputFile\n );\n\n fs.writeFileSync(\n wrapperFile,\n [\n `import * as specModule from ${JSON.stringify(wrapperImportSpecifier)};`,\n \"const resolvedSpec =\",\n ' Reflect.get(specModule, \"spec\") ??',\n ' Reflect.get(specModule, \"default\") ??',\n \" specModule;\",\n \"\",\n \"export const spec = resolvedSpec;\",\n \"\",\n ].join(\"\\n\")\n );\n\n try {\n await build({\n cwd: tempDir,\n input: wrapperFile,\n treeshake: true,\n experimental: {\n attachDebugInfo: \"none\",\n },\n external: (source: string) => {\n if (source.startsWith(\"node:\")) {\n return true;\n }\n\n return !source.startsWith(\".\") && !path.isAbsolute(source);\n },\n output: {\n file: bundledSpecFile,\n format: \"esm\",\n },\n });\n } finally {\n fs.rmSync(tempDir, { recursive: true, force: true });\n }\n\n if (!fs.existsSync(bundledSpecFile)) {\n throw new Error(\n `Failed to bundle spec entrypoint '${config.inputFile}' to '${bundledSpecFile}'.`\n );\n }\n\n return bundledSpecFile;\n}\n\nfunction resolveBundledInputFile(inputFile: string): string {\n if (path.isAbsolute(inputFile)) {\n return inputFile;\n }\n\n if (WINDOWS_ABSOLUTE_PATH_PATTERN.test(inputFile)) {\n return path.win32.normalize(inputFile);\n }\n\n if (WINDOWS_UNC_PATH_PATTERN.test(inputFile)) {\n return path.win32.normalize(inputFile);\n }\n\n return path.resolve(inputFile);\n}\n\nfunction usesWindowsPathSemantics(...filePaths: string[]): boolean {\n return filePaths.some(filePath => {\n return (\n WINDOWS_ABSOLUTE_PATH_PATTERN.test(filePath) ||\n WINDOWS_UNC_PATH_PATTERN.test(filePath)\n );\n });\n}\n\nfunction resolveRealFilePath(filePath: string): string {\n if (!fs.existsSync(filePath)) {\n return filePath;\n }\n\n return fs.realpathSync.native(filePath);\n}\n","export class InvalidSpecEntrypointError extends Error {\n public constructor(specEntrypoint: string) {\n super(\n `Spec entrypoint '${specEntrypoint}' must export a SpecDefinition as its default export, named 'spec' export, or module namespace.`\n );\n this.name = \"InvalidSpecEntrypointError\";\n }\n}\n","import { HttpMethod, HttpStatusCode } from \"@rexeus/typeweaver-core\";\nimport type { SpecDefinition } from \"@rexeus/typeweaver-core\";\n\nconst validHttpStatusCodes = new Set<HttpStatusCode>(\n Object.values(HttpStatusCode).filter(\n (statusCode): statusCode is HttpStatusCode => typeof statusCode === \"number\"\n )\n);\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n};\n\nconst isResponseDefinition = (value: unknown): boolean => {\n if (!isRecord(value)) {\n return false;\n }\n\n return (\n typeof value.name === \"string\" &&\n value.name.length > 0 &&\n typeof value.description === \"string\" &&\n value.description.length > 0 &&\n validHttpStatusCodes.has(value.statusCode as HttpStatusCode)\n );\n};\n\nconst isOperationDefinition = (value: unknown): boolean => {\n if (!isRecord(value) || !Array.isArray(value.responses)) {\n return false;\n }\n\n return (\n typeof value.operationId === \"string\" &&\n value.operationId.length > 0 &&\n typeof value.path === \"string\" &&\n value.path.length > 0 &&\n typeof value.summary === \"string\" &&\n value.summary.length > 0 &&\n Object.values(HttpMethod).includes(value.method as HttpMethod) &&\n isRecord(value.request) &&\n value.responses.length > 0 &&\n value.responses.every(response => isResponseDefinition(response))\n );\n};\n\nconst isResourceDefinition = (value: unknown): boolean => {\n return (\n isRecord(value) &&\n Array.isArray(value.operations) &&\n value.operations.every(isOperationDefinition)\n );\n};\n\nexport const isSpecDefinition = (value: unknown): value is SpecDefinition => {\n if (!isRecord(value) || !isRecord(value.resources)) {\n return false;\n }\n\n return Object.values(value.resources).every(isResourceDefinition);\n};\n","import { createHash } from \"node:crypto\";\nimport fs from \"node:fs\";\nimport { pathToFileURL } from \"node:url\";\nimport type { SpecDefinition } from \"@rexeus/typeweaver-core\";\nimport { InvalidSpecEntrypointError } from \"./InvalidSpecEntrypointError.js\";\nimport { isSpecDefinition } from \"./specGuards.js\";\n\nexport async function importDefinition(\n bundledSpecFile: string\n): Promise<SpecDefinition> {\n const contentHash = createHash(\"sha256\")\n .update(fs.readFileSync(bundledSpecFile))\n .digest(\"hex\");\n const moduleUrl = pathToFileURL(bundledSpecFile);\n\n moduleUrl.searchParams.set(\"content\", contentHash);\n\n const specModule = (await import(moduleUrl.toString())) as {\n readonly spec?: unknown;\n readonly default?: unknown;\n };\n const definition = specModule.spec ?? specModule.default ?? specModule;\n\n if (!isSpecDefinition(definition)) {\n throw new InvalidSpecEntrypointError(bundledSpecFile);\n }\n\n return definition;\n}\n","import fs from \"node:fs\";\nimport type { SpecDefinition } from \"@rexeus/typeweaver-core\";\nimport { normalizeSpec } from \"@rexeus/typeweaver-gen\";\nimport type { NormalizedSpec } from \"@rexeus/typeweaver-gen\";\nimport { bundle } from \"./spec/specBundler.js\";\nimport { importDefinition } from \"./spec/specImporter.js\";\n\nexport type SpecLoaderConfig = {\n readonly inputFile: string;\n readonly specOutputDir: string;\n};\n\nexport type LoadedSpec = {\n readonly definition: SpecDefinition;\n readonly normalizedSpec: NormalizedSpec;\n};\n\nexport async function loadSpec(config: SpecLoaderConfig): Promise<LoadedSpec> {\n fs.mkdirSync(config.specOutputDir, { recursive: true });\n\n const bundledSpecFile = await bundle(config);\n writeSpecDeclarationFile(config.specOutputDir);\n\n const definition = await importDefinition(bundledSpecFile);\n const normalizedSpec = normalizeSpec(definition);\n\n return {\n definition,\n normalizedSpec,\n };\n}\n\nfunction writeSpecDeclarationFile(specOutputDir: string): void {\n fs.writeFileSync(\n `${specOutputDir}/spec.d.ts`,\n [\n 'import type { SpecDefinition } from \"@rexeus/typeweaver-core\";',\n \"export declare const spec: SpecDefinition;\",\n \"\",\n ].join(\"\\n\")\n );\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n createPluginContextBuilder,\n createPluginRegistry,\n} from \"@rexeus/typeweaver-gen\";\nimport type { PluginConfig, TypeweaverConfig } from \"@rexeus/typeweaver-gen\";\nimport { TypesPlugin } from \"@rexeus/typeweaver-types\";\nimport { formatCode } from \"./formatter.js\";\nimport { generateIndexFiles } from \"./indexFileGenerator.js\";\nimport { loadPlugins } from \"./pluginLoader.js\";\nimport { loadSpec } from \"./specLoader.js\";\nimport type { PluginResolutionStrategy } from \"./pluginLoader.js\";\n\nconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\nexport const assertSafeCleanTarget = (\n outputDir: string,\n currentWorkingDirectory: string\n): void => {\n const trimmedOutputDir = outputDir.trim();\n if (trimmedOutputDir.length === 0) {\n throw new Error(\n \"Refusing to clean an empty output directory path. Pass a dedicated generated output directory instead.\"\n );\n }\n\n const resolvedWorkingDirectory = path.resolve(currentWorkingDirectory);\n const canonicalWorkingDirectory = fs.realpathSync.native(\n resolvedWorkingDirectory\n );\n const resolvedOutputDir = path.resolve(\n resolvedWorkingDirectory,\n trimmedOutputDir\n );\n const canonicalOutputDir = canonicalizePathForContainment(resolvedOutputDir);\n const filesystemRoot = path.parse(canonicalOutputDir).root;\n\n if (canonicalOutputDir === filesystemRoot) {\n throw new Error(\n `Refusing to clean '${outputDir}' because it resolves to the filesystem root.`\n );\n }\n\n if (\n resolvedOutputDir === resolvedWorkingDirectory ||\n canonicalOutputDir === canonicalWorkingDirectory\n ) {\n throw new Error(\n `Refusing to clean '${outputDir}' because it resolves to the current working directory.`\n );\n }\n\n const logicalProtectedWorkspaceRoot = findProtectedWorkspaceRoot(\n resolvedWorkingDirectory\n );\n const canonicalProtectedWorkspaceRoot = findProtectedWorkspaceRoot(\n canonicalWorkingDirectory\n );\n const protectedWorkspaceRoots = [\n logicalProtectedWorkspaceRoot,\n canonicalProtectedWorkspaceRoot,\n ].filter((root): root is string => root !== undefined);\n const protectedWorkspaceRootTarget = protectedWorkspaceRoots.find(\n protectedWorkspaceRoot =>\n resolvedOutputDir === protectedWorkspaceRoot ||\n canonicalOutputDir === fs.realpathSync.native(protectedWorkspaceRoot)\n );\n\n if (protectedWorkspaceRootTarget !== undefined) {\n throw new Error(\n `Refusing to clean '${outputDir}' because it resolves to the inferred workspace root '${protectedWorkspaceRootTarget}'. Choose a dedicated output subdirectory instead.`\n );\n }\n\n if (\n protectedWorkspaceRoots.length > 0 &&\n (isSameOrDescendantOf(resolvedWorkingDirectory, resolvedOutputDir) ||\n isSameOrDescendantOf(canonicalWorkingDirectory, canonicalOutputDir))\n ) {\n throw new Error(\n `Refusing to clean '${outputDir}' because it resolves to an ancestor directory of the current working directory. Choose a dedicated output subdirectory instead.`\n );\n }\n};\n\n/**\n * Main generator for typeweaver\n * Uses a plugin-based architecture for extensible code generation\n */\nexport class Generator {\n public readonly coreDir = \"@rexeus/typeweaver-core\";\n public readonly templateDir = path.join(moduleDir, \"templates\");\n\n private readonly registry = createPluginRegistry();\n private readonly contextBuilder = createPluginContextBuilder();\n private readonly requiredPlugins: [TypesPlugin];\n private readonly strategies: PluginResolutionStrategy[];\n\n private inputFile = \"\";\n private outputDir = \"\";\n private specOutputDir = \"\";\n private responsesOutputDir = \"\";\n\n public constructor(\n requiredPlugins: [TypesPlugin] = [new TypesPlugin()],\n strategies?: PluginResolutionStrategy[]\n ) {\n this.requiredPlugins = requiredPlugins;\n this.strategies = strategies ?? [\"npm\", \"local\"];\n }\n\n /**\n * Generate code using the plugin system\n */\n public async generate(\n specFile: string,\n outputDir: string,\n config?: TypeweaverConfig,\n currentWorkingDirectory: string = process.cwd()\n ): Promise<void> {\n console.info(\"Starting generation...\");\n\n this.initializeDirectories(specFile, outputDir, currentWorkingDirectory);\n\n if (config?.clean ?? true) {\n assertSafeCleanTarget(this.outputDir, currentWorkingDirectory);\n console.info(\"Cleaning output directory...\");\n fs.rmSync(this.outputDir, { recursive: true, force: true });\n }\n\n fs.mkdirSync(this.outputDir, { recursive: true });\n fs.mkdirSync(this.responsesOutputDir, { recursive: true });\n fs.mkdirSync(this.specOutputDir, { recursive: true });\n\n await loadPlugins(\n this.registry,\n this.requiredPlugins,\n this.strategies,\n config\n );\n\n console.info(\n `Bundling spec from '${this.inputFile}' to '${this.specOutputDir}'...`\n );\n let { normalizedSpec } = await loadSpec({\n inputFile: this.inputFile,\n specOutputDir: this.specOutputDir,\n });\n\n const pluginContext = this.contextBuilder.createPluginContext({\n outputDir: this.outputDir,\n inputDir: path.dirname(this.inputFile),\n config: (config ?? {}) as PluginConfig,\n });\n\n console.info(\"Initializing plugins...\");\n for (const registration of this.registry.getAll()) {\n if (registration.plugin.initialize) {\n await registration.plugin.initialize(pluginContext);\n }\n }\n\n console.info(\"Collecting resources...\");\n for (const registration of this.registry.getAll()) {\n if (registration.plugin.collectResources) {\n normalizedSpec =\n await registration.plugin.collectResources(normalizedSpec);\n }\n }\n\n const generatorContext = this.contextBuilder.createGeneratorContext({\n outputDir: this.outputDir,\n inputDir: path.dirname(this.inputFile),\n config: (config ?? {}) as PluginConfig,\n normalizedSpec,\n templateDir: this.templateDir,\n coreDir: this.coreDir,\n responsesOutputDir: this.responsesOutputDir,\n specOutputDir: this.specOutputDir,\n });\n\n console.info(\"Generating code...\");\n for (const registration of this.registry.getAll()) {\n console.info(`Running plugin: ${registration.plugin.name}`);\n if (registration.plugin.generate) {\n await registration.plugin.generate(generatorContext);\n }\n }\n\n generateIndexFiles(this.templateDir, generatorContext);\n\n console.info(\"Finalizing plugins...\");\n for (const registration of this.registry.getAll()) {\n if (registration.plugin.finalize) {\n await registration.plugin.finalize(pluginContext);\n }\n }\n\n if (config?.format ?? true) {\n await formatCode(this.outputDir);\n }\n\n console.info(\"Generation complete!\");\n console.info(\n `Generated files: ${this.contextBuilder.getGeneratedFiles().length}`\n );\n }\n\n private initializeDirectories(\n specFile: string,\n outputDir: string,\n currentWorkingDirectory: string\n ): void {\n this.inputFile = path.resolve(currentWorkingDirectory, specFile);\n this.outputDir = path.resolve(currentWorkingDirectory, outputDir);\n this.responsesOutputDir = path.join(this.outputDir, \"responses\");\n this.specOutputDir = path.join(this.outputDir, \"spec\");\n }\n}\n\nconst findProtectedWorkspaceRoot = (\n startDirectory: string\n): string | undefined => {\n let currentDirectory = startDirectory;\n\n while (true) {\n if (hasWorkspaceMarker(currentDirectory)) {\n return currentDirectory;\n }\n\n const parentDirectory = path.dirname(currentDirectory);\n if (parentDirectory === currentDirectory) {\n return undefined;\n }\n\n currentDirectory = parentDirectory;\n }\n};\n\nconst hasWorkspaceMarker = (directory: string): boolean => {\n return [\"pnpm-workspace.yaml\", \".git\"].some(marker =>\n fs.existsSync(path.join(directory, marker))\n );\n};\n\nconst canonicalizePathForContainment = (targetPath: string): string => {\n const remainingSegments: string[] = [];\n let nearestExistingPath = path.resolve(targetPath);\n\n while (!fs.existsSync(nearestExistingPath)) {\n const parentPath = path.dirname(nearestExistingPath);\n if (parentPath === nearestExistingPath) {\n break;\n }\n\n remainingSegments.unshift(path.basename(nearestExistingPath));\n nearestExistingPath = parentPath;\n }\n\n const canonicalExistingPath = fs.realpathSync.native(nearestExistingPath);\n\n return path.join(canonicalExistingPath, ...remainingSegments);\n};\n\nconst isSameOrDescendantOf = (directory: string, ancestor: string): boolean => {\n const relativePath = path.relative(ancestor, directory);\n const parentTraversalPrefix = `..${path.sep}`;\n const escapesAncestor =\n relativePath === \"..\" || relativePath.startsWith(parentTraversalPrefix);\n\n return (\n relativePath === \"\" || (!escapesAncestor && !path.isAbsolute(relativePath))\n );\n};\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { TypeweaverConfig } from \"@rexeus/typeweaver-gen\";\nimport { Command } from \"commander\";\nimport { getResolvedConfigPath, loadConfig } from \"./configLoader.js\";\nimport { Generator } from \"./generators/Generator.js\";\nimport type { CommandOptions as CommanderOptions } from \"commander\";\n\nconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\nconst packageJson = JSON.parse(\n fs.readFileSync(path.join(moduleDir, \"../package.json\"), \"utf-8\")\n) as {\n readonly version: string;\n readonly name: string;\n readonly description: string;\n};\n\ntype CommandOptions = CommanderOptions & {\n input?: string;\n output?: string;\n config?: string;\n plugins?: string;\n format?: boolean;\n clean?: boolean;\n};\n\nconst program = new Command();\nconst execDir = process.cwd();\n\nprogram\n .name(\"@rexeus/typeweaver\")\n .description(\"Type-safe API framework with code generation for TypeScript\")\n .version(packageJson.version);\n\nprogram\n .command(\"generate\")\n .description(\"Generate types, validators, and clients from an API spec\")\n .option(\"-i, --input <inputPath>\", \"path to spec entrypoint file\")\n .option(\"-o, --output <outputDir>\", \"output directory for generated files\")\n .option(\n \"-c, --config <configFile>\",\n \"path to a .js, .mjs, or .cjs configuration file\"\n )\n .option(\"-p, --plugins <plugins>\", \"comma-separated list of plugins to use\")\n .option(\"--format\", \"format generated code with oxfmt (default: true)\")\n .option(\"--no-format\", \"disable code formatting\")\n .option(\"--clean\", \"clean output directory before generation (default: true)\")\n .option(\"--no-clean\", \"disable cleaning output directory\")\n .action(async (options: CommandOptions) => {\n let config: Partial<TypeweaverConfig> = {};\n\n // Load configuration file if provided\n if (options.config) {\n const configPath = getResolvedConfigPath(options.config, execDir);\n\n try {\n config = await loadConfig(configPath);\n console.info(`Loaded configuration from ${configPath}`);\n } catch (error) {\n console.error(`Failed to load configuration file: ${options.config}`);\n console.error(error);\n process.exit(1);\n }\n }\n\n // Override with CLI options\n const inputPath = options.input ?? config.input;\n const outputDir = options.output ?? config.output;\n // Validate required options\n if (!inputPath) {\n throw new Error(\n \"No input spec entrypoint provided. Use --input or specify in config file.\"\n );\n }\n if (!outputDir) {\n throw new Error(\n \"No output directory provided. Use --output or specify in config file.\"\n );\n }\n\n // Resolve paths\n const resolvedInputPath = path.isAbsolute(inputPath)\n ? inputPath\n : path.join(execDir, inputPath);\n const resolvedOutputDir = path.isAbsolute(outputDir)\n ? outputDir\n : path.join(execDir, outputDir);\n\n // Build final configuration\n const finalConfig: TypeweaverConfig = {\n input: resolvedInputPath,\n output: resolvedOutputDir,\n format: options.format ?? config.format ?? true,\n clean: options.clean ?? config.clean ?? true,\n };\n\n // Handle plugins\n if (options.plugins) {\n // Parse comma-separated plugins from CLI\n finalConfig.plugins = options.plugins.split(\",\").map(p => p.trim());\n } else if (config.plugins) {\n // Use plugins from config file\n finalConfig.plugins = config.plugins;\n }\n // If no plugins specified, Generator will use defaults\n\n // Run generation\n const generator = new Generator();\n return generator.generate(\n resolvedInputPath,\n resolvedOutputDir,\n finalConfig,\n execDir\n );\n });\n\n// Add future commands placeholder\nprogram\n .command(\"init\")\n .description(\"Initialize a new typeweaver project (coming soon)\")\n .action(() => {\n console.log(\"The init command is coming soon!\");\n });\n\nprogram.parse(process.argv);\n"],"mappings":";;;;;;;;;;;AAIA,MAAM,8BAA8B,IAAI,IAAI;CAAC;CAAO;CAAQ;CAAO,CAAC;AACpE,MAAM,2CAA2C,IAAI,IAAI;CACvD;CACA;CACA;CACD,CAAC;AAEF,MAAa,yBACX,YACA,0BAAkC,QAAQ,KAAK,KACpC;AACX,QAAO,KAAK,WAAW,WAAW,GAC9B,aACA,KAAK,QAAQ,yBAAyB,WAAW;;AAGvD,MAAa,6BAA6B,eAA6B;CACrE,MAAM,YAAY,KAAK,QAAQ,WAAW,CAAC,aAAa;AAExD,KAAI,yCAAyC,IAAI,UAAU,CACzD,OAAM,IAAI,MACR,qDAAqD,WAAW,qFACjE;AAGH,KAAI,CAAC,4BAA4B,IAAI,UAAU,CAC7C,OAAM,IAAI,MACR,0CAA0C,WAAW,6DACtD;;AAIL,MAAa,aAAa,OACxB,eACuC;AACvC,2BAA0B,WAAW;CAKrC,MAAM,eAAe,gBADA,MAAM,OADT,cADG,KAAK,QAAQ,WAAW,CACA,CAAC,UAAU,GAEL,WAAW;AAE9D,KAAI,CAAC,eAAe,aAAa,CAC/B,OAAM,IAAI,MACR,uBAAuB,WAAW,oFACnC;AAGH,QAAO;;AAGT,MAAM,mBACJ,cACA,eACY;CACZ,MAAM,mBAAmB,OAAO,OAAO,cAAc,UAAU;CAC/D,MAAM,uBAAuB,OAAO,OAAO,cAAc,SAAS;AAElE,KAAI,oBAAoB,qBACtB,OAAM,IAAI,MACR,uBAAuB,WAAW,4GACnC;AAGH,KAAI,kBAAkB;AACpB,MAAI,4BAA4B,aAAa,QAAQ,CACnD,OAAM,IAAI,MACR,uBAAuB,WAAW,sLACnC;AAGH,SAAO,aAAa;;AAGtB,KAAI,qBACF,QAAO,aAAa;AAGtB,OAAM,IAAI,MACR,uBAAuB,WAAW,+EACnC;;AAGH,MAAM,kBAAkB,UAAuD;AAC7E,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;AAG7E,MAAM,+BAA+B,UAA4B;AAC/D,KAAI,CAAC,eAAe,MAAM,CACxB,QAAO;AAGT,QAAO,OAAO,OAAO,OAAO,UAAU,IAAI,OAAO,OAAO,OAAO,SAAS;;;;AC3F1E,eAAsB,WACpB,WACA,UACe;CACf,MAAM,SAAS,MAAM,eAAe;AACpC,KAAI,CAAC,OACH;AAIF,OAAM,gBADY,YAAY,WACG,OAAO;;AAG1C,eAAe,gBAA+C;AAC5D,KAAI;AAEF,UADc,MAAM,OAAO,UACd;SACP;AACN,UAAQ,KACN,gFACD;AACD;;;AAIJ,eAAe,gBACb,WACA,QACe;CACf,MAAM,WAAW,GAAG,YAAY,WAAW,EAAE,eAAe,MAAM,CAAC;AAEnE,MAAK,MAAM,WAAW,SACpB,KAAI,QAAQ,QAAQ,EAAE;EACpB,MAAM,WAAW,KAAK,KAAK,WAAW,QAAQ,KAAK;EAEnD,MAAM,EAAE,SAAS,MAAM,OAAO,UADV,GAAG,aAAa,UAAU,OAAO,CACD;AACpD,KAAG,cAAc,UAAU,KAAK;YACvB,QAAQ,aAAa,CAC9B,OAAM,gBAAgB,KAAK,KAAK,WAAW,QAAQ,KAAK,EAAE,OAAO;;;;ACjCvE,SAAgB,mBACd,aACA,SACM;CACN,MAAM,mBAAmB,KAAK,KAAK,aAAa,YAAY;CAC5D,MAAM,WAAW,GAAG,aAAa,kBAAkB,OAAO;CAE1D,MAAM,iBAAiB,QAAQ,mBAAmB;CAClD,MAAM,yBAAS,IAAI,KAA0B;CAC7C,MAAM,4BAAY,IAAI,KAAa;CACnC,MAAM,kCAAkB,IAAI,KAAa;AAEzC,MAAK,MAAM,QAAQ,gBAAgB;EACjC,MAAM,iBAAiB,KAAK,QAAQ,OAAO,IAAI;EAC/C,MAAM,YAAY,eAAe,QAAQ,SAAS,MAAM;EACxD,MAAM,WAAW,eAAe,QAAQ,SAAS,GAAG;EACpD,MAAM,aAAa,SAAS,QAAQ,IAAI;AAExC,MAAI,aAAa,QACf;AAGF,MAAI,eAAe,IAAI;AACrB,aAAU,IAAI,KAAK,YAAY;AAC/B;;EAGF,MAAM,eAAe,SAAS,MAAM,GAAG,WAAW;AAElD,MAAI,aAAa,aAAa;AAC5B,mBAAgB,IAAI,MAAM;AAC1B;;AAGF,MAAI,iBAAiB,OAAO;GAC1B,MAAM,cAAc,SAAS,QAAQ,KAAK,aAAa,EAAE;GACzD,MAAM,WACJ,gBAAgB,KAAK,WAAW,SAAS,MAAM,GAAG,YAAY;GAEhE,MAAM,YAAY,SAAS,MAAM,SAAS,SAAS,EAAE;AAErD,OAAI,cAAc,QAChB,iBAAgB,IAAI,SAAS;QACxB;AACL,QAAI,CAAC,OAAO,IAAI,SAAS,CACvB,QAAO,IAAI,0BAAU,IAAI,KAAK,CAAC;AAEjC,WAAO,IAAI,SAAS,CAAE,IAAI,KAAK,UAAU,KAAK;;SAE3C;GACL,MAAM,YAAY,SAAS,MAAM,aAAa,EAAE;AAEhD,OAAI,cAAc,QAChB,iBAAgB,IAAI,aAAa;QAC5B;AACL,QAAI,CAAC,OAAO,IAAI,aAAa,CAC3B,QAAO,IAAI,8BAAc,IAAI,KAAK,CAAC;AAErC,WAAO,IAAI,aAAa,CAAE,IAAI,KAAK,UAAU,KAAK;;;;AAKxD,MAAK,MAAM,CAAC,UAAU,YAAY,QAAQ;AACxC,MAAI,gBAAgB,IAAI,SAAS,CAC/B;EAGF,MAAM,sBAAsB,eAAe,UAAU,EACnD,YAAY,MAAM,KAAK,QAAQ,CAAC,MAAM,EACvC,CAAC;EAEF,MAAM,kBAAkB,KAAK,KAAK,QAAQ,WAAW,UAAU,WAAW;AAC1E,KAAG,UAAU,KAAK,QAAQ,gBAAgB,EAAE,EAAE,WAAW,MAAM,CAAC;AAChE,KAAG,cAAc,iBAAiB,oBAAoB;;CAGxD,MAAM,iBAAiB,IAAI,IAAY,UAAU;AACjD,MAAK,MAAM,YAAY,OAAO,MAAM,CAClC,gBAAe,IAAI,KAAK,SAAS,WAAW;AAE9C,MAAK,MAAM,aAAa,gBACtB,gBAAe,IAAI,KAAK,UAAU,WAAW;CAG/C,MAAM,cAAc,eAAe,UAAU,EAC3C,YAAY,MAAM,KAAK,eAAe,CAAC,MAAM,EAC9C,CAAC;AAEF,IAAG,cAAc,KAAK,KAAK,QAAQ,WAAW,WAAW,EAAE,YAAY;;;;AC3FzE,IAAa,uBAAb,MAAa,6BAA6B,MAAiC;CACzE,YACE,YACA,UAIA;AACA,QAAM,0BAA0B,WAAW,GAAG;AAN9B,OAAA,aAAA;AACA,OAAA,WAAA;AAMhB,SAAO,eAAe,MAAM,qBAAqB,UAAU;;;;;ACe/D,eAAsB,YACpB,UACA,iBACA,YACA,QACe;AACf,MAAK,MAAM,kBAAkB,gBAC3B,UAAS,SAAS,eAAe;AAGnC,KAAI,CAAC,QAAQ,QACX;CAGF,MAAM,aAAiC,EAAE;AAEzC,MAAK,MAAM,UAAU,OAAO,SAAS;EAGnC,MAAM,SAAS,MAAM,WAFF,OAAO,WAAW,WAAW,SAAS,OAAO,IAEpB,YADvB,OAAO,WAAW,WAAW,KAAA,IAAY,OAAO,GACA;AAErE,MAAI,OAAO,YAAY,MACrB,OAAM,IAAI,qBACR,OAAO,MAAM,YACb,OAAO,MAAM,SACd;AAGH,aAAW,KAAK,OAAO,MAAM;AAC7B,WAAS,SAAS,OAAO,MAAM,QAAQ,OAAO,MAAM,OAAO;;AAG7D,uBAAsB,WAAW;;AAGnC,eAAe,WACb,YACA,YACA,cACwD;CACxD,MAAM,gBAAgB,oBAAoB,YAAY,WAAW;CACjE,MAAM,WAA8C,EAAE;AAEtD,MAAK,MAAM,gBAAgB,cACzB,KAAI;EAEF,MAAM,SAAS,qBADO,MAAM,OAAO,eACgB,aAAa;AAChE,MAAI,OAAO,QACT,QAAO;GACL,SAAS;GACT,OAAO;IACL,QAAQ,OAAO;IACf,QAAQ;IACR,QAAQ;IACT;GACF;AAEH,WAAS,KAAK;GACZ,MAAM;GACN,OAAO,OAAO;GACf,CAAC;UACK,OAAO;AACd,WAAS,KAAK;GACZ,MAAM;GACN,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;GAC9D,CAAC;;AAIN,QAAO;EACL,SAAS;EACT,OAAO;GACL;GACA;GACD;EACF;;AAGH,SAAS,qBACP,cACA,cACsC;CACtC,MAAM,aAAa,gCAAgC,aAAa;AAChE,KAAI,WAAW,WAAW,EACxB,QAAO;EACL,SAAS;EACT,OAAO;EACR;CAGH,MAAM,SAAmB,EAAE;AAC3B,MAAK,MAAM,aAAa,WACtB,KAAI;EACF,MAAM,SAAS,IAAI,UAAU,YAAY,aAAa;AACtD,MAAI,mBAAmB,OAAO,CAC5B,QAAO;GACL,SAAS;GACT,OAAO;GACR;AAGH,SAAO,KACL,WAAW,UAAU,WAAW,qDACjC;UACM,OAAO;AACd,SAAO,KACL,WAAW,UAAU,WAAW,+BAA+B,YAAY,MAAM,GAClF;;AAIL,QAAO;EACL,SAAS;EACT,OAAO,OAAO,KAAK,KAAK;EACzB;;AAGH,SAAS,gCACP,cACmB;CACnB,MAAM,aAAgC,EAAE;AAExC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,aAAa,CACrD,KAAI,QAAQ,aAAa,OAAO,UAAU,WACxC,YAAW,KAAK;EACd,YAAY;EACZ,aAAa;EACd,CAAC;CAKN,MAAM,gBAAgB,aAAa;AACnC,KAAI,OAAO,kBAAkB,WAC3B,YAAW,KAAK;EACd,YAAY;EACZ,aAAa;EACd,CAAC;AAGJ,QAAO;;AAGT,SAAS,mBAAmB,OAA2C;AACrE,QACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAAsC,SAAS,YACtD,MAAoC,KAAK,SAAS;;AAIvD,SAAS,YAAY,OAAwB;AAC3C,QAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;;AAG/D,SAAS,oBACP,YACA,YACU;CACV,MAAM,QAAkB,EAAE;AAE1B,MAAK,MAAM,YAAY,WACrB,SAAQ,UAAR;EACE,KAAK;AACH,SAAM,KAAK,sBAAsB,aAAa;AAC9C,SAAM,KAAK,WAAW,aAAa;AACnC;EACF,KAAK;AACH,SAAM,KAAK,uBAAuB,WAAW,CAAC;AAC9C;EACF,KAAK;AACH,SAAM,KAAK,WAAW;AACtB;;AAIN,QAAO;;AAGT,SAAS,uBAAuB,YAA4B;AAC1D,KAAI,WAAW,WAAW,QAAQ,CAChC,QAAO;AAGT,KAAI,KAAK,WAAW,WAAW,CAC7B,QAAO,cAAc,WAAW,CAAC;AAGnC,QAAO;;AAGT,SAAS,sBAAsB,YAAsC;AACnE,KAAI,WAAW,SAAS,GAAG;AACzB,UAAQ,KAAK,uBAAuB,WAAW,OAAO,aAAa;AACnE,OAAK,MAAM,UAAU,WACnB,SAAQ,KAAK,OAAO,OAAO,OAAO,KAAK,SAAS,OAAO,OAAO,GAAG;;;;;AC/NvE,MAAM,gCAAgC;AACtC,MAAM,2BAA2B;AAOjC,SAAgB,6BACd,aACA,WACQ;CACR,MAAM,oBAAoB,wBAAwB,UAAU;CAC5D,MAAM,0BAA0B,yBAC9B,aACA,kBACD;CACD,MAAM,aAAa,0BAA0B,KAAK,QAAQ,KAAK;CAC/D,MAAM,aAAa,0BACf,WAAW,QAAQ,YAAY,GAC/B,oBAAoB,WAAW,QAAQ,YAAY,CAAC;CACxD,MAAM,oBAAoB,0BACtB,oBACA,oBAAoB,kBAAkB;CAC1C,MAAM,oBAAoB,WACvB,SAAS,YAAY,kBAAkB,CACvC,WAAW,WAAW,KAAK,IAAI;AAElC,KAAI,kBAAkB,WAAW,IAAI,IAAI,kBAAkB,WAAW,KAAK,CACzE,QAAO;AAGT,QAAO,KAAK;;AAGd,eAAsB,OAAO,QAA4C;CACvE,MAAM,UAAU,GAAG,YACjB,KAAK,KAAK,GAAG,QAAQ,EAAE,0BAA0B,CAClD;CACD,MAAM,cAAc,KAAK,KAAK,SAAS,qBAAqB;CAC5D,MAAM,kBAAkB,KAAK,KAAK,OAAO,eAAe,UAAU;CAClE,MAAM,yBAAyB,6BAC7B,aACA,OAAO,UACR;AAED,IAAG,cACD,aACA;EACE,+BAA+B,KAAK,UAAU,uBAAuB,CAAC;EACtE;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,KAAK,KAAK,CACb;AAED,KAAI;AACF,QAAM,MAAM;GACV,KAAK;GACL,OAAO;GACP,WAAW;GACX,cAAc,EACZ,iBAAiB,QAClB;GACD,WAAW,WAAmB;AAC5B,QAAI,OAAO,WAAW,QAAQ,CAC5B,QAAO;AAGT,WAAO,CAAC,OAAO,WAAW,IAAI,IAAI,CAAC,KAAK,WAAW,OAAO;;GAE5D,QAAQ;IACN,MAAM;IACN,QAAQ;IACT;GACF,CAAC;WACM;AACR,KAAG,OAAO,SAAS;GAAE,WAAW;GAAM,OAAO;GAAM,CAAC;;AAGtD,KAAI,CAAC,GAAG,WAAW,gBAAgB,CACjC,OAAM,IAAI,MACR,qCAAqC,OAAO,UAAU,QAAQ,gBAAgB,IAC/E;AAGH,QAAO;;AAGT,SAAS,wBAAwB,WAA2B;AAC1D,KAAI,KAAK,WAAW,UAAU,CAC5B,QAAO;AAGT,KAAI,8BAA8B,KAAK,UAAU,CAC/C,QAAO,KAAK,MAAM,UAAU,UAAU;AAGxC,KAAI,yBAAyB,KAAK,UAAU,CAC1C,QAAO,KAAK,MAAM,UAAU,UAAU;AAGxC,QAAO,KAAK,QAAQ,UAAU;;AAGhC,SAAS,yBAAyB,GAAG,WAA8B;AACjE,QAAO,UAAU,MAAK,aAAY;AAChC,SACE,8BAA8B,KAAK,SAAS,IAC5C,yBAAyB,KAAK,SAAS;GAEzC;;AAGJ,SAAS,oBAAoB,UAA0B;AACrD,KAAI,CAAC,GAAG,WAAW,SAAS,CAC1B,QAAO;AAGT,QAAO,GAAG,aAAa,OAAO,SAAS;;;;AChIzC,IAAa,6BAAb,cAAgD,MAAM;CACpD,YAAmB,gBAAwB;AACzC,QACE,oBAAoB,eAAe,iGACpC;AACD,OAAK,OAAO;;;;;ACFhB,MAAM,uBAAuB,IAAI,IAC/B,OAAO,OAAO,eAAe,CAAC,QAC3B,eAA6C,OAAO,eAAe,SACrE,CACF;AAED,MAAM,YAAY,UAAqD;AACrE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;AAG7E,MAAM,wBAAwB,UAA4B;AACxD,KAAI,CAAC,SAAS,MAAM,CAClB,QAAO;AAGT,QACE,OAAO,MAAM,SAAS,YACtB,MAAM,KAAK,SAAS,KACpB,OAAO,MAAM,gBAAgB,YAC7B,MAAM,YAAY,SAAS,KAC3B,qBAAqB,IAAI,MAAM,WAA6B;;AAIhE,MAAM,yBAAyB,UAA4B;AACzD,KAAI,CAAC,SAAS,MAAM,IAAI,CAAC,MAAM,QAAQ,MAAM,UAAU,CACrD,QAAO;AAGT,QACE,OAAO,MAAM,gBAAgB,YAC7B,MAAM,YAAY,SAAS,KAC3B,OAAO,MAAM,SAAS,YACtB,MAAM,KAAK,SAAS,KACpB,OAAO,MAAM,YAAY,YACzB,MAAM,QAAQ,SAAS,KACvB,OAAO,OAAO,WAAW,CAAC,SAAS,MAAM,OAAqB,IAC9D,SAAS,MAAM,QAAQ,IACvB,MAAM,UAAU,SAAS,KACzB,MAAM,UAAU,OAAM,aAAY,qBAAqB,SAAS,CAAC;;AAIrE,MAAM,wBAAwB,UAA4B;AACxD,QACE,SAAS,MAAM,IACf,MAAM,QAAQ,MAAM,WAAW,IAC/B,MAAM,WAAW,MAAM,sBAAsB;;AAIjD,MAAa,oBAAoB,UAA4C;AAC3E,KAAI,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,MAAM,UAAU,CAChD,QAAO;AAGT,QAAO,OAAO,OAAO,MAAM,UAAU,CAAC,MAAM,qBAAqB;;;;ACpDnE,eAAsB,iBACpB,iBACyB;CACzB,MAAM,cAAc,WAAW,SAAS,CACrC,OAAO,GAAG,aAAa,gBAAgB,CAAC,CACxC,OAAO,MAAM;CAChB,MAAM,YAAY,cAAc,gBAAgB;AAEhD,WAAU,aAAa,IAAI,WAAW,YAAY;CAElD,MAAM,aAAc,MAAM,OAAO,UAAU,UAAU;CAIrD,MAAM,aAAa,WAAW,QAAQ,WAAW,WAAW;AAE5D,KAAI,CAAC,iBAAiB,WAAW,CAC/B,OAAM,IAAI,2BAA2B,gBAAgB;AAGvD,QAAO;;;;ACVT,eAAsB,SAAS,QAA+C;AAC5E,IAAG,UAAU,OAAO,eAAe,EAAE,WAAW,MAAM,CAAC;CAEvD,MAAM,kBAAkB,MAAM,OAAO,OAAO;AAC5C,0BAAyB,OAAO,cAAc;CAE9C,MAAM,aAAa,MAAM,iBAAiB,gBAAgB;AAG1D,QAAO;EACL;EACA,gBAJqB,cAAc,WAAW;EAK/C;;AAGH,SAAS,yBAAyB,eAA6B;AAC7D,IAAG,cACD,GAAG,cAAc,aACjB;EACE;EACA;EACA;EACD,CAAC,KAAK,KAAK,CACb;;;;ACzBH,MAAMA,cAAY,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAE9D,MAAa,yBACX,WACA,4BACS;CACT,MAAM,mBAAmB,UAAU,MAAM;AACzC,KAAI,iBAAiB,WAAW,EAC9B,OAAM,IAAI,MACR,yGACD;CAGH,MAAM,2BAA2B,KAAK,QAAQ,wBAAwB;CACtE,MAAM,4BAA4B,GAAG,aAAa,OAChD,yBACD;CACD,MAAM,oBAAoB,KAAK,QAC7B,0BACA,iBACD;CACD,MAAM,qBAAqB,+BAA+B,kBAAkB;AAG5E,KAAI,uBAFmB,KAAK,MAAM,mBAAmB,CAAC,KAGpD,OAAM,IAAI,MACR,sBAAsB,UAAU,+CACjC;AAGH,KACE,sBAAsB,4BACtB,uBAAuB,0BAEvB,OAAM,IAAI,MACR,sBAAsB,UAAU,yDACjC;CASH,MAAM,0BAA0B,CANM,2BACpC,yBACD,EACuC,2BACtC,0BACD,CAIA,CAAC,QAAQ,SAAyB,SAAS,KAAA,EAAU;CACtD,MAAM,+BAA+B,wBAAwB,MAC3D,2BACE,sBAAsB,0BACtB,uBAAuB,GAAG,aAAa,OAAO,uBAAuB,CACxE;AAED,KAAI,iCAAiC,KAAA,EACnC,OAAM,IAAI,MACR,sBAAsB,UAAU,wDAAwD,6BAA6B,oDACtH;AAGH,KACE,wBAAwB,SAAS,MAChC,qBAAqB,0BAA0B,kBAAkB,IAChE,qBAAqB,2BAA2B,mBAAmB,EAErE,OAAM,IAAI,MACR,sBAAsB,UAAU,kIACjC;;;;;;AAQL,IAAa,YAAb,MAAuB;CACrB,UAA0B;CAC1B,cAA8B,KAAK,KAAKA,aAAW,YAAY;CAE/D,WAA4B,sBAAsB;CAClD,iBAAkC,4BAA4B;CAC9D;CACA;CAEA,YAAoB;CACpB,YAAoB;CACpB,gBAAwB;CACxB,qBAA6B;CAE7B,YACE,kBAAiC,CAAC,IAAI,aAAa,CAAC,EACpD,YACA;AACA,OAAK,kBAAkB;AACvB,OAAK,aAAa,cAAc,CAAC,OAAO,QAAQ;;;;;CAMlD,MAAa,SACX,UACA,WACA,QACA,0BAAkC,QAAQ,KAAK,EAChC;AACf,UAAQ,KAAK,yBAAyB;AAEtC,OAAK,sBAAsB,UAAU,WAAW,wBAAwB;AAExE,MAAI,QAAQ,SAAS,MAAM;AACzB,yBAAsB,KAAK,WAAW,wBAAwB;AAC9D,WAAQ,KAAK,+BAA+B;AAC5C,MAAG,OAAO,KAAK,WAAW;IAAE,WAAW;IAAM,OAAO;IAAM,CAAC;;AAG7D,KAAG,UAAU,KAAK,WAAW,EAAE,WAAW,MAAM,CAAC;AACjD,KAAG,UAAU,KAAK,oBAAoB,EAAE,WAAW,MAAM,CAAC;AAC1D,KAAG,UAAU,KAAK,eAAe,EAAE,WAAW,MAAM,CAAC;AAErD,QAAM,YACJ,KAAK,UACL,KAAK,iBACL,KAAK,YACL,OACD;AAED,UAAQ,KACN,uBAAuB,KAAK,UAAU,QAAQ,KAAK,cAAc,MAClE;EACD,IAAI,EAAE,mBAAmB,MAAM,SAAS;GACtC,WAAW,KAAK;GAChB,eAAe,KAAK;GACrB,CAAC;EAEF,MAAM,gBAAgB,KAAK,eAAe,oBAAoB;GAC5D,WAAW,KAAK;GAChB,UAAU,KAAK,QAAQ,KAAK,UAAU;GACtC,QAAS,UAAU,EAAE;GACtB,CAAC;AAEF,UAAQ,KAAK,0BAA0B;AACvC,OAAK,MAAM,gBAAgB,KAAK,SAAS,QAAQ,CAC/C,KAAI,aAAa,OAAO,WACtB,OAAM,aAAa,OAAO,WAAW,cAAc;AAIvD,UAAQ,KAAK,0BAA0B;AACvC,OAAK,MAAM,gBAAgB,KAAK,SAAS,QAAQ,CAC/C,KAAI,aAAa,OAAO,iBACtB,kBACE,MAAM,aAAa,OAAO,iBAAiB,eAAe;EAIhE,MAAM,mBAAmB,KAAK,eAAe,uBAAuB;GAClE,WAAW,KAAK;GAChB,UAAU,KAAK,QAAQ,KAAK,UAAU;GACtC,QAAS,UAAU,EAAE;GACrB;GACA,aAAa,KAAK;GAClB,SAAS,KAAK;GACd,oBAAoB,KAAK;GACzB,eAAe,KAAK;GACrB,CAAC;AAEF,UAAQ,KAAK,qBAAqB;AAClC,OAAK,MAAM,gBAAgB,KAAK,SAAS,QAAQ,EAAE;AACjD,WAAQ,KAAK,mBAAmB,aAAa,OAAO,OAAO;AAC3D,OAAI,aAAa,OAAO,SACtB,OAAM,aAAa,OAAO,SAAS,iBAAiB;;AAIxD,qBAAmB,KAAK,aAAa,iBAAiB;AAEtD,UAAQ,KAAK,wBAAwB;AACrC,OAAK,MAAM,gBAAgB,KAAK,SAAS,QAAQ,CAC/C,KAAI,aAAa,OAAO,SACtB,OAAM,aAAa,OAAO,SAAS,cAAc;AAIrD,MAAI,QAAQ,UAAU,KACpB,OAAM,WAAW,KAAK,UAAU;AAGlC,UAAQ,KAAK,uBAAuB;AACpC,UAAQ,KACN,oBAAoB,KAAK,eAAe,mBAAmB,CAAC,SAC7D;;CAGH,sBACE,UACA,WACA,yBACM;AACN,OAAK,YAAY,KAAK,QAAQ,yBAAyB,SAAS;AAChE,OAAK,YAAY,KAAK,QAAQ,yBAAyB,UAAU;AACjE,OAAK,qBAAqB,KAAK,KAAK,KAAK,WAAW,YAAY;AAChE,OAAK,gBAAgB,KAAK,KAAK,KAAK,WAAW,OAAO;;;AAI1D,MAAM,8BACJ,mBACuB;CACvB,IAAI,mBAAmB;AAEvB,QAAO,MAAM;AACX,MAAI,mBAAmB,iBAAiB,CACtC,QAAO;EAGT,MAAM,kBAAkB,KAAK,QAAQ,iBAAiB;AACtD,MAAI,oBAAoB,iBACtB;AAGF,qBAAmB;;;AAIvB,MAAM,sBAAsB,cAA+B;AACzD,QAAO,CAAC,uBAAuB,OAAO,CAAC,MAAK,WAC1C,GAAG,WAAW,KAAK,KAAK,WAAW,OAAO,CAAC,CAC5C;;AAGH,MAAM,kCAAkC,eAA+B;CACrE,MAAM,oBAA8B,EAAE;CACtC,IAAI,sBAAsB,KAAK,QAAQ,WAAW;AAElD,QAAO,CAAC,GAAG,WAAW,oBAAoB,EAAE;EAC1C,MAAM,aAAa,KAAK,QAAQ,oBAAoB;AACpD,MAAI,eAAe,oBACjB;AAGF,oBAAkB,QAAQ,KAAK,SAAS,oBAAoB,CAAC;AAC7D,wBAAsB;;CAGxB,MAAM,wBAAwB,GAAG,aAAa,OAAO,oBAAoB;AAEzE,QAAO,KAAK,KAAK,uBAAuB,GAAG,kBAAkB;;AAG/D,MAAM,wBAAwB,WAAmB,aAA8B;CAC7E,MAAM,eAAe,KAAK,SAAS,UAAU,UAAU;CACvD,MAAM,wBAAwB,KAAK,KAAK;CACxC,MAAM,kBACJ,iBAAiB,QAAQ,aAAa,WAAW,sBAAsB;AAEzE,QACE,iBAAiB,MAAO,CAAC,mBAAmB,CAAC,KAAK,WAAW,aAAa;;;;ACxQ9E,MAAM,YAAY,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAC9D,MAAM,cAAc,KAAK,MACvB,GAAG,aAAa,KAAK,KAAK,WAAW,kBAAkB,EAAE,QAAQ,CAClE;AAeD,MAAM,UAAU,IAAI,SAAS;AAC7B,MAAM,UAAU,QAAQ,KAAK;AAE7B,QACG,KAAK,qBAAqB,CAC1B,YAAY,8DAA8D,CAC1E,QAAQ,YAAY,QAAQ;AAE/B,QACG,QAAQ,WAAW,CACnB,YAAY,2DAA2D,CACvE,OAAO,2BAA2B,+BAA+B,CACjE,OAAO,4BAA4B,uCAAuC,CAC1E,OACC,6BACA,kDACD,CACA,OAAO,2BAA2B,yCAAyC,CAC3E,OAAO,YAAY,mDAAmD,CACtE,OAAO,eAAe,0BAA0B,CAChD,OAAO,WAAW,2DAA2D,CAC7E,OAAO,cAAc,oCAAoC,CACzD,OAAO,OAAO,YAA4B;CACzC,IAAI,SAAoC,EAAE;AAG1C,KAAI,QAAQ,QAAQ;EAClB,MAAM,aAAa,sBAAsB,QAAQ,QAAQ,QAAQ;AAEjE,MAAI;AACF,YAAS,MAAM,WAAW,WAAW;AACrC,WAAQ,KAAK,6BAA6B,aAAa;WAChD,OAAO;AACd,WAAQ,MAAM,sCAAsC,QAAQ,SAAS;AACrE,WAAQ,MAAM,MAAM;AACpB,WAAQ,KAAK,EAAE;;;CAKnB,MAAM,YAAY,QAAQ,SAAS,OAAO;CAC1C,MAAM,YAAY,QAAQ,UAAU,OAAO;AAE3C,KAAI,CAAC,UACH,OAAM,IAAI,MACR,4EACD;AAEH,KAAI,CAAC,UACH,OAAM,IAAI,MACR,wEACD;CAIH,MAAM,oBAAoB,KAAK,WAAW,UAAU,GAChD,YACA,KAAK,KAAK,SAAS,UAAU;CACjC,MAAM,oBAAoB,KAAK,WAAW,UAAU,GAChD,YACA,KAAK,KAAK,SAAS,UAAU;CAGjC,MAAM,cAAgC;EACpC,OAAO;EACP,QAAQ;EACR,QAAQ,QAAQ,UAAU,OAAO,UAAU;EAC3C,OAAO,QAAQ,SAAS,OAAO,SAAS;EACzC;AAGD,KAAI,QAAQ,QAEV,aAAY,UAAU,QAAQ,QAAQ,MAAM,IAAI,CAAC,KAAI,MAAK,EAAE,MAAM,CAAC;UAC1D,OAAO,QAEhB,aAAY,UAAU,OAAO;AAM/B,QADkB,IAAI,WAAW,CAChB,SACf,mBACA,mBACA,aACA,QACD;EACD;AAGJ,QACG,QAAQ,OAAO,CACf,YAAY,oDAAoD,CAChE,aAAa;AACZ,SAAQ,IAAI,mCAAmC;EAC/C;AAEJ,QAAQ,MAAM,QAAQ,KAAK"}
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":["moduleDir"],"sources":["../src/errors/InvalidConfigExportError.ts","../src/errors/UnsupportedConfigExtensionError.ts","../src/errors/UnsupportedTypeScriptConfigError.ts","../src/configLoader.ts","../src/generators/errors/UnsafeCleanTargetError.ts","../src/generators/formatter.ts","../src/generators/indexFileGenerator.ts","../src/generators/errors/PluginLoadingFailure.ts","../src/generators/pluginLoader.ts","../src/generators/spec/errors/SpecBundleOutputMissingError.ts","../src/generators/spec/specBundler.ts","../src/generators/spec/InvalidSpecEntrypointError.ts","../src/generators/spec/specGuards.ts","../src/generators/spec/specImporter.ts","../src/generators/specLoader.ts","../src/generators/Generator.ts","../src/errors/MissingGenerateOptionError.ts","../src/resolveGenerateOptions.ts","../src/cli.ts"],"sourcesContent":["export type InvalidConfigExportReason =\n | \"both-default-and-named-config\"\n | \"default-namespace-wrapper\"\n | \"missing-config-export\"\n | \"non-object-config\";\n\nexport class InvalidConfigExportError extends Error {\n public override readonly name = \"InvalidConfigExportError\";\n\n public constructor(\n public readonly configPath: string,\n public readonly reason: InvalidConfigExportReason\n ) {\n super(getInvalidConfigExportMessage(configPath, reason));\n }\n}\n\nconst getInvalidConfigExportMessage = (\n configPath: string,\n reason: InvalidConfigExportReason\n): string => {\n switch (reason) {\n case \"both-default-and-named-config\":\n return `Configuration file '${configPath}' must choose one export style: use either 'export default' or 'export const config = ...', but not both.`;\n case \"default-namespace-wrapper\":\n return `Configuration file '${configPath}' default export must be the config object itself, not a module namespace-like wrapper. Export the config directly with 'export default { ... }' or use 'export const config = ...'.`;\n case \"missing-config-export\":\n return `Configuration file '${configPath}' must export its config via 'export default' or 'export const config = ...'.`;\n case \"non-object-config\":\n return `Configuration file '${configPath}' must export a config object via 'export default' or 'export const config = ...'.`;\n }\n};\n","export class UnsupportedConfigExtensionError extends Error {\n public override readonly name = \"UnsupportedConfigExtensionError\";\n\n public constructor(\n public readonly configPath: string,\n public readonly extension: string,\n public readonly supportedExtensions: readonly string[]\n ) {\n super(\n `Unsupported config file extension '${extension}' for '${configPath}'. TypeWeaver accepts only these config extensions: ${supportedExtensions.join(\", \")}.`\n );\n }\n}\n","export class UnsupportedTypeScriptConfigError extends Error {\n public override readonly name = \"UnsupportedTypeScriptConfigError\";\n\n public constructor(\n public readonly configPath: string,\n public readonly extension: string\n ) {\n super(\n `TypeScript config files are not supported: '${configPath}' uses '${extension}'. Use a JavaScript config file with one of these extensions: .js, .mjs, or .cjs.`\n );\n }\n}\n","import path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport type { TypeweaverConfig } from \"@rexeus/typeweaver-gen\";\nimport { InvalidConfigExportError } from \"./errors/InvalidConfigExportError.js\";\nimport { UnsupportedConfigExtensionError } from \"./errors/UnsupportedConfigExtensionError.js\";\nimport { UnsupportedTypeScriptConfigError } from \"./errors/UnsupportedTypeScriptConfigError.js\";\n\nconst SUPPORTED_CONFIG_EXTENSIONS = [\".js\", \".mjs\", \".cjs\"] as const;\nconst SUPPORTED_CONFIG_EXTENSION_SET = new Set<string>(\n SUPPORTED_CONFIG_EXTENSIONS\n);\nconst UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS = new Set([\n \".ts\",\n \".mts\",\n \".cts\",\n]);\n\nexport const getResolvedConfigPath = (\n configPath: string,\n currentWorkingDirectory: string = process.cwd()\n): string => {\n return path.isAbsolute(configPath)\n ? configPath\n : path.resolve(currentWorkingDirectory, configPath);\n};\n\nexport const assertSupportedConfigPath = (configPath: string): void => {\n const extension = path.extname(configPath).toLowerCase();\n\n if (UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS.has(extension)) {\n throw new UnsupportedTypeScriptConfigError(configPath, extension);\n }\n\n if (!SUPPORTED_CONFIG_EXTENSION_SET.has(extension)) {\n throw new UnsupportedConfigExtensionError(\n configPath,\n extension,\n SUPPORTED_CONFIG_EXTENSIONS\n );\n }\n};\n\nexport const loadConfig = async (\n configPath: string\n): Promise<Partial<TypeweaverConfig>> => {\n assertSupportedConfigPath(configPath);\n\n const resolvedPath = path.resolve(configPath);\n const configUrl = pathToFileURL(resolvedPath).toString();\n const configModule = await import(configUrl);\n const loadedConfig = getConfigExport(configModule, configPath);\n\n if (!isConfigObject(loadedConfig)) {\n throw new InvalidConfigExportError(configPath, \"non-object-config\");\n }\n\n return loadedConfig;\n};\n\nconst getConfigExport = (\n configModule: Record<string, unknown>,\n configPath: string\n): unknown => {\n const hasDefaultExport = Object.hasOwn(configModule, \"default\");\n const hasNamedConfigExport = Object.hasOwn(configModule, \"config\");\n\n if (hasDefaultExport && hasNamedConfigExport) {\n throw new InvalidConfigExportError(\n configPath,\n \"both-default-and-named-config\"\n );\n }\n\n if (hasDefaultExport) {\n if (isNamespaceLikeConfigExport(configModule.default)) {\n throw new InvalidConfigExportError(\n configPath,\n \"default-namespace-wrapper\"\n );\n }\n\n return configModule.default;\n }\n\n if (hasNamedConfigExport) {\n return configModule.config;\n }\n\n throw new InvalidConfigExportError(configPath, \"missing-config-export\");\n};\n\nconst isConfigObject = (value: unknown): value is Partial<TypeweaverConfig> => {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n};\n\nconst isNamespaceLikeConfigExport = (value: unknown): boolean => {\n if (!isConfigObject(value)) {\n return false;\n }\n\n return Object.hasOwn(value, \"default\") || Object.hasOwn(value, \"config\");\n};\n","export type UnsafeCleanTargetReason =\n | \"empty-path\"\n | \"filesystem-root\"\n | \"current-working-directory\"\n | \"workspace-root\"\n | \"ancestor-of-current-working-directory\";\n\nexport type UnsafeCleanTargetDiagnostics = {\n readonly resolvedOutputDir?: string;\n readonly currentWorkingDirectory?: string;\n readonly protectedWorkspaceRoot?: string;\n readonly filesystemRoot?: string;\n};\n\nexport class UnsafeCleanTargetError extends Error {\n public override readonly name = \"UnsafeCleanTargetError\";\n public readonly resolvedOutputDir: string | undefined;\n public readonly currentWorkingDirectory: string | undefined;\n public readonly protectedWorkspaceRoot: string | undefined;\n public readonly filesystemRoot: string | undefined;\n\n public constructor(\n public readonly outputDir: string,\n public readonly reason: UnsafeCleanTargetReason,\n diagnostics: UnsafeCleanTargetDiagnostics = {}\n ) {\n super(getUnsafeCleanTargetMessage(outputDir, reason, diagnostics));\n this.resolvedOutputDir = diagnostics.resolvedOutputDir;\n this.currentWorkingDirectory = diagnostics.currentWorkingDirectory;\n this.protectedWorkspaceRoot = diagnostics.protectedWorkspaceRoot;\n this.filesystemRoot = diagnostics.filesystemRoot;\n }\n}\n\nconst getUnsafeCleanTargetMessage = (\n outputDir: string,\n reason: UnsafeCleanTargetReason,\n diagnostics: UnsafeCleanTargetDiagnostics\n): string => {\n const targetDescription = `Refusing to clean '${outputDir}'`;\n const suffix = \"Use a dedicated generated output directory instead.\";\n\n switch (reason) {\n case \"empty-path\":\n return `Refusing to clean an empty output directory path. ${suffix}`;\n case \"filesystem-root\":\n return `${targetDescription} because it resolves to the filesystem root '${diagnostics.filesystemRoot ?? diagnostics.resolvedOutputDir ?? outputDir}'. ${suffix}`;\n case \"current-working-directory\":\n return `${targetDescription} because it resolves to the current working directory '${diagnostics.currentWorkingDirectory ?? diagnostics.resolvedOutputDir ?? outputDir}'. ${suffix}`;\n case \"workspace-root\":\n return `${targetDescription} because it resolves to the protected workspace root '${diagnostics.protectedWorkspaceRoot ?? diagnostics.resolvedOutputDir ?? outputDir}'. ${suffix}`;\n case \"ancestor-of-current-working-directory\":\n return `${targetDescription} because it resolves to an ancestor directory of the current working directory '${diagnostics.currentWorkingDirectory ?? \"\"}'. ${suffix}`;\n }\n};\n","import fs from \"node:fs\";\nimport path from \"node:path\";\n\ntype FormatFn = (filename: string, source: string) => Promise<{ code: string }>;\n\nexport async function formatCode(\n outputDir: string,\n startDir?: string\n): Promise<void> {\n const format = await loadFormatter();\n if (!format) {\n return;\n }\n\n const targetDir = startDir ?? outputDir;\n await formatDirectory(targetDir, format);\n}\n\nasync function loadFormatter(): Promise<FormatFn | undefined> {\n try {\n const oxfmt = await import(\"oxfmt\");\n return oxfmt.format;\n } catch {\n console.warn(\n \"oxfmt not installed - skipping formatting. Install with: npm install -D oxfmt\"\n );\n return undefined;\n }\n}\n\nasync function formatDirectory(\n targetDir: string,\n format: FormatFn\n): Promise<void> {\n const contents = fs.readdirSync(targetDir, { withFileTypes: true });\n\n for (const content of contents) {\n if (content.isFile()) {\n const filePath = path.join(targetDir, content.name);\n const unformatted = fs.readFileSync(filePath, \"utf8\");\n const { code } = await format(filePath, unformatted);\n fs.writeFileSync(filePath, code);\n } else if (content.isDirectory()) {\n await formatDirectory(path.join(targetDir, content.name), format);\n }\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { renderTemplate } from \"@rexeus/typeweaver-gen\";\nimport type { GeneratorContext } from \"@rexeus/typeweaver-gen\";\n\nexport type IndexFileGenerationContext = Pick<\n GeneratorContext,\n \"outputDir\" | \"getGeneratedFiles\"\n>;\n\nexport function generateIndexFiles(\n templateDir: string,\n context: IndexFileGenerationContext\n): void {\n const templateFilePath = path.join(templateDir, \"Index.ejs\");\n const template = fs.readFileSync(templateFilePath, \"utf8\");\n\n const generatedFiles = context.getGeneratedFiles();\n const groups = new Map<string, Set<string>>();\n const rootFiles = new Set<string>();\n const existingBarrels = new Set<string>();\n\n for (const file of generatedFiles) {\n const normalizedFile = file.replace(/\\\\/g, \"/\");\n const withJsExt = normalizedFile.replace(/\\.ts$/, \".js\");\n const stripped = normalizedFile.replace(/\\.ts$/, \"\");\n const firstSlash = stripped.indexOf(\"/\");\n\n if (stripped === \"index\") {\n continue;\n }\n\n if (firstSlash === -1) {\n rootFiles.add(`./${withJsExt}`);\n continue;\n }\n\n const firstSegment = stripped.slice(0, firstSlash);\n\n if (stripped === \"lib/index\") {\n existingBarrels.add(\"lib\");\n continue;\n }\n\n if (firstSegment === \"lib\") {\n const secondSlash = stripped.indexOf(\"/\", firstSlash + 1);\n const groupKey =\n secondSlash === -1 ? stripped : stripped.slice(0, secondSlash);\n\n const entryName = stripped.slice(groupKey.length + 1);\n\n if (entryName === \"index\") {\n existingBarrels.add(groupKey);\n } else {\n if (!groups.has(groupKey)) {\n groups.set(groupKey, new Set());\n }\n groups.get(groupKey)!.add(`./${entryName}.js`);\n }\n } else {\n const entryName = stripped.slice(firstSlash + 1);\n\n if (entryName === \"index\") {\n existingBarrels.add(firstSegment);\n } else {\n if (!groups.has(firstSegment)) {\n groups.set(firstSegment, new Set());\n }\n groups.get(firstSegment)!.add(`./${entryName}.js`);\n }\n }\n }\n\n for (const [groupKey, entries] of groups) {\n if (existingBarrels.has(groupKey)) {\n continue;\n }\n\n const domainBarrelContent = renderTemplate(template, {\n indexPaths: Array.from(entries).sort(),\n });\n\n const domainIndexPath = path.join(context.outputDir, groupKey, \"index.ts\");\n fs.mkdirSync(path.dirname(domainIndexPath), { recursive: true });\n fs.writeFileSync(domainIndexPath, domainBarrelContent);\n }\n\n const rootIndexPaths = new Set<string>(rootFiles);\n for (const groupKey of groups.keys()) {\n rootIndexPaths.add(`./${groupKey}/index.js`);\n }\n for (const barrelKey of existingBarrels) {\n rootIndexPaths.add(`./${barrelKey}/index.js`);\n }\n\n const rootContent = renderTemplate(template, {\n indexPaths: Array.from(rootIndexPaths).sort(),\n });\n\n fs.writeFileSync(path.join(context.outputDir, \"index.ts\"), rootContent);\n}\n","export type PluginLoadError = {\n readonly pluginName: string;\n readonly attempts: readonly {\n readonly path: string;\n readonly error: string;\n }[];\n};\n\nexport class PluginLoadingFailure extends Error implements PluginLoadError {\n public constructor(\n public readonly pluginName: string,\n public readonly attempts: readonly {\n readonly path: string;\n readonly error: string;\n }[]\n ) {\n super(`Failed to load plugin '${pluginName}'`);\n Object.setPrototypeOf(this, PluginLoadingFailure.prototype);\n }\n}\n","import path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport type {\n PluginConfig,\n PluginConstructor,\n TypeweaverConfig,\n TypeweaverPlugin,\n} from \"@rexeus/typeweaver-gen\";\nimport { PluginLoadingFailure } from \"./errors/PluginLoadingFailure.js\";\nimport type { PluginLoadError } from \"./errors/PluginLoadingFailure.js\";\n\nexport type PluginResolutionStrategy = \"npm\" | \"local\" | \"scoped\";\n\nexport type PluginRegistrar = {\n readonly register: (plugin: TypeweaverPlugin, config?: unknown) => void;\n};\n\nexport type PluginLoadResult = {\n readonly plugin: TypeweaverPlugin;\n readonly source: string;\n readonly config?: PluginConfig;\n};\n\ntype PluginCandidate = {\n readonly exportName: string;\n readonly constructor: PluginConstructor;\n};\n\ntype LoadResult<T, E> =\n | { success: true; value: T }\n | { success: false; error: E };\n\nexport async function loadPlugins(\n registry: PluginRegistrar,\n requiredPlugins: readonly TypeweaverPlugin[],\n strategies: readonly PluginResolutionStrategy[],\n config?: TypeweaverConfig\n): Promise<void> {\n for (const requiredPlugin of requiredPlugins) {\n registry.register(requiredPlugin);\n }\n\n if (!config?.plugins) {\n return;\n }\n\n const successful: PluginLoadResult[] = [];\n\n for (const plugin of config.plugins) {\n const pluginName = typeof plugin === \"string\" ? plugin : plugin[0];\n const pluginConfig = typeof plugin === \"string\" ? undefined : plugin[1];\n const result = await loadPlugin(pluginName, strategies, pluginConfig);\n\n if (result.success === false) {\n throw new PluginLoadingFailure(\n result.error.pluginName,\n result.error.attempts\n );\n }\n\n successful.push(result.value);\n registry.register(result.value.plugin, result.value.config);\n }\n\n reportSuccessfulLoads(successful);\n}\n\nasync function loadPlugin(\n pluginName: string,\n strategies: readonly PluginResolutionStrategy[],\n pluginConfig?: PluginConfig\n): Promise<LoadResult<PluginLoadResult, PluginLoadError>> {\n const possiblePaths = generatePluginPaths(pluginName, strategies);\n const attempts: { path: string; error: string }[] = [];\n\n for (const possiblePath of possiblePaths) {\n try {\n const pluginPackage = await import(possiblePath);\n const plugin = createPluginInstance(pluginPackage, pluginConfig);\n if (plugin.success) {\n return {\n success: true,\n value: {\n plugin: plugin.value,\n source: possiblePath,\n config: pluginConfig,\n },\n };\n }\n attempts.push({\n path: possiblePath,\n error: plugin.error,\n });\n } catch (error) {\n attempts.push({\n path: possiblePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n return {\n success: false,\n error: {\n pluginName,\n attempts,\n },\n };\n}\n\nfunction createPluginInstance(\n pluginModule: Record<string, unknown>,\n pluginConfig?: PluginConfig\n): LoadResult<TypeweaverPlugin, string> {\n const candidates = findPluginConstructorCandidates(pluginModule);\n if (candidates.length === 0) {\n return {\n success: false,\n error: \"No plugin constructor export found\",\n };\n }\n\n const errors: string[] = [];\n for (const candidate of candidates) {\n try {\n const plugin = new candidate.constructor(pluginConfig);\n if (isTypeweaverPlugin(plugin)) {\n return {\n success: true,\n value: plugin,\n };\n }\n\n errors.push(\n `Export '${candidate.exportName}' did not produce a valid plugin with a string name`\n );\n } catch (error) {\n errors.push(\n `Export '${candidate.exportName}' could not be instantiated: ${formatError(error)}`\n );\n }\n }\n\n return {\n success: false,\n error: errors.join(\"; \"),\n };\n}\n\nfunction findPluginConstructorCandidates(\n pluginModule: Record<string, unknown>\n): PluginCandidate[] {\n const candidates: PluginCandidate[] = [];\n\n for (const [key, value] of Object.entries(pluginModule)) {\n if (key !== \"default\" && typeof value === \"function\") {\n candidates.push({\n exportName: key,\n constructor: value as PluginConstructor,\n });\n }\n }\n\n // Fall back to default export for third-party plugin compatibility\n const defaultExport = pluginModule.default;\n if (typeof defaultExport === \"function\") {\n candidates.push({\n exportName: \"default\",\n constructor: defaultExport as PluginConstructor,\n });\n }\n\n return candidates;\n}\n\nfunction isTypeweaverPlugin(value: unknown): value is TypeweaverPlugin {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { readonly name?: unknown }).name === \"string\" &&\n (value as { readonly name: string }).name.length > 0\n );\n}\n\nfunction formatError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction generatePluginPaths(\n pluginName: string,\n strategies: readonly PluginResolutionStrategy[]\n): string[] {\n const paths: string[] = [];\n\n for (const strategy of strategies) {\n switch (strategy) {\n case \"npm\":\n paths.push(`@rexeus/typeweaver-${pluginName}`);\n paths.push(`@rexeus/${pluginName}`);\n break;\n case \"local\":\n paths.push(toLocalImportSpecifier(pluginName));\n break;\n case \"scoped\":\n paths.push(pluginName);\n break;\n }\n }\n\n return paths;\n}\n\nfunction toLocalImportSpecifier(pluginName: string): string {\n if (pluginName.startsWith(\"file:\")) {\n return pluginName;\n }\n\n if (path.isAbsolute(pluginName)) {\n return pathToFileURL(pluginName).href;\n }\n\n return pluginName;\n}\n\nfunction reportSuccessfulLoads(successful: PluginLoadResult[]): void {\n if (successful.length > 0) {\n console.info(`Successfully loaded ${successful.length} plugin(s):`);\n for (const result of successful) {\n console.info(` - ${result.plugin.name} (from ${result.source})`);\n }\n }\n}\n","export class SpecBundleOutputMissingError extends Error {\n public override readonly name = \"SpecBundleOutputMissingError\";\n\n public constructor(\n public readonly inputFile: string,\n public readonly bundledSpecFile: string,\n public readonly specOutputDir: string\n ) {\n super(\n `Spec bundling completed but did not create the expected output '${bundledSpecFile}' for entrypoint '${inputFile}'. Expected the bundle inside '${specOutputDir}'.`\n );\n }\n}\n","import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { build } from \"rolldown\";\nimport { SpecBundleOutputMissingError } from \"./errors/SpecBundleOutputMissingError.js\";\n\nconst WINDOWS_ABSOLUTE_PATH_PATTERN = /^[A-Za-z]:[\\\\/]/;\nconst WINDOWS_UNC_PATH_PATTERN = /^\\\\\\\\/;\n\nexport type SpecBundlerConfig = {\n readonly inputFile: string;\n readonly specOutputDir: string;\n};\n\nexport type SpecBundlerDeps = {\n readonly build?: typeof build;\n readonly existsSync?: (filePath: string) => boolean;\n};\n\nexport function createWrapperImportSpecifier(\n wrapperFile: string,\n inputFile: string\n): string {\n const absoluteInputFile = resolveBundledInputFile(inputFile);\n const useWindowsPathSemantics = usesWindowsPathSemantics(\n wrapperFile,\n absoluteInputFile\n );\n const pathModule = useWindowsPathSemantics ? path.win32 : path.posix;\n const wrapperDir = useWindowsPathSemantics\n ? pathModule.dirname(wrapperFile)\n : resolveRealFilePath(pathModule.dirname(wrapperFile));\n const resolvedInputFile = useWindowsPathSemantics\n ? absoluteInputFile\n : resolveRealFilePath(absoluteInputFile);\n const relativeInputFile = pathModule\n .relative(wrapperDir, resolvedInputFile)\n .replaceAll(pathModule.sep, \"/\");\n\n if (relativeInputFile.startsWith(\".\") || relativeInputFile.startsWith(\"..\")) {\n return relativeInputFile;\n }\n\n return `./${relativeInputFile}`;\n}\n\nexport async function bundle(\n config: SpecBundlerConfig,\n deps: SpecBundlerDeps = {}\n): Promise<string> {\n const tempDir = fs.mkdtempSync(\n path.join(os.tmpdir(), \"typeweaver-spec-loader-\")\n );\n const wrapperFile = path.join(tempDir, \"spec-entrypoint.ts\");\n const bundledSpecFile = path.join(config.specOutputDir, \"spec.js\");\n const wrapperImportSpecifier = createWrapperImportSpecifier(\n wrapperFile,\n config.inputFile\n );\n\n fs.writeFileSync(\n wrapperFile,\n [\n `import * as specModule from ${JSON.stringify(wrapperImportSpecifier)};`,\n \"const resolvedSpec =\",\n ' Reflect.get(specModule, \"spec\") ??',\n ' Reflect.get(specModule, \"default\") ??',\n \" specModule;\",\n \"\",\n \"export const spec = resolvedSpec;\",\n \"\",\n ].join(\"\\n\")\n );\n\n try {\n await (deps.build ?? build)({\n cwd: tempDir,\n input: wrapperFile,\n treeshake: true,\n experimental: {\n attachDebugInfo: \"none\",\n },\n external: (source: string) => {\n if (source.startsWith(\"node:\")) {\n return true;\n }\n\n return !source.startsWith(\".\") && !path.isAbsolute(source);\n },\n output: {\n file: bundledSpecFile,\n format: \"esm\",\n },\n });\n } finally {\n fs.rmSync(tempDir, { recursive: true, force: true });\n }\n\n if (!(deps.existsSync ?? fs.existsSync)(bundledSpecFile)) {\n throw new SpecBundleOutputMissingError(\n config.inputFile,\n bundledSpecFile,\n config.specOutputDir\n );\n }\n\n return bundledSpecFile;\n}\n\nfunction resolveBundledInputFile(inputFile: string): string {\n if (path.isAbsolute(inputFile)) {\n return inputFile;\n }\n\n if (WINDOWS_ABSOLUTE_PATH_PATTERN.test(inputFile)) {\n return path.win32.normalize(inputFile);\n }\n\n if (WINDOWS_UNC_PATH_PATTERN.test(inputFile)) {\n return path.win32.normalize(inputFile);\n }\n\n return path.resolve(inputFile);\n}\n\nfunction usesWindowsPathSemantics(...filePaths: string[]): boolean {\n return filePaths.some(filePath => {\n return (\n WINDOWS_ABSOLUTE_PATH_PATTERN.test(filePath) ||\n WINDOWS_UNC_PATH_PATTERN.test(filePath)\n );\n });\n}\n\nfunction resolveRealFilePath(filePath: string): string {\n if (!fs.existsSync(filePath)) {\n return filePath;\n }\n\n return fs.realpathSync.native(filePath);\n}\n","export class InvalidSpecEntrypointError extends Error {\n public constructor(specEntrypoint: string) {\n super(\n `Spec entrypoint '${specEntrypoint}' must export a SpecDefinition as its default export, named 'spec' export, or module namespace.`\n );\n this.name = \"InvalidSpecEntrypointError\";\n }\n}\n","import { HttpMethod, HttpStatusCode } from \"@rexeus/typeweaver-core\";\nimport type { SpecDefinition } from \"@rexeus/typeweaver-core\";\n\nconst validHttpStatusCodes = new Set<HttpStatusCode>(\n Object.values(HttpStatusCode).filter(\n (statusCode): statusCode is HttpStatusCode => typeof statusCode === \"number\"\n )\n);\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n};\n\nconst isResponseDefinition = (value: unknown): boolean => {\n if (!isRecord(value)) {\n return false;\n }\n\n return (\n typeof value.name === \"string\" &&\n value.name.length > 0 &&\n typeof value.description === \"string\" &&\n value.description.length > 0 &&\n validHttpStatusCodes.has(value.statusCode as HttpStatusCode)\n );\n};\n\nconst isOperationDefinition = (value: unknown): boolean => {\n if (!isRecord(value) || !Array.isArray(value.responses)) {\n return false;\n }\n\n return (\n typeof value.operationId === \"string\" &&\n value.operationId.length > 0 &&\n typeof value.path === \"string\" &&\n value.path.length > 0 &&\n typeof value.summary === \"string\" &&\n value.summary.length > 0 &&\n Object.values(HttpMethod).includes(value.method as HttpMethod) &&\n isRecord(value.request) &&\n value.responses.length > 0 &&\n value.responses.every(response => isResponseDefinition(response))\n );\n};\n\nconst isResourceDefinition = (value: unknown): boolean => {\n return (\n isRecord(value) &&\n Array.isArray(value.operations) &&\n value.operations.every(isOperationDefinition)\n );\n};\n\nexport const isSpecDefinition = (value: unknown): value is SpecDefinition => {\n if (!isRecord(value) || !isRecord(value.resources)) {\n return false;\n }\n\n return Object.values(value.resources).every(isResourceDefinition);\n};\n","import { createHash } from \"node:crypto\";\nimport fs from \"node:fs\";\nimport { pathToFileURL } from \"node:url\";\nimport type { SpecDefinition } from \"@rexeus/typeweaver-core\";\nimport { InvalidSpecEntrypointError } from \"./InvalidSpecEntrypointError.js\";\nimport { isSpecDefinition } from \"./specGuards.js\";\n\nexport async function importDefinition(\n bundledSpecFile: string\n): Promise<SpecDefinition> {\n const contentHash = createHash(\"sha256\")\n .update(fs.readFileSync(bundledSpecFile))\n .digest(\"hex\");\n const moduleUrl = pathToFileURL(bundledSpecFile);\n\n moduleUrl.searchParams.set(\"content\", contentHash);\n\n const specModule = (await import(moduleUrl.toString())) as {\n readonly spec?: unknown;\n readonly default?: unknown;\n };\n const definition = specModule.spec ?? specModule.default ?? specModule;\n\n if (!isSpecDefinition(definition)) {\n throw new InvalidSpecEntrypointError(bundledSpecFile);\n }\n\n return definition;\n}\n","import fs from \"node:fs\";\nimport type { SpecDefinition } from \"@rexeus/typeweaver-core\";\nimport { normalizeSpec } from \"@rexeus/typeweaver-gen\";\nimport type { NormalizedSpec } from \"@rexeus/typeweaver-gen\";\nimport { bundle } from \"./spec/specBundler.js\";\nimport { importDefinition } from \"./spec/specImporter.js\";\n\nexport type SpecLoaderConfig = {\n readonly inputFile: string;\n readonly specOutputDir: string;\n};\n\nexport type LoadedSpec = {\n readonly definition: SpecDefinition;\n readonly normalizedSpec: NormalizedSpec;\n};\n\nexport async function loadSpec(config: SpecLoaderConfig): Promise<LoadedSpec> {\n fs.mkdirSync(config.specOutputDir, { recursive: true });\n\n const bundledSpecFile = await bundle(config);\n writeSpecDeclarationFile(config.specOutputDir);\n\n const definition = await importDefinition(bundledSpecFile);\n const normalizedSpec = normalizeSpec(definition);\n\n return {\n definition,\n normalizedSpec,\n };\n}\n\nfunction writeSpecDeclarationFile(specOutputDir: string): void {\n fs.writeFileSync(\n `${specOutputDir}/spec.d.ts`,\n [\n 'import type { SpecDefinition } from \"@rexeus/typeweaver-core\";',\n \"export declare const spec: SpecDefinition;\",\n \"\",\n ].join(\"\\n\")\n );\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n createPluginContextBuilder,\n createPluginRegistry,\n} from \"@rexeus/typeweaver-gen\";\nimport type { PluginConfig, TypeweaverConfig } from \"@rexeus/typeweaver-gen\";\nimport { TypesPlugin } from \"@rexeus/typeweaver-types\";\nimport { UnsafeCleanTargetError } from \"./errors/UnsafeCleanTargetError.js\";\nimport { formatCode } from \"./formatter.js\";\nimport { generateIndexFiles } from \"./indexFileGenerator.js\";\nimport { loadPlugins } from \"./pluginLoader.js\";\nimport { loadSpec } from \"./specLoader.js\";\nimport type { PluginResolutionStrategy } from \"./pluginLoader.js\";\n\nconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\nexport const assertSafeCleanTarget = (\n outputDir: string,\n currentWorkingDirectory: string\n): void => {\n const trimmedOutputDir = outputDir.trim();\n if (trimmedOutputDir.length === 0) {\n throw new UnsafeCleanTargetError(outputDir, \"empty-path\");\n }\n\n const resolvedWorkingDirectory = path.resolve(currentWorkingDirectory);\n const canonicalWorkingDirectory = fs.realpathSync.native(\n resolvedWorkingDirectory\n );\n const resolvedOutputDir = path.resolve(\n resolvedWorkingDirectory,\n trimmedOutputDir\n );\n const canonicalOutputDir = canonicalizePathForContainment(resolvedOutputDir);\n const filesystemRoot = path.parse(canonicalOutputDir).root;\n\n if (canonicalOutputDir === filesystemRoot) {\n throw new UnsafeCleanTargetError(outputDir, \"filesystem-root\", {\n resolvedOutputDir,\n currentWorkingDirectory: resolvedWorkingDirectory,\n filesystemRoot,\n });\n }\n\n if (\n resolvedOutputDir === resolvedWorkingDirectory ||\n canonicalOutputDir === canonicalWorkingDirectory\n ) {\n throw new UnsafeCleanTargetError(outputDir, \"current-working-directory\", {\n resolvedOutputDir,\n currentWorkingDirectory: resolvedWorkingDirectory,\n });\n }\n\n const logicalProtectedWorkspaceRoot = findProtectedWorkspaceRoot(\n resolvedWorkingDirectory\n );\n const canonicalProtectedWorkspaceRoot = findProtectedWorkspaceRoot(\n canonicalWorkingDirectory\n );\n const protectedWorkspaceRoots = [\n logicalProtectedWorkspaceRoot,\n canonicalProtectedWorkspaceRoot,\n ].filter((root): root is string => root !== undefined);\n const protectedWorkspaceRootTarget = protectedWorkspaceRoots.find(\n protectedWorkspaceRoot =>\n resolvedOutputDir === protectedWorkspaceRoot ||\n canonicalOutputDir === fs.realpathSync.native(protectedWorkspaceRoot)\n );\n\n if (protectedWorkspaceRootTarget !== undefined) {\n throw new UnsafeCleanTargetError(outputDir, \"workspace-root\", {\n resolvedOutputDir,\n currentWorkingDirectory: resolvedWorkingDirectory,\n protectedWorkspaceRoot: protectedWorkspaceRootTarget,\n });\n }\n\n if (\n protectedWorkspaceRoots.length > 0 &&\n (isSameOrDescendantOf(resolvedWorkingDirectory, resolvedOutputDir) ||\n isSameOrDescendantOf(canonicalWorkingDirectory, canonicalOutputDir))\n ) {\n throw new UnsafeCleanTargetError(\n outputDir,\n \"ancestor-of-current-working-directory\",\n {\n resolvedOutputDir,\n currentWorkingDirectory: resolvedWorkingDirectory,\n }\n );\n }\n};\n\n/**\n * Main generator for typeweaver\n * Uses a plugin-based architecture for extensible code generation\n */\nexport class Generator {\n public readonly coreDir = \"@rexeus/typeweaver-core\";\n public readonly templateDir = path.join(moduleDir, \"templates\");\n\n private readonly registry = createPluginRegistry();\n private readonly contextBuilder = createPluginContextBuilder();\n private readonly requiredPlugins: [TypesPlugin];\n private readonly strategies: PluginResolutionStrategy[];\n\n private inputFile = \"\";\n private outputDir = \"\";\n private specOutputDir = \"\";\n private responsesOutputDir = \"\";\n\n public constructor(\n requiredPlugins: [TypesPlugin] = [new TypesPlugin()],\n strategies?: PluginResolutionStrategy[]\n ) {\n this.requiredPlugins = requiredPlugins;\n this.strategies = strategies ?? [\"npm\", \"local\"];\n }\n\n /**\n * Generate code using the plugin system\n */\n public async generate(\n specFile: string,\n outputDir: string,\n config?: TypeweaverConfig,\n currentWorkingDirectory: string = process.cwd()\n ): Promise<void> {\n console.info(\"Starting generation...\");\n\n this.initializeDirectories(specFile, outputDir, currentWorkingDirectory);\n\n if (config?.clean ?? true) {\n assertSafeCleanTarget(this.outputDir, currentWorkingDirectory);\n console.info(\"Cleaning output directory...\");\n fs.rmSync(this.outputDir, { recursive: true, force: true });\n }\n\n fs.mkdirSync(this.outputDir, { recursive: true });\n fs.mkdirSync(this.responsesOutputDir, { recursive: true });\n fs.mkdirSync(this.specOutputDir, { recursive: true });\n\n await loadPlugins(\n this.registry,\n this.requiredPlugins,\n this.strategies,\n config\n );\n\n console.info(\n `Bundling spec from '${this.inputFile}' to '${this.specOutputDir}'...`\n );\n let { normalizedSpec } = await loadSpec({\n inputFile: this.inputFile,\n specOutputDir: this.specOutputDir,\n });\n\n const pluginContext = this.contextBuilder.createPluginContext({\n outputDir: this.outputDir,\n inputDir: path.dirname(this.inputFile),\n config: (config ?? {}) as PluginConfig,\n });\n\n console.info(\"Initializing plugins...\");\n for (const registration of this.registry.getAll()) {\n if (registration.plugin.initialize) {\n await registration.plugin.initialize(pluginContext);\n }\n }\n\n console.info(\"Collecting resources...\");\n for (const registration of this.registry.getAll()) {\n if (registration.plugin.collectResources) {\n normalizedSpec =\n await registration.plugin.collectResources(normalizedSpec);\n }\n }\n\n const generatorContext = this.contextBuilder.createGeneratorContext({\n outputDir: this.outputDir,\n inputDir: path.dirname(this.inputFile),\n config: (config ?? {}) as PluginConfig,\n normalizedSpec,\n templateDir: this.templateDir,\n coreDir: this.coreDir,\n responsesOutputDir: this.responsesOutputDir,\n specOutputDir: this.specOutputDir,\n });\n\n console.info(\"Generating code...\");\n for (const registration of this.registry.getAll()) {\n console.info(`Running plugin: ${registration.plugin.name}`);\n if (registration.plugin.generate) {\n await registration.plugin.generate(generatorContext);\n }\n }\n\n generateIndexFiles(this.templateDir, generatorContext);\n\n console.info(\"Finalizing plugins...\");\n for (const registration of this.registry.getAll()) {\n if (registration.plugin.finalize) {\n await registration.plugin.finalize(pluginContext);\n }\n }\n\n if (config?.format ?? true) {\n await formatCode(this.outputDir);\n }\n\n console.info(\"Generation complete!\");\n console.info(\n `Generated files: ${this.contextBuilder.getGeneratedFiles().length}`\n );\n }\n\n private initializeDirectories(\n specFile: string,\n outputDir: string,\n currentWorkingDirectory: string\n ): void {\n this.inputFile = path.resolve(currentWorkingDirectory, specFile);\n this.outputDir = path.resolve(currentWorkingDirectory, outputDir);\n this.responsesOutputDir = path.join(this.outputDir, \"responses\");\n this.specOutputDir = path.join(this.outputDir, \"spec\");\n }\n}\n\nconst findProtectedWorkspaceRoot = (\n startDirectory: string\n): string | undefined => {\n let currentDirectory = startDirectory;\n\n while (true) {\n if (hasWorkspaceMarker(currentDirectory)) {\n return currentDirectory;\n }\n\n const parentDirectory = path.dirname(currentDirectory);\n if (parentDirectory === currentDirectory) {\n return undefined;\n }\n\n currentDirectory = parentDirectory;\n }\n};\n\nconst hasWorkspaceMarker = (directory: string): boolean => {\n return [\"pnpm-workspace.yaml\", \".git\"].some(marker =>\n fs.existsSync(path.join(directory, marker))\n );\n};\n\nconst canonicalizePathForContainment = (targetPath: string): string => {\n const remainingSegments: string[] = [];\n let nearestExistingPath = path.resolve(targetPath);\n\n while (!fs.existsSync(nearestExistingPath)) {\n const parentPath = path.dirname(nearestExistingPath);\n if (parentPath === nearestExistingPath) {\n break;\n }\n\n remainingSegments.unshift(path.basename(nearestExistingPath));\n nearestExistingPath = parentPath;\n }\n\n const canonicalExistingPath = fs.realpathSync.native(nearestExistingPath);\n\n return path.join(canonicalExistingPath, ...remainingSegments);\n};\n\nconst isSameOrDescendantOf = (directory: string, ancestor: string): boolean => {\n const relativePath = path.relative(ancestor, directory);\n const parentTraversalPrefix = `..${path.sep}`;\n const escapesAncestor =\n relativePath === \"..\" || relativePath.startsWith(parentTraversalPrefix);\n\n return (\n relativePath === \"\" || (!escapesAncestor && !path.isAbsolute(relativePath))\n );\n};\n","export class MissingGenerateOptionError extends Error {\n public override readonly name = \"MissingGenerateOptionError\";\n\n public constructor(\n public readonly optionName: string,\n public readonly flag: string,\n public readonly configKey: string\n ) {\n super(\n `Missing required generate option '${optionName}'. Pass ${flag} or set '${configKey}' in the TypeWeaver config file.`\n );\n }\n}\n","import path from \"node:path\";\nimport type { TypeweaverConfig } from \"@rexeus/typeweaver-gen\";\nimport { MissingGenerateOptionError } from \"./errors/MissingGenerateOptionError.js\";\n\nexport type GenerateCommandOptions = {\n readonly input?: string;\n readonly output?: string;\n readonly plugins?: string;\n readonly format?: boolean;\n readonly clean?: boolean;\n};\n\nexport type ResolvedGenerateOptions = {\n readonly inputPath: string;\n readonly outputDir: string;\n readonly config: TypeweaverConfig;\n};\n\nexport const resolveGenerateOptions = (\n options: GenerateCommandOptions,\n config: Partial<TypeweaverConfig>,\n currentWorkingDirectory: string\n): ResolvedGenerateOptions => {\n const inputPath = options.input ?? config.input;\n const outputDir = options.output ?? config.output;\n\n if (!inputPath) {\n throw new MissingGenerateOptionError(\"input\", \"--input\", \"input\");\n }\n\n if (!outputDir) {\n throw new MissingGenerateOptionError(\"output\", \"--output\", \"output\");\n }\n\n const resolvedInputPath = path.isAbsolute(inputPath)\n ? inputPath\n : path.join(currentWorkingDirectory, inputPath);\n const resolvedOutputDir = path.isAbsolute(outputDir)\n ? outputDir\n : path.join(currentWorkingDirectory, outputDir);\n const finalConfig: TypeweaverConfig = {\n input: resolvedInputPath,\n output: resolvedOutputDir,\n format: options.format ?? config.format ?? true,\n clean: options.clean ?? config.clean ?? true,\n };\n\n if (options.plugins) {\n finalConfig.plugins = options.plugins\n .split(\",\")\n .map(plugin => plugin.trim());\n } else if (config.plugins) {\n finalConfig.plugins = config.plugins;\n }\n\n return {\n inputPath: resolvedInputPath,\n outputDir: resolvedOutputDir,\n config: finalConfig,\n };\n};\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { TypeweaverConfig } from \"@rexeus/typeweaver-gen\";\nimport { Command } from \"commander\";\nimport { getResolvedConfigPath, loadConfig } from \"./configLoader.js\";\nimport { Generator } from \"./generators/Generator.js\";\nimport { resolveGenerateOptions } from \"./resolveGenerateOptions.js\";\nimport type { CommandOptions as CommanderOptions } from \"commander\";\n\nconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\nconst packageJson = JSON.parse(\n fs.readFileSync(path.join(moduleDir, \"../package.json\"), \"utf-8\")\n) as {\n readonly version: string;\n readonly name: string;\n readonly description: string;\n};\n\ntype CommandOptions = CommanderOptions & {\n input?: string;\n output?: string;\n config?: string;\n plugins?: string;\n format?: boolean;\n clean?: boolean;\n};\n\nconst program = new Command();\nconst execDir = process.cwd();\n\nprogram\n .name(\"@rexeus/typeweaver\")\n .description(\"Type-safe API framework with code generation for TypeScript\")\n .version(packageJson.version);\n\nprogram\n .command(\"generate\")\n .description(\"Generate types, validators, and clients from an API spec\")\n .option(\"-i, --input <inputPath>\", \"path to spec entrypoint file\")\n .option(\"-o, --output <outputDir>\", \"output directory for generated files\")\n .option(\n \"-c, --config <configFile>\",\n \"path to a .js, .mjs, or .cjs configuration file\"\n )\n .option(\"-p, --plugins <plugins>\", \"comma-separated list of plugins to use\")\n .option(\"--format\", \"format generated code with oxfmt (default: true)\")\n .option(\"--no-format\", \"disable code formatting\")\n .option(\"--clean\", \"clean output directory before generation (default: true)\")\n .option(\"--no-clean\", \"disable cleaning output directory\")\n .action(async (options: CommandOptions) => {\n let config: Partial<TypeweaverConfig> = {};\n\n // Load configuration file if provided\n if (options.config) {\n const configPath = getResolvedConfigPath(options.config, execDir);\n\n try {\n config = await loadConfig(configPath);\n console.info(`Loaded configuration from ${configPath}`);\n } catch (error) {\n console.error(`Failed to load configuration file: ${options.config}`);\n console.error(error);\n process.exit(1);\n }\n }\n\n const resolvedGenerateOptions = resolveGenerateOptions(\n options,\n config,\n execDir\n );\n\n // Run generation\n const generator = new Generator();\n return generator.generate(\n resolvedGenerateOptions.inputPath,\n resolvedGenerateOptions.outputDir,\n resolvedGenerateOptions.config,\n execDir\n );\n });\n\n// Add future commands placeholder\nprogram\n .command(\"init\")\n .description(\"Initialize a new typeweaver project (coming soon)\")\n .action(() => {\n console.log(\"The init command is coming soon!\");\n });\n\nprogram.parse(process.argv);\n"],"mappings":"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"}
|
package/dist/entry.mjs
CHANGED
|
@@ -17,7 +17,7 @@ const getRuntimeDisplayName = (runtime) => {
|
|
|
17
17
|
const main = async () => {
|
|
18
18
|
const runtime = detectRuntime();
|
|
19
19
|
console.info(`Running on ${getRuntimeDisplayName(runtime)}`);
|
|
20
|
-
await import("./cli-
|
|
20
|
+
await import("./cli-BVUW7VcY.mjs");
|
|
21
21
|
};
|
|
22
22
|
main().catch((error) => {
|
|
23
23
|
console.error("Failed to start TypeWeaver CLI:", error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rexeus/typeweaver",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.5",
|
|
4
4
|
"description": "🧵✨ Typeweaver CLI. Entry point into the Typeweaver framework to scaffold, validate, and generate API assets.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -54,13 +54,13 @@
|
|
|
54
54
|
"commander": "^14.0.3",
|
|
55
55
|
"oxc-transform": "^0.121.0",
|
|
56
56
|
"rolldown": "^1.0.0-rc.13",
|
|
57
|
-
"@rexeus/typeweaver-
|
|
58
|
-
"@rexeus/typeweaver-
|
|
59
|
-
"@rexeus/typeweaver-
|
|
60
|
-
"@rexeus/typeweaver-hono": "^0.10.
|
|
61
|
-
"@rexeus/typeweaver-
|
|
62
|
-
"@rexeus/typeweaver-
|
|
63
|
-
"@rexeus/typeweaver-
|
|
57
|
+
"@rexeus/typeweaver-core": "^0.10.5",
|
|
58
|
+
"@rexeus/typeweaver-clients": "^0.10.5",
|
|
59
|
+
"@rexeus/typeweaver-server": "^0.10.5",
|
|
60
|
+
"@rexeus/typeweaver-hono": "^0.10.5",
|
|
61
|
+
"@rexeus/typeweaver-types": "^0.10.5",
|
|
62
|
+
"@rexeus/typeweaver-aws-cdk": "^0.10.5",
|
|
63
|
+
"@rexeus/typeweaver-gen": "^0.10.5"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
66
|
"oxfmt": ">=0.30.0"
|