@rexeus/typeweaver 0.9.2 โ 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -15
- package/dist/{cli-CF2Dbqut.mjs โ cli-DTzc-YtR.mjs} +94 -27
- package/dist/cli.cjs +93 -28
- package/dist/cli.mjs +94 -27
- package/dist/cli.mjs.map +1 -1
- package/dist/entry.mjs +1 -2
- package/package.json +11 -13
- package/dist/tsx-loader-DtL8gLLb.mjs +0 -3
package/README.md
CHANGED
|
@@ -34,6 +34,16 @@ bun add @rexeus/typeweaver-core
|
|
|
34
34
|
|
|
35
35
|
Now you are ready to start building! Check out [Quickstart](#-get-started)
|
|
36
36
|
|
|
37
|
+
## ๐ท๏ธ Naming conventions
|
|
38
|
+
|
|
39
|
+
- `operationId` should use camelCase (preferred), for example `getUser`.
|
|
40
|
+
- PascalCase `operationId` values are supported for compatibility.
|
|
41
|
+
- snake_case and kebab-case `operationId` values are not supported.
|
|
42
|
+
- `resourceName` should preferably be a singular noun in camelCase, for example `user` or
|
|
43
|
+
`authSession`.
|
|
44
|
+
- Plural and PascalCase `resourceName` values are supported.
|
|
45
|
+
- snake_case and kebab-case `resourceName` values are not supported.
|
|
46
|
+
|
|
37
47
|
## ๐ฏ Why typeweaver?
|
|
38
48
|
|
|
39
49
|
- ๐ **Define once, generate everything**: API contracts in Zod become clients, servers, validators,
|
|
@@ -91,7 +101,7 @@ bunx typeweaver generate --input ./api/spec/index.ts --output ./api/generated --
|
|
|
91
101
|
|
|
92
102
|
- `--input, -i <path>`: Spec entrypoint file (required)
|
|
93
103
|
- `--output, -o <path>`: Output directory for generated code (required)
|
|
94
|
-
- `--config, -c <path>`: Configuration file path (optional)
|
|
104
|
+
- `--config, -c <path>`: Configuration file path (`.js`, `.mjs`, or `.cjs`, optional)
|
|
95
105
|
- `--plugins, -p <plugins>`: Comma-separated list of plugins to use (e.g., "clients,hono" or "all"
|
|
96
106
|
for all plugins)
|
|
97
107
|
- `--format / --no-format`: Enable/disable code formatting with oxfmt (default: true)
|
|
@@ -99,9 +109,10 @@ bunx typeweaver generate --input ./api/spec/index.ts --output ./api/generated --
|
|
|
99
109
|
|
|
100
110
|
### ๐ Configuration File
|
|
101
111
|
|
|
102
|
-
Create a config file (
|
|
112
|
+
Create a JavaScript config file (for example `typeweaver.config.mjs`) for more complex
|
|
113
|
+
configurations:
|
|
103
114
|
|
|
104
|
-
```
|
|
115
|
+
```js
|
|
105
116
|
export default {
|
|
106
117
|
input: "./api/spec/index.ts",
|
|
107
118
|
output: "./api/generated",
|
|
@@ -114,11 +125,14 @@ export default {
|
|
|
114
125
|
Then run:
|
|
115
126
|
|
|
116
127
|
```bash
|
|
117
|
-
npx typeweaver generate --config ./typeweaver.config.
|
|
128
|
+
npx typeweaver generate --config ./typeweaver.config.mjs
|
|
118
129
|
```
|
|
119
130
|
|
|
120
131
|
> Replace `npx` with `pnpx`, `deno run -A npm:@rexeus/typeweaver`, or `bunx` depending on your
|
|
121
132
|
> runtime.
|
|
133
|
+
>
|
|
134
|
+
> TypeScript config files (`.ts`, `.mts`, `.cts`) are no longer supported by the published CLI.
|
|
135
|
+
> Convert them to JavaScript first if needed.
|
|
122
136
|
|
|
123
137
|
## ๐ฑ Get Started
|
|
124
138
|
|
|
@@ -161,10 +175,10 @@ import {
|
|
|
161
175
|
import { z } from "zod";
|
|
162
176
|
import { sharedResponses } from "../shared/sharedResponses";
|
|
163
177
|
import { userSchema } from "./userSchema";
|
|
164
|
-
import UserNotFoundErrorDefinition from "./errors/UserNotFoundErrorDefinition";
|
|
178
|
+
import { UserNotFoundErrorDefinition } from "./errors/UserNotFoundErrorDefinition";
|
|
165
179
|
|
|
166
|
-
export
|
|
167
|
-
operationId: "
|
|
180
|
+
export const GetUserDefinition = defineOperation({
|
|
181
|
+
operationId: "getUser",
|
|
168
182
|
method: HttpMethod.GET,
|
|
169
183
|
path: "/users/:userId",
|
|
170
184
|
summary: "Get a user by id",
|
|
@@ -192,9 +206,9 @@ export default defineOperation({
|
|
|
192
206
|
```typescript
|
|
193
207
|
// api/spec/index.ts
|
|
194
208
|
import { defineSpec } from "@rexeus/typeweaver-core";
|
|
195
|
-
import GetUserDefinition from "./user/GetUserDefinition";
|
|
209
|
+
import { GetUserDefinition } from "./user/GetUserDefinition";
|
|
196
210
|
|
|
197
|
-
export
|
|
211
|
+
export const spec = defineSpec({
|
|
198
212
|
resources: {
|
|
199
213
|
user: {
|
|
200
214
|
operations: [GetUserDefinition],
|
|
@@ -221,12 +235,12 @@ export const userSchema = z.object({
|
|
|
221
235
|
|
|
222
236
|
```typescript
|
|
223
237
|
// api/spec/shared/sharedResponses.ts
|
|
224
|
-
import ForbiddenErrorDefinition from "./ForbiddenErrorDefinition";
|
|
225
|
-
import InternalServerErrorDefinition from "./InternalServerErrorDefinition";
|
|
226
|
-
import TooManyRequestsErrorDefinition from "./TooManyRequestsErrorDefinition";
|
|
227
|
-
import UnauthorizedErrorDefinition from "./UnauthorizedErrorDefinition";
|
|
228
|
-
import UnsupportedMediaTypeErrorDefinition from "./UnsupportedMediaTypeErrorDefinition";
|
|
229
|
-
import ValidationErrorDefinition from "./ValidationErrorDefinition";
|
|
238
|
+
import { ForbiddenErrorDefinition } from "./ForbiddenErrorDefinition";
|
|
239
|
+
import { InternalServerErrorDefinition } from "./InternalServerErrorDefinition";
|
|
240
|
+
import { TooManyRequestsErrorDefinition } from "./TooManyRequestsErrorDefinition";
|
|
241
|
+
import { UnauthorizedErrorDefinition } from "./UnauthorizedErrorDefinition";
|
|
242
|
+
import { UnsupportedMediaTypeErrorDefinition } from "./UnsupportedMediaTypeErrorDefinition";
|
|
243
|
+
import { ValidationErrorDefinition } from "./ValidationErrorDefinition";
|
|
230
244
|
|
|
231
245
|
export const sharedResponses = [
|
|
232
246
|
ForbiddenErrorDefinition,
|
|
@@ -3,12 +3,55 @@ import fs from "node:fs";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
5
|
import { Command } from "commander";
|
|
6
|
-
import { createPluginContextBuilder, createPluginRegistry, normalizeSpec } from "@rexeus/typeweaver-gen";
|
|
7
|
-
import TypesPlugin from "@rexeus/typeweaver-types";
|
|
8
|
-
import ejs from "ejs";
|
|
6
|
+
import { createPluginContextBuilder, createPluginRegistry, normalizeSpec, renderTemplate } from "@rexeus/typeweaver-gen";
|
|
7
|
+
import { TypesPlugin } from "@rexeus/typeweaver-types";
|
|
9
8
|
import os from "node:os";
|
|
10
|
-
import {
|
|
9
|
+
import { build } from "rolldown";
|
|
11
10
|
import { HttpMethod, HttpStatusCode } from "@rexeus/typeweaver-core";
|
|
11
|
+
//#region src/configLoader.ts
|
|
12
|
+
const SUPPORTED_CONFIG_EXTENSIONS = new Set([
|
|
13
|
+
".js",
|
|
14
|
+
".mjs",
|
|
15
|
+
".cjs"
|
|
16
|
+
]);
|
|
17
|
+
const UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS = new Set([
|
|
18
|
+
".ts",
|
|
19
|
+
".mts",
|
|
20
|
+
".cts"
|
|
21
|
+
]);
|
|
22
|
+
const getResolvedConfigPath = (configPath, currentWorkingDirectory = process.cwd()) => {
|
|
23
|
+
return path.isAbsolute(configPath) ? configPath : path.join(currentWorkingDirectory, configPath);
|
|
24
|
+
};
|
|
25
|
+
const assertSupportedConfigPath = (configPath) => {
|
|
26
|
+
const extension = path.extname(configPath).toLowerCase();
|
|
27
|
+
if (UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS.has(extension)) throw new Error(`TypeScript config files are no longer supported: '${configPath}'. Convert the config to .js, .mjs, or .cjs, or compile it before passing --config.`);
|
|
28
|
+
if (!SUPPORTED_CONFIG_EXTENSIONS.has(extension)) throw new Error(`Unsupported config file extension for '${configPath}'. TypeWeaver only accepts .js, .mjs, or .cjs config files.`);
|
|
29
|
+
};
|
|
30
|
+
const loadConfig = async (configPath) => {
|
|
31
|
+
assertSupportedConfigPath(configPath);
|
|
32
|
+
const loadedConfig = getConfigExport(await import(pathToFileURL(path.resolve(configPath)).toString()), configPath);
|
|
33
|
+
if (!isConfigObject(loadedConfig)) throw new Error(`Configuration file '${configPath}' must export a config object via 'export default' or 'export const config = ...'.`);
|
|
34
|
+
return loadedConfig;
|
|
35
|
+
};
|
|
36
|
+
const getConfigExport = (configModule, configPath) => {
|
|
37
|
+
const hasDefaultExport = Object.hasOwn(configModule, "default");
|
|
38
|
+
const hasNamedConfigExport = Object.hasOwn(configModule, "config");
|
|
39
|
+
if (hasDefaultExport && hasNamedConfigExport) throw new Error(`Configuration file '${configPath}' must choose a single export style: either 'export default' or 'export const config = ...', but not both.`);
|
|
40
|
+
if (hasDefaultExport) {
|
|
41
|
+
if (isNamespaceLikeConfigExport(configModule.default)) throw new Error(`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 = ...'.`);
|
|
42
|
+
return configModule.default;
|
|
43
|
+
}
|
|
44
|
+
if (hasNamedConfigExport) return configModule.config;
|
|
45
|
+
throw new Error(`Configuration file '${configPath}' must export its config via 'export default' or 'export const config = ...'.`);
|
|
46
|
+
};
|
|
47
|
+
const isConfigObject = (value) => {
|
|
48
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
49
|
+
};
|
|
50
|
+
const isNamespaceLikeConfigExport = (value) => {
|
|
51
|
+
if (!isConfigObject(value)) return false;
|
|
52
|
+
return Object.hasOwn(value, "default") || Object.hasOwn(value, "config");
|
|
53
|
+
};
|
|
54
|
+
//#endregion
|
|
12
55
|
//#region src/generators/formatter.ts
|
|
13
56
|
async function formatCode(outputDir, startDir) {
|
|
14
57
|
const format = await loadFormatter();
|
|
@@ -68,7 +111,7 @@ function generateIndexFiles(templateDir, context) {
|
|
|
68
111
|
}
|
|
69
112
|
for (const [groupKey, entries] of groups) {
|
|
70
113
|
if (existingBarrels.has(groupKey)) continue;
|
|
71
|
-
const domainBarrelContent =
|
|
114
|
+
const domainBarrelContent = renderTemplate(template, { indexPaths: Array.from(entries).sort() });
|
|
72
115
|
const domainIndexPath = path.join(context.outputDir, groupKey, "index.ts");
|
|
73
116
|
fs.mkdirSync(path.dirname(domainIndexPath), { recursive: true });
|
|
74
117
|
fs.writeFileSync(domainIndexPath, domainBarrelContent);
|
|
@@ -76,7 +119,7 @@ function generateIndexFiles(templateDir, context) {
|
|
|
76
119
|
const rootIndexPaths = new Set(rootFiles);
|
|
77
120
|
for (const groupKey of groups.keys()) rootIndexPaths.add(`./${groupKey}`);
|
|
78
121
|
for (const barrelKey of existingBarrels) rootIndexPaths.add(`./${barrelKey}`);
|
|
79
|
-
const rootContent =
|
|
122
|
+
const rootContent = renderTemplate(template, { indexPaths: Array.from(rootIndexPaths).sort() });
|
|
80
123
|
fs.writeFileSync(path.join(context.outputDir, "index.ts"), rootContent);
|
|
81
124
|
}
|
|
82
125
|
//#endregion
|
|
@@ -109,17 +152,17 @@ async function loadPlugin(pluginName, strategies) {
|
|
|
109
152
|
const possiblePaths = generatePluginPaths(pluginName, strategies);
|
|
110
153
|
const attempts = [];
|
|
111
154
|
for (const possiblePath of possiblePaths) try {
|
|
112
|
-
const
|
|
113
|
-
if (
|
|
155
|
+
const PluginClass = findPluginConstructor(await import(possiblePath));
|
|
156
|
+
if (PluginClass) return {
|
|
114
157
|
success: true,
|
|
115
158
|
value: {
|
|
116
|
-
plugin: new
|
|
159
|
+
plugin: new PluginClass(),
|
|
117
160
|
source: possiblePath
|
|
118
161
|
}
|
|
119
162
|
};
|
|
120
163
|
attempts.push({
|
|
121
164
|
path: possiblePath,
|
|
122
|
-
error: "No
|
|
165
|
+
error: "No plugin class export found"
|
|
123
166
|
});
|
|
124
167
|
} catch (error) {
|
|
125
168
|
attempts.push({
|
|
@@ -135,6 +178,11 @@ async function loadPlugin(pluginName, strategies) {
|
|
|
135
178
|
}
|
|
136
179
|
};
|
|
137
180
|
}
|
|
181
|
+
function findPluginConstructor(pluginModule) {
|
|
182
|
+
for (const [key, value] of Object.entries(pluginModule)) if (key !== "default" && typeof value === "function") return value;
|
|
183
|
+
const defaultExport = pluginModule.default;
|
|
184
|
+
if (typeof defaultExport === "function") return defaultExport;
|
|
185
|
+
}
|
|
138
186
|
function generatePluginPaths(pluginName, strategies) {
|
|
139
187
|
const paths = [];
|
|
140
188
|
for (const strategy of strategies) switch (strategy) {
|
|
@@ -176,16 +224,15 @@ async function bundle(config) {
|
|
|
176
224
|
fs.writeFileSync(wrapperFile, [
|
|
177
225
|
`import * as specModule from ${JSON.stringify(wrapperImportSpecifier)};`,
|
|
178
226
|
"const resolvedSpec =",
|
|
179
|
-
" Reflect.get(specModule, \"default\") ??",
|
|
180
227
|
" Reflect.get(specModule, \"spec\") ??",
|
|
228
|
+
" Reflect.get(specModule, \"default\") ??",
|
|
181
229
|
" specModule;",
|
|
182
230
|
"",
|
|
183
|
-
"export default resolvedSpec;",
|
|
184
231
|
"export const spec = resolvedSpec;",
|
|
185
232
|
""
|
|
186
233
|
].join("\n"));
|
|
187
234
|
try {
|
|
188
|
-
await
|
|
235
|
+
await build({
|
|
189
236
|
cwd: tempDir,
|
|
190
237
|
input: wrapperFile,
|
|
191
238
|
treeshake: true,
|
|
@@ -256,7 +303,7 @@ const isSpecDefinition = (value) => {
|
|
|
256
303
|
//#region src/generators/spec/specImporter.ts
|
|
257
304
|
async function importDefinition(bundledSpecFile) {
|
|
258
305
|
const specModule = await import(pathToFileURL(bundledSpecFile).toString());
|
|
259
|
-
const definition = specModule.
|
|
306
|
+
const definition = specModule.spec ?? specModule.default ?? specModule;
|
|
260
307
|
if (!isSpecDefinition(definition)) throw new InvalidSpecEntrypointError(bundledSpecFile);
|
|
261
308
|
return definition;
|
|
262
309
|
}
|
|
@@ -275,8 +322,6 @@ async function loadSpec(config) {
|
|
|
275
322
|
function writeSpecDeclarationFile(specOutputDir) {
|
|
276
323
|
fs.writeFileSync(`${specOutputDir}/spec.d.ts`, [
|
|
277
324
|
"import type { SpecDefinition } from \"@rexeus/typeweaver-core\";",
|
|
278
|
-
"declare const _default: SpecDefinition;",
|
|
279
|
-
"export default _default;",
|
|
280
325
|
"export declare const spec: SpecDefinition;",
|
|
281
326
|
""
|
|
282
327
|
].join("\n"));
|
|
@@ -284,6 +329,16 @@ function writeSpecDeclarationFile(specOutputDir) {
|
|
|
284
329
|
//#endregion
|
|
285
330
|
//#region src/generators/Generator.ts
|
|
286
331
|
const moduleDir$1 = path.dirname(fileURLToPath(import.meta.url));
|
|
332
|
+
const assertSafeCleanTarget = (outputDir, currentWorkingDirectory) => {
|
|
333
|
+
const trimmedOutputDir = outputDir.trim();
|
|
334
|
+
if (trimmedOutputDir.length === 0) throw new Error("Refusing to clean an empty output directory path. Pass a dedicated generated output directory instead.");
|
|
335
|
+
const resolvedWorkingDirectory = path.resolve(currentWorkingDirectory);
|
|
336
|
+
const resolvedOutputDir = path.resolve(resolvedWorkingDirectory, trimmedOutputDir);
|
|
337
|
+
if (resolvedOutputDir === path.parse(resolvedOutputDir).root) throw new Error(`Refusing to clean '${outputDir}' because it resolves to the filesystem root.`);
|
|
338
|
+
if (resolvedOutputDir === resolvedWorkingDirectory) throw new Error(`Refusing to clean '${outputDir}' because it resolves to the current working directory.`);
|
|
339
|
+
const protectedWorkspaceRoot = findProtectedWorkspaceRoot(resolvedWorkingDirectory);
|
|
340
|
+
if (protectedWorkspaceRoot !== void 0 && resolvedOutputDir === protectedWorkspaceRoot) throw new Error(`Refusing to clean '${outputDir}' because it resolves to the inferred workspace root '${protectedWorkspaceRoot}'. Choose a dedicated output subdirectory instead.`);
|
|
341
|
+
};
|
|
287
342
|
/**
|
|
288
343
|
* Main generator for typeweaver
|
|
289
344
|
* Uses a plugin-based architecture for extensible code generation
|
|
@@ -306,10 +361,11 @@ var Generator = class {
|
|
|
306
361
|
/**
|
|
307
362
|
* Generate code using the plugin system
|
|
308
363
|
*/
|
|
309
|
-
async generate(specFile, outputDir, config) {
|
|
364
|
+
async generate(specFile, outputDir, config, currentWorkingDirectory = process.cwd()) {
|
|
310
365
|
console.info("Starting generation...");
|
|
311
|
-
this.initializeDirectories(specFile, outputDir);
|
|
366
|
+
this.initializeDirectories(specFile, outputDir, currentWorkingDirectory);
|
|
312
367
|
if (config?.clean ?? true) {
|
|
368
|
+
assertSafeCleanTarget(this.outputDir, currentWorkingDirectory);
|
|
313
369
|
console.info("Cleaning output directory...");
|
|
314
370
|
fs.rmSync(this.outputDir, {
|
|
315
371
|
recursive: true,
|
|
@@ -356,13 +412,25 @@ var Generator = class {
|
|
|
356
412
|
console.info("Generation complete!");
|
|
357
413
|
console.info(`Generated files: ${this.contextBuilder.getGeneratedFiles().length}`);
|
|
358
414
|
}
|
|
359
|
-
initializeDirectories(specFile, outputDir) {
|
|
360
|
-
this.inputFile = specFile;
|
|
361
|
-
this.outputDir = outputDir;
|
|
362
|
-
this.responsesOutputDir = path.join(outputDir, "responses");
|
|
415
|
+
initializeDirectories(specFile, outputDir, currentWorkingDirectory) {
|
|
416
|
+
this.inputFile = path.resolve(currentWorkingDirectory, specFile);
|
|
417
|
+
this.outputDir = path.resolve(currentWorkingDirectory, outputDir);
|
|
418
|
+
this.responsesOutputDir = path.join(this.outputDir, "responses");
|
|
363
419
|
this.specOutputDir = path.join(this.outputDir, "spec");
|
|
364
420
|
}
|
|
365
421
|
};
|
|
422
|
+
const findProtectedWorkspaceRoot = (startDirectory) => {
|
|
423
|
+
let currentDirectory = startDirectory;
|
|
424
|
+
while (true) {
|
|
425
|
+
if (hasWorkspaceMarker(currentDirectory)) return currentDirectory;
|
|
426
|
+
const parentDirectory = path.dirname(currentDirectory);
|
|
427
|
+
if (parentDirectory === currentDirectory) return;
|
|
428
|
+
currentDirectory = parentDirectory;
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
const hasWorkspaceMarker = (directory) => {
|
|
432
|
+
return ["pnpm-workspace.yaml", ".git"].some((marker) => fs.existsSync(path.join(directory, marker)));
|
|
433
|
+
};
|
|
366
434
|
//#endregion
|
|
367
435
|
//#region src/cli.ts
|
|
368
436
|
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -370,13 +438,12 @@ const packageJson = JSON.parse(fs.readFileSync(path.join(moduleDir, "../package.
|
|
|
370
438
|
const program = new Command();
|
|
371
439
|
const execDir = process.cwd();
|
|
372
440
|
program.name("@rexeus/typeweaver").description("Type-safe API framework with code generation for TypeScript").version(packageJson.version);
|
|
373
|
-
program.command("generate").description("Generate types, validators, and clients from an API spec").option("-i, --input <inputPath>", "path to spec entrypoint file").option("-o, --output <outputDir>", "output directory for generated files").option("-c, --config <configFile>", "path to configuration file").option("-p, --plugins <plugins>", "comma-separated list of plugins to use").option("--format", "format generated code with oxfmt (default: true)").option("--no-format", "disable code formatting").option("--clean", "clean output directory before generation (default: true)").option("--no-clean", "disable cleaning output directory").action(async (options) => {
|
|
441
|
+
program.command("generate").description("Generate types, validators, and clients from an API spec").option("-i, --input <inputPath>", "path to spec entrypoint file").option("-o, --output <outputDir>", "output directory for generated files").option("-c, --config <configFile>", "path to a .js, .mjs, or .cjs configuration file").option("-p, --plugins <plugins>", "comma-separated list of plugins to use").option("--format", "format generated code with oxfmt (default: true)").option("--no-format", "disable code formatting").option("--clean", "clean output directory before generation (default: true)").option("--no-clean", "disable cleaning output directory").action(async (options) => {
|
|
374
442
|
let config = {};
|
|
375
443
|
if (options.config) {
|
|
376
|
-
const configPath =
|
|
444
|
+
const configPath = getResolvedConfigPath(options.config, execDir);
|
|
377
445
|
try {
|
|
378
|
-
|
|
379
|
-
config = configModule.default ?? configModule;
|
|
446
|
+
config = await loadConfig(configPath);
|
|
380
447
|
console.info(`Loaded configuration from ${configPath}`);
|
|
381
448
|
} catch (error) {
|
|
382
449
|
console.error(`Failed to load configuration file: ${options.config}`);
|
|
@@ -398,7 +465,7 @@ program.command("generate").description("Generate types, validators, and clients
|
|
|
398
465
|
};
|
|
399
466
|
if (options.plugins) finalConfig.plugins = options.plugins.split(",").map((p) => p.trim());
|
|
400
467
|
else if (config.plugins) finalConfig.plugins = config.plugins;
|
|
401
|
-
return new Generator().generate(resolvedInputPath, resolvedOutputDir, finalConfig);
|
|
468
|
+
return new Generator().generate(resolvedInputPath, resolvedOutputDir, finalConfig, execDir);
|
|
402
469
|
});
|
|
403
470
|
program.command("init").description("Initialize a new typeweaver project (coming soon)").action(() => {
|
|
404
471
|
console.log("The init command is coming soon!");
|
package/dist/cli.cjs
CHANGED
|
@@ -28,13 +28,54 @@ let node_url = require("node:url");
|
|
|
28
28
|
let commander = require("commander");
|
|
29
29
|
let _rexeus_typeweaver_gen = require("@rexeus/typeweaver-gen");
|
|
30
30
|
let _rexeus_typeweaver_types = require("@rexeus/typeweaver-types");
|
|
31
|
-
_rexeus_typeweaver_types = __toESM(_rexeus_typeweaver_types);
|
|
32
|
-
let ejs = require("ejs");
|
|
33
|
-
ejs = __toESM(ejs);
|
|
34
31
|
let node_os = require("node:os");
|
|
35
32
|
node_os = __toESM(node_os);
|
|
36
|
-
let
|
|
33
|
+
let rolldown = require("rolldown");
|
|
37
34
|
let _rexeus_typeweaver_core = require("@rexeus/typeweaver-core");
|
|
35
|
+
//#region src/configLoader.ts
|
|
36
|
+
const SUPPORTED_CONFIG_EXTENSIONS = new Set([
|
|
37
|
+
".js",
|
|
38
|
+
".mjs",
|
|
39
|
+
".cjs"
|
|
40
|
+
]);
|
|
41
|
+
const UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS = new Set([
|
|
42
|
+
".ts",
|
|
43
|
+
".mts",
|
|
44
|
+
".cts"
|
|
45
|
+
]);
|
|
46
|
+
const getResolvedConfigPath = (configPath, currentWorkingDirectory = process.cwd()) => {
|
|
47
|
+
return node_path.default.isAbsolute(configPath) ? configPath : node_path.default.join(currentWorkingDirectory, configPath);
|
|
48
|
+
};
|
|
49
|
+
const assertSupportedConfigPath = (configPath) => {
|
|
50
|
+
const extension = node_path.default.extname(configPath).toLowerCase();
|
|
51
|
+
if (UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS.has(extension)) throw new Error(`TypeScript config files are no longer supported: '${configPath}'. Convert the config to .js, .mjs, or .cjs, or compile it before passing --config.`);
|
|
52
|
+
if (!SUPPORTED_CONFIG_EXTENSIONS.has(extension)) throw new Error(`Unsupported config file extension for '${configPath}'. TypeWeaver only accepts .js, .mjs, or .cjs config files.`);
|
|
53
|
+
};
|
|
54
|
+
const loadConfig = async (configPath) => {
|
|
55
|
+
assertSupportedConfigPath(configPath);
|
|
56
|
+
const loadedConfig = getConfigExport(await import((0, node_url.pathToFileURL)(node_path.default.resolve(configPath)).toString()), configPath);
|
|
57
|
+
if (!isConfigObject(loadedConfig)) throw new Error(`Configuration file '${configPath}' must export a config object via 'export default' or 'export const config = ...'.`);
|
|
58
|
+
return loadedConfig;
|
|
59
|
+
};
|
|
60
|
+
const getConfigExport = (configModule, configPath) => {
|
|
61
|
+
const hasDefaultExport = Object.hasOwn(configModule, "default");
|
|
62
|
+
const hasNamedConfigExport = Object.hasOwn(configModule, "config");
|
|
63
|
+
if (hasDefaultExport && hasNamedConfigExport) throw new Error(`Configuration file '${configPath}' must choose a single export style: either 'export default' or 'export const config = ...', but not both.`);
|
|
64
|
+
if (hasDefaultExport) {
|
|
65
|
+
if (isNamespaceLikeConfigExport(configModule.default)) throw new Error(`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 = ...'.`);
|
|
66
|
+
return configModule.default;
|
|
67
|
+
}
|
|
68
|
+
if (hasNamedConfigExport) return configModule.config;
|
|
69
|
+
throw new Error(`Configuration file '${configPath}' must export its config via 'export default' or 'export const config = ...'.`);
|
|
70
|
+
};
|
|
71
|
+
const isConfigObject = (value) => {
|
|
72
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
73
|
+
};
|
|
74
|
+
const isNamespaceLikeConfigExport = (value) => {
|
|
75
|
+
if (!isConfigObject(value)) return false;
|
|
76
|
+
return Object.hasOwn(value, "default") || Object.hasOwn(value, "config");
|
|
77
|
+
};
|
|
78
|
+
//#endregion
|
|
38
79
|
//#region src/generators/formatter.ts
|
|
39
80
|
async function formatCode(outputDir, startDir) {
|
|
40
81
|
const format = await loadFormatter();
|
|
@@ -94,7 +135,7 @@ function generateIndexFiles(templateDir, context) {
|
|
|
94
135
|
}
|
|
95
136
|
for (const [groupKey, entries] of groups) {
|
|
96
137
|
if (existingBarrels.has(groupKey)) continue;
|
|
97
|
-
const domainBarrelContent =
|
|
138
|
+
const domainBarrelContent = (0, _rexeus_typeweaver_gen.renderTemplate)(template, { indexPaths: Array.from(entries).sort() });
|
|
98
139
|
const domainIndexPath = node_path.default.join(context.outputDir, groupKey, "index.ts");
|
|
99
140
|
node_fs.default.mkdirSync(node_path.default.dirname(domainIndexPath), { recursive: true });
|
|
100
141
|
node_fs.default.writeFileSync(domainIndexPath, domainBarrelContent);
|
|
@@ -102,7 +143,7 @@ function generateIndexFiles(templateDir, context) {
|
|
|
102
143
|
const rootIndexPaths = new Set(rootFiles);
|
|
103
144
|
for (const groupKey of groups.keys()) rootIndexPaths.add(`./${groupKey}`);
|
|
104
145
|
for (const barrelKey of existingBarrels) rootIndexPaths.add(`./${barrelKey}`);
|
|
105
|
-
const rootContent =
|
|
146
|
+
const rootContent = (0, _rexeus_typeweaver_gen.renderTemplate)(template, { indexPaths: Array.from(rootIndexPaths).sort() });
|
|
106
147
|
node_fs.default.writeFileSync(node_path.default.join(context.outputDir, "index.ts"), rootContent);
|
|
107
148
|
}
|
|
108
149
|
//#endregion
|
|
@@ -135,17 +176,17 @@ async function loadPlugin(pluginName, strategies) {
|
|
|
135
176
|
const possiblePaths = generatePluginPaths(pluginName, strategies);
|
|
136
177
|
const attempts = [];
|
|
137
178
|
for (const possiblePath of possiblePaths) try {
|
|
138
|
-
const
|
|
139
|
-
if (
|
|
179
|
+
const PluginClass = findPluginConstructor(await import(possiblePath));
|
|
180
|
+
if (PluginClass) return {
|
|
140
181
|
success: true,
|
|
141
182
|
value: {
|
|
142
|
-
plugin: new
|
|
183
|
+
plugin: new PluginClass(),
|
|
143
184
|
source: possiblePath
|
|
144
185
|
}
|
|
145
186
|
};
|
|
146
187
|
attempts.push({
|
|
147
188
|
path: possiblePath,
|
|
148
|
-
error: "No
|
|
189
|
+
error: "No plugin class export found"
|
|
149
190
|
});
|
|
150
191
|
} catch (error) {
|
|
151
192
|
attempts.push({
|
|
@@ -161,6 +202,11 @@ async function loadPlugin(pluginName, strategies) {
|
|
|
161
202
|
}
|
|
162
203
|
};
|
|
163
204
|
}
|
|
205
|
+
function findPluginConstructor(pluginModule) {
|
|
206
|
+
for (const [key, value] of Object.entries(pluginModule)) if (key !== "default" && typeof value === "function") return value;
|
|
207
|
+
const defaultExport = pluginModule.default;
|
|
208
|
+
if (typeof defaultExport === "function") return defaultExport;
|
|
209
|
+
}
|
|
164
210
|
function generatePluginPaths(pluginName, strategies) {
|
|
165
211
|
const paths = [];
|
|
166
212
|
for (const strategy of strategies) switch (strategy) {
|
|
@@ -202,16 +248,15 @@ async function bundle(config) {
|
|
|
202
248
|
node_fs.default.writeFileSync(wrapperFile, [
|
|
203
249
|
`import * as specModule from ${JSON.stringify(wrapperImportSpecifier)};`,
|
|
204
250
|
"const resolvedSpec =",
|
|
205
|
-
" Reflect.get(specModule, \"default\") ??",
|
|
206
251
|
" Reflect.get(specModule, \"spec\") ??",
|
|
252
|
+
" Reflect.get(specModule, \"default\") ??",
|
|
207
253
|
" specModule;",
|
|
208
254
|
"",
|
|
209
|
-
"export default resolvedSpec;",
|
|
210
255
|
"export const spec = resolvedSpec;",
|
|
211
256
|
""
|
|
212
257
|
].join("\n"));
|
|
213
258
|
try {
|
|
214
|
-
await
|
|
259
|
+
await (0, rolldown.build)({
|
|
215
260
|
cwd: tempDir,
|
|
216
261
|
input: wrapperFile,
|
|
217
262
|
treeshake: true,
|
|
@@ -282,7 +327,7 @@ const isSpecDefinition = (value) => {
|
|
|
282
327
|
//#region src/generators/spec/specImporter.ts
|
|
283
328
|
async function importDefinition(bundledSpecFile) {
|
|
284
329
|
const specModule = await import((0, node_url.pathToFileURL)(bundledSpecFile).toString());
|
|
285
|
-
const definition = specModule.
|
|
330
|
+
const definition = specModule.spec ?? specModule.default ?? specModule;
|
|
286
331
|
if (!isSpecDefinition(definition)) throw new InvalidSpecEntrypointError(bundledSpecFile);
|
|
287
332
|
return definition;
|
|
288
333
|
}
|
|
@@ -301,8 +346,6 @@ async function loadSpec(config) {
|
|
|
301
346
|
function writeSpecDeclarationFile(specOutputDir) {
|
|
302
347
|
node_fs.default.writeFileSync(`${specOutputDir}/spec.d.ts`, [
|
|
303
348
|
"import type { SpecDefinition } from \"@rexeus/typeweaver-core\";",
|
|
304
|
-
"declare const _default: SpecDefinition;",
|
|
305
|
-
"export default _default;",
|
|
306
349
|
"export declare const spec: SpecDefinition;",
|
|
307
350
|
""
|
|
308
351
|
].join("\n"));
|
|
@@ -310,6 +353,16 @@ function writeSpecDeclarationFile(specOutputDir) {
|
|
|
310
353
|
//#endregion
|
|
311
354
|
//#region src/generators/Generator.ts
|
|
312
355
|
const moduleDir$1 = node_path.default.dirname((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
|
|
356
|
+
const assertSafeCleanTarget = (outputDir, currentWorkingDirectory) => {
|
|
357
|
+
const trimmedOutputDir = outputDir.trim();
|
|
358
|
+
if (trimmedOutputDir.length === 0) throw new Error("Refusing to clean an empty output directory path. Pass a dedicated generated output directory instead.");
|
|
359
|
+
const resolvedWorkingDirectory = node_path.default.resolve(currentWorkingDirectory);
|
|
360
|
+
const resolvedOutputDir = node_path.default.resolve(resolvedWorkingDirectory, trimmedOutputDir);
|
|
361
|
+
if (resolvedOutputDir === node_path.default.parse(resolvedOutputDir).root) throw new Error(`Refusing to clean '${outputDir}' because it resolves to the filesystem root.`);
|
|
362
|
+
if (resolvedOutputDir === resolvedWorkingDirectory) throw new Error(`Refusing to clean '${outputDir}' because it resolves to the current working directory.`);
|
|
363
|
+
const protectedWorkspaceRoot = findProtectedWorkspaceRoot(resolvedWorkingDirectory);
|
|
364
|
+
if (protectedWorkspaceRoot !== void 0 && resolvedOutputDir === protectedWorkspaceRoot) throw new Error(`Refusing to clean '${outputDir}' because it resolves to the inferred workspace root '${protectedWorkspaceRoot}'. Choose a dedicated output subdirectory instead.`);
|
|
365
|
+
};
|
|
313
366
|
/**
|
|
314
367
|
* Main generator for typeweaver
|
|
315
368
|
* Uses a plugin-based architecture for extensible code generation
|
|
@@ -325,17 +378,18 @@ var Generator = class {
|
|
|
325
378
|
outputDir = "";
|
|
326
379
|
specOutputDir = "";
|
|
327
380
|
responsesOutputDir = "";
|
|
328
|
-
constructor(requiredPlugins = [new _rexeus_typeweaver_types.
|
|
381
|
+
constructor(requiredPlugins = [new _rexeus_typeweaver_types.TypesPlugin()], strategies) {
|
|
329
382
|
this.requiredPlugins = requiredPlugins;
|
|
330
383
|
this.strategies = strategies ?? ["npm", "local"];
|
|
331
384
|
}
|
|
332
385
|
/**
|
|
333
386
|
* Generate code using the plugin system
|
|
334
387
|
*/
|
|
335
|
-
async generate(specFile, outputDir, config) {
|
|
388
|
+
async generate(specFile, outputDir, config, currentWorkingDirectory = process.cwd()) {
|
|
336
389
|
console.info("Starting generation...");
|
|
337
|
-
this.initializeDirectories(specFile, outputDir);
|
|
390
|
+
this.initializeDirectories(specFile, outputDir, currentWorkingDirectory);
|
|
338
391
|
if (config?.clean ?? true) {
|
|
392
|
+
assertSafeCleanTarget(this.outputDir, currentWorkingDirectory);
|
|
339
393
|
console.info("Cleaning output directory...");
|
|
340
394
|
node_fs.default.rmSync(this.outputDir, {
|
|
341
395
|
recursive: true,
|
|
@@ -382,13 +436,25 @@ var Generator = class {
|
|
|
382
436
|
console.info("Generation complete!");
|
|
383
437
|
console.info(`Generated files: ${this.contextBuilder.getGeneratedFiles().length}`);
|
|
384
438
|
}
|
|
385
|
-
initializeDirectories(specFile, outputDir) {
|
|
386
|
-
this.inputFile = specFile;
|
|
387
|
-
this.outputDir = outputDir;
|
|
388
|
-
this.responsesOutputDir = node_path.default.join(outputDir, "responses");
|
|
439
|
+
initializeDirectories(specFile, outputDir, currentWorkingDirectory) {
|
|
440
|
+
this.inputFile = node_path.default.resolve(currentWorkingDirectory, specFile);
|
|
441
|
+
this.outputDir = node_path.default.resolve(currentWorkingDirectory, outputDir);
|
|
442
|
+
this.responsesOutputDir = node_path.default.join(this.outputDir, "responses");
|
|
389
443
|
this.specOutputDir = node_path.default.join(this.outputDir, "spec");
|
|
390
444
|
}
|
|
391
445
|
};
|
|
446
|
+
const findProtectedWorkspaceRoot = (startDirectory) => {
|
|
447
|
+
let currentDirectory = startDirectory;
|
|
448
|
+
while (true) {
|
|
449
|
+
if (hasWorkspaceMarker(currentDirectory)) return currentDirectory;
|
|
450
|
+
const parentDirectory = node_path.default.dirname(currentDirectory);
|
|
451
|
+
if (parentDirectory === currentDirectory) return;
|
|
452
|
+
currentDirectory = parentDirectory;
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
const hasWorkspaceMarker = (directory) => {
|
|
456
|
+
return ["pnpm-workspace.yaml", ".git"].some((marker) => node_fs.default.existsSync(node_path.default.join(directory, marker)));
|
|
457
|
+
};
|
|
392
458
|
//#endregion
|
|
393
459
|
//#region src/cli.ts
|
|
394
460
|
const moduleDir = node_path.default.dirname((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
|
|
@@ -396,13 +462,12 @@ const packageJson = JSON.parse(node_fs.default.readFileSync(node_path.default.jo
|
|
|
396
462
|
const program = new commander.Command();
|
|
397
463
|
const execDir = process.cwd();
|
|
398
464
|
program.name("@rexeus/typeweaver").description("Type-safe API framework with code generation for TypeScript").version(packageJson.version);
|
|
399
|
-
program.command("generate").description("Generate types, validators, and clients from an API spec").option("-i, --input <inputPath>", "path to spec entrypoint file").option("-o, --output <outputDir>", "output directory for generated files").option("-c, --config <configFile>", "path to configuration file").option("-p, --plugins <plugins>", "comma-separated list of plugins to use").option("--format", "format generated code with oxfmt (default: true)").option("--no-format", "disable code formatting").option("--clean", "clean output directory before generation (default: true)").option("--no-clean", "disable cleaning output directory").action(async (options) => {
|
|
465
|
+
program.command("generate").description("Generate types, validators, and clients from an API spec").option("-i, --input <inputPath>", "path to spec entrypoint file").option("-o, --output <outputDir>", "output directory for generated files").option("-c, --config <configFile>", "path to a .js, .mjs, or .cjs configuration file").option("-p, --plugins <plugins>", "comma-separated list of plugins to use").option("--format", "format generated code with oxfmt (default: true)").option("--no-format", "disable code formatting").option("--clean", "clean output directory before generation (default: true)").option("--no-clean", "disable cleaning output directory").action(async (options) => {
|
|
400
466
|
let config = {};
|
|
401
467
|
if (options.config) {
|
|
402
|
-
const configPath =
|
|
468
|
+
const configPath = getResolvedConfigPath(options.config, execDir);
|
|
403
469
|
try {
|
|
404
|
-
|
|
405
|
-
config = configModule.default ?? configModule;
|
|
470
|
+
config = await loadConfig(configPath);
|
|
406
471
|
console.info(`Loaded configuration from ${configPath}`);
|
|
407
472
|
} catch (error) {
|
|
408
473
|
console.error(`Failed to load configuration file: ${options.config}`);
|
|
@@ -424,7 +489,7 @@ program.command("generate").description("Generate types, validators, and clients
|
|
|
424
489
|
};
|
|
425
490
|
if (options.plugins) finalConfig.plugins = options.plugins.split(",").map((p) => p.trim());
|
|
426
491
|
else if (config.plugins) finalConfig.plugins = config.plugins;
|
|
427
|
-
return new Generator().generate(resolvedInputPath, resolvedOutputDir, finalConfig);
|
|
492
|
+
return new Generator().generate(resolvedInputPath, resolvedOutputDir, finalConfig, execDir);
|
|
428
493
|
});
|
|
429
494
|
program.command("init").description("Initialize a new typeweaver project (coming soon)").action(() => {
|
|
430
495
|
console.log("The init command is coming soon!");
|
package/dist/cli.mjs
CHANGED
|
@@ -2,12 +2,55 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import { createPluginContextBuilder, createPluginRegistry, normalizeSpec } from "@rexeus/typeweaver-gen";
|
|
6
|
-
import TypesPlugin from "@rexeus/typeweaver-types";
|
|
7
|
-
import ejs from "ejs";
|
|
5
|
+
import { createPluginContextBuilder, createPluginRegistry, normalizeSpec, renderTemplate } from "@rexeus/typeweaver-gen";
|
|
6
|
+
import { TypesPlugin } from "@rexeus/typeweaver-types";
|
|
8
7
|
import os from "node:os";
|
|
9
|
-
import {
|
|
8
|
+
import { build } from "rolldown";
|
|
10
9
|
import { HttpMethod, HttpStatusCode } from "@rexeus/typeweaver-core";
|
|
10
|
+
//#region src/configLoader.ts
|
|
11
|
+
const SUPPORTED_CONFIG_EXTENSIONS = new Set([
|
|
12
|
+
".js",
|
|
13
|
+
".mjs",
|
|
14
|
+
".cjs"
|
|
15
|
+
]);
|
|
16
|
+
const UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS = new Set([
|
|
17
|
+
".ts",
|
|
18
|
+
".mts",
|
|
19
|
+
".cts"
|
|
20
|
+
]);
|
|
21
|
+
const getResolvedConfigPath = (configPath, currentWorkingDirectory = process.cwd()) => {
|
|
22
|
+
return path.isAbsolute(configPath) ? configPath : path.join(currentWorkingDirectory, configPath);
|
|
23
|
+
};
|
|
24
|
+
const assertSupportedConfigPath = (configPath) => {
|
|
25
|
+
const extension = path.extname(configPath).toLowerCase();
|
|
26
|
+
if (UNSUPPORTED_TYPESCRIPT_CONFIG_EXTENSIONS.has(extension)) throw new Error(`TypeScript config files are no longer supported: '${configPath}'. Convert the config to .js, .mjs, or .cjs, or compile it before passing --config.`);
|
|
27
|
+
if (!SUPPORTED_CONFIG_EXTENSIONS.has(extension)) throw new Error(`Unsupported config file extension for '${configPath}'. TypeWeaver only accepts .js, .mjs, or .cjs config files.`);
|
|
28
|
+
};
|
|
29
|
+
const loadConfig = async (configPath) => {
|
|
30
|
+
assertSupportedConfigPath(configPath);
|
|
31
|
+
const loadedConfig = getConfigExport(await import(pathToFileURL(path.resolve(configPath)).toString()), configPath);
|
|
32
|
+
if (!isConfigObject(loadedConfig)) throw new Error(`Configuration file '${configPath}' must export a config object via 'export default' or 'export const config = ...'.`);
|
|
33
|
+
return loadedConfig;
|
|
34
|
+
};
|
|
35
|
+
const getConfigExport = (configModule, configPath) => {
|
|
36
|
+
const hasDefaultExport = Object.hasOwn(configModule, "default");
|
|
37
|
+
const hasNamedConfigExport = Object.hasOwn(configModule, "config");
|
|
38
|
+
if (hasDefaultExport && hasNamedConfigExport) throw new Error(`Configuration file '${configPath}' must choose a single export style: either 'export default' or 'export const config = ...', but not both.`);
|
|
39
|
+
if (hasDefaultExport) {
|
|
40
|
+
if (isNamespaceLikeConfigExport(configModule.default)) throw new Error(`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 = ...'.`);
|
|
41
|
+
return configModule.default;
|
|
42
|
+
}
|
|
43
|
+
if (hasNamedConfigExport) return configModule.config;
|
|
44
|
+
throw new Error(`Configuration file '${configPath}' must export its config via 'export default' or 'export const config = ...'.`);
|
|
45
|
+
};
|
|
46
|
+
const isConfigObject = (value) => {
|
|
47
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
48
|
+
};
|
|
49
|
+
const isNamespaceLikeConfigExport = (value) => {
|
|
50
|
+
if (!isConfigObject(value)) return false;
|
|
51
|
+
return Object.hasOwn(value, "default") || Object.hasOwn(value, "config");
|
|
52
|
+
};
|
|
53
|
+
//#endregion
|
|
11
54
|
//#region src/generators/formatter.ts
|
|
12
55
|
async function formatCode(outputDir, startDir) {
|
|
13
56
|
const format = await loadFormatter();
|
|
@@ -67,7 +110,7 @@ function generateIndexFiles(templateDir, context) {
|
|
|
67
110
|
}
|
|
68
111
|
for (const [groupKey, entries] of groups) {
|
|
69
112
|
if (existingBarrels.has(groupKey)) continue;
|
|
70
|
-
const domainBarrelContent =
|
|
113
|
+
const domainBarrelContent = renderTemplate(template, { indexPaths: Array.from(entries).sort() });
|
|
71
114
|
const domainIndexPath = path.join(context.outputDir, groupKey, "index.ts");
|
|
72
115
|
fs.mkdirSync(path.dirname(domainIndexPath), { recursive: true });
|
|
73
116
|
fs.writeFileSync(domainIndexPath, domainBarrelContent);
|
|
@@ -75,7 +118,7 @@ function generateIndexFiles(templateDir, context) {
|
|
|
75
118
|
const rootIndexPaths = new Set(rootFiles);
|
|
76
119
|
for (const groupKey of groups.keys()) rootIndexPaths.add(`./${groupKey}`);
|
|
77
120
|
for (const barrelKey of existingBarrels) rootIndexPaths.add(`./${barrelKey}`);
|
|
78
|
-
const rootContent =
|
|
121
|
+
const rootContent = renderTemplate(template, { indexPaths: Array.from(rootIndexPaths).sort() });
|
|
79
122
|
fs.writeFileSync(path.join(context.outputDir, "index.ts"), rootContent);
|
|
80
123
|
}
|
|
81
124
|
//#endregion
|
|
@@ -108,17 +151,17 @@ async function loadPlugin(pluginName, strategies) {
|
|
|
108
151
|
const possiblePaths = generatePluginPaths(pluginName, strategies);
|
|
109
152
|
const attempts = [];
|
|
110
153
|
for (const possiblePath of possiblePaths) try {
|
|
111
|
-
const
|
|
112
|
-
if (
|
|
154
|
+
const PluginClass = findPluginConstructor(await import(possiblePath));
|
|
155
|
+
if (PluginClass) return {
|
|
113
156
|
success: true,
|
|
114
157
|
value: {
|
|
115
|
-
plugin: new
|
|
158
|
+
plugin: new PluginClass(),
|
|
116
159
|
source: possiblePath
|
|
117
160
|
}
|
|
118
161
|
};
|
|
119
162
|
attempts.push({
|
|
120
163
|
path: possiblePath,
|
|
121
|
-
error: "No
|
|
164
|
+
error: "No plugin class export found"
|
|
122
165
|
});
|
|
123
166
|
} catch (error) {
|
|
124
167
|
attempts.push({
|
|
@@ -134,6 +177,11 @@ async function loadPlugin(pluginName, strategies) {
|
|
|
134
177
|
}
|
|
135
178
|
};
|
|
136
179
|
}
|
|
180
|
+
function findPluginConstructor(pluginModule) {
|
|
181
|
+
for (const [key, value] of Object.entries(pluginModule)) if (key !== "default" && typeof value === "function") return value;
|
|
182
|
+
const defaultExport = pluginModule.default;
|
|
183
|
+
if (typeof defaultExport === "function") return defaultExport;
|
|
184
|
+
}
|
|
137
185
|
function generatePluginPaths(pluginName, strategies) {
|
|
138
186
|
const paths = [];
|
|
139
187
|
for (const strategy of strategies) switch (strategy) {
|
|
@@ -175,16 +223,15 @@ async function bundle(config) {
|
|
|
175
223
|
fs.writeFileSync(wrapperFile, [
|
|
176
224
|
`import * as specModule from ${JSON.stringify(wrapperImportSpecifier)};`,
|
|
177
225
|
"const resolvedSpec =",
|
|
178
|
-
" Reflect.get(specModule, \"default\") ??",
|
|
179
226
|
" Reflect.get(specModule, \"spec\") ??",
|
|
227
|
+
" Reflect.get(specModule, \"default\") ??",
|
|
180
228
|
" specModule;",
|
|
181
229
|
"",
|
|
182
|
-
"export default resolvedSpec;",
|
|
183
230
|
"export const spec = resolvedSpec;",
|
|
184
231
|
""
|
|
185
232
|
].join("\n"));
|
|
186
233
|
try {
|
|
187
|
-
await
|
|
234
|
+
await build({
|
|
188
235
|
cwd: tempDir,
|
|
189
236
|
input: wrapperFile,
|
|
190
237
|
treeshake: true,
|
|
@@ -255,7 +302,7 @@ const isSpecDefinition = (value) => {
|
|
|
255
302
|
//#region src/generators/spec/specImporter.ts
|
|
256
303
|
async function importDefinition(bundledSpecFile) {
|
|
257
304
|
const specModule = await import(pathToFileURL(bundledSpecFile).toString());
|
|
258
|
-
const definition = specModule.
|
|
305
|
+
const definition = specModule.spec ?? specModule.default ?? specModule;
|
|
259
306
|
if (!isSpecDefinition(definition)) throw new InvalidSpecEntrypointError(bundledSpecFile);
|
|
260
307
|
return definition;
|
|
261
308
|
}
|
|
@@ -274,8 +321,6 @@ async function loadSpec(config) {
|
|
|
274
321
|
function writeSpecDeclarationFile(specOutputDir) {
|
|
275
322
|
fs.writeFileSync(`${specOutputDir}/spec.d.ts`, [
|
|
276
323
|
"import type { SpecDefinition } from \"@rexeus/typeweaver-core\";",
|
|
277
|
-
"declare const _default: SpecDefinition;",
|
|
278
|
-
"export default _default;",
|
|
279
324
|
"export declare const spec: SpecDefinition;",
|
|
280
325
|
""
|
|
281
326
|
].join("\n"));
|
|
@@ -283,6 +328,16 @@ function writeSpecDeclarationFile(specOutputDir) {
|
|
|
283
328
|
//#endregion
|
|
284
329
|
//#region src/generators/Generator.ts
|
|
285
330
|
const moduleDir$1 = path.dirname(fileURLToPath(import.meta.url));
|
|
331
|
+
const assertSafeCleanTarget = (outputDir, currentWorkingDirectory) => {
|
|
332
|
+
const trimmedOutputDir = outputDir.trim();
|
|
333
|
+
if (trimmedOutputDir.length === 0) throw new Error("Refusing to clean an empty output directory path. Pass a dedicated generated output directory instead.");
|
|
334
|
+
const resolvedWorkingDirectory = path.resolve(currentWorkingDirectory);
|
|
335
|
+
const resolvedOutputDir = path.resolve(resolvedWorkingDirectory, trimmedOutputDir);
|
|
336
|
+
if (resolvedOutputDir === path.parse(resolvedOutputDir).root) throw new Error(`Refusing to clean '${outputDir}' because it resolves to the filesystem root.`);
|
|
337
|
+
if (resolvedOutputDir === resolvedWorkingDirectory) throw new Error(`Refusing to clean '${outputDir}' because it resolves to the current working directory.`);
|
|
338
|
+
const protectedWorkspaceRoot = findProtectedWorkspaceRoot(resolvedWorkingDirectory);
|
|
339
|
+
if (protectedWorkspaceRoot !== void 0 && resolvedOutputDir === protectedWorkspaceRoot) throw new Error(`Refusing to clean '${outputDir}' because it resolves to the inferred workspace root '${protectedWorkspaceRoot}'. Choose a dedicated output subdirectory instead.`);
|
|
340
|
+
};
|
|
286
341
|
/**
|
|
287
342
|
* Main generator for typeweaver
|
|
288
343
|
* Uses a plugin-based architecture for extensible code generation
|
|
@@ -305,10 +360,11 @@ var Generator = class {
|
|
|
305
360
|
/**
|
|
306
361
|
* Generate code using the plugin system
|
|
307
362
|
*/
|
|
308
|
-
async generate(specFile, outputDir, config) {
|
|
363
|
+
async generate(specFile, outputDir, config, currentWorkingDirectory = process.cwd()) {
|
|
309
364
|
console.info("Starting generation...");
|
|
310
|
-
this.initializeDirectories(specFile, outputDir);
|
|
365
|
+
this.initializeDirectories(specFile, outputDir, currentWorkingDirectory);
|
|
311
366
|
if (config?.clean ?? true) {
|
|
367
|
+
assertSafeCleanTarget(this.outputDir, currentWorkingDirectory);
|
|
312
368
|
console.info("Cleaning output directory...");
|
|
313
369
|
fs.rmSync(this.outputDir, {
|
|
314
370
|
recursive: true,
|
|
@@ -355,13 +411,25 @@ var Generator = class {
|
|
|
355
411
|
console.info("Generation complete!");
|
|
356
412
|
console.info(`Generated files: ${this.contextBuilder.getGeneratedFiles().length}`);
|
|
357
413
|
}
|
|
358
|
-
initializeDirectories(specFile, outputDir) {
|
|
359
|
-
this.inputFile = specFile;
|
|
360
|
-
this.outputDir = outputDir;
|
|
361
|
-
this.responsesOutputDir = path.join(outputDir, "responses");
|
|
414
|
+
initializeDirectories(specFile, outputDir, currentWorkingDirectory) {
|
|
415
|
+
this.inputFile = path.resolve(currentWorkingDirectory, specFile);
|
|
416
|
+
this.outputDir = path.resolve(currentWorkingDirectory, outputDir);
|
|
417
|
+
this.responsesOutputDir = path.join(this.outputDir, "responses");
|
|
362
418
|
this.specOutputDir = path.join(this.outputDir, "spec");
|
|
363
419
|
}
|
|
364
420
|
};
|
|
421
|
+
const findProtectedWorkspaceRoot = (startDirectory) => {
|
|
422
|
+
let currentDirectory = startDirectory;
|
|
423
|
+
while (true) {
|
|
424
|
+
if (hasWorkspaceMarker(currentDirectory)) return currentDirectory;
|
|
425
|
+
const parentDirectory = path.dirname(currentDirectory);
|
|
426
|
+
if (parentDirectory === currentDirectory) return;
|
|
427
|
+
currentDirectory = parentDirectory;
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
const hasWorkspaceMarker = (directory) => {
|
|
431
|
+
return ["pnpm-workspace.yaml", ".git"].some((marker) => fs.existsSync(path.join(directory, marker)));
|
|
432
|
+
};
|
|
365
433
|
//#endregion
|
|
366
434
|
//#region src/cli.ts
|
|
367
435
|
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -369,13 +437,12 @@ const packageJson = JSON.parse(fs.readFileSync(path.join(moduleDir, "../package.
|
|
|
369
437
|
const program = new Command();
|
|
370
438
|
const execDir = process.cwd();
|
|
371
439
|
program.name("@rexeus/typeweaver").description("Type-safe API framework with code generation for TypeScript").version(packageJson.version);
|
|
372
|
-
program.command("generate").description("Generate types, validators, and clients from an API spec").option("-i, --input <inputPath>", "path to spec entrypoint file").option("-o, --output <outputDir>", "output directory for generated files").option("-c, --config <configFile>", "path to configuration file").option("-p, --plugins <plugins>", "comma-separated list of plugins to use").option("--format", "format generated code with oxfmt (default: true)").option("--no-format", "disable code formatting").option("--clean", "clean output directory before generation (default: true)").option("--no-clean", "disable cleaning output directory").action(async (options) => {
|
|
440
|
+
program.command("generate").description("Generate types, validators, and clients from an API spec").option("-i, --input <inputPath>", "path to spec entrypoint file").option("-o, --output <outputDir>", "output directory for generated files").option("-c, --config <configFile>", "path to a .js, .mjs, or .cjs configuration file").option("-p, --plugins <plugins>", "comma-separated list of plugins to use").option("--format", "format generated code with oxfmt (default: true)").option("--no-format", "disable code formatting").option("--clean", "clean output directory before generation (default: true)").option("--no-clean", "disable cleaning output directory").action(async (options) => {
|
|
373
441
|
let config = {};
|
|
374
442
|
if (options.config) {
|
|
375
|
-
const configPath =
|
|
443
|
+
const configPath = getResolvedConfigPath(options.config, execDir);
|
|
376
444
|
try {
|
|
377
|
-
|
|
378
|
-
config = configModule.default ?? configModule;
|
|
445
|
+
config = await loadConfig(configPath);
|
|
379
446
|
console.info(`Loaded configuration from ${configPath}`);
|
|
380
447
|
} catch (error) {
|
|
381
448
|
console.error(`Failed to load configuration file: ${options.config}`);
|
|
@@ -397,7 +464,7 @@ program.command("generate").description("Generate types, validators, and clients
|
|
|
397
464
|
};
|
|
398
465
|
if (options.plugins) finalConfig.plugins = options.plugins.split(",").map((p) => p.trim());
|
|
399
466
|
else if (config.plugins) finalConfig.plugins = config.plugins;
|
|
400
|
-
return new Generator().generate(resolvedInputPath, resolvedOutputDir, finalConfig);
|
|
467
|
+
return new Generator().generate(resolvedInputPath, resolvedOutputDir, finalConfig, execDir);
|
|
401
468
|
});
|
|
402
469
|
program.command("init").description("Initialize a new typeweaver project (coming soon)").action(() => {
|
|
403
470
|
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/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 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 type { GeneratorContext } from \"@rexeus/typeweaver-gen\";\nimport ejs from \"ejs\";\n\nexport function generateIndexFiles(\n templateDir: string,\n context: GeneratorContext\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 stripped = file.replace(/\\.ts$/, \"\");\n const firstSlash = stripped.indexOf(\"/\");\n\n if (firstSlash === -1) {\n rootFiles.add(`./${stripped}`);\n continue;\n }\n\n const firstSegment = stripped.slice(0, firstSlash);\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}`);\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}`);\n }\n }\n }\n\n for (const [groupKey, entries] of groups) {\n if (existingBarrels.has(groupKey)) {\n continue;\n }\n\n const domainBarrelContent = ejs.render(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}`);\n }\n for (const barrelKey of existingBarrels) {\n rootIndexPaths.add(`./${barrelKey}`);\n }\n\n const rootContent = ejs.render(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 type {\n PluginRegistryApi,\n TypeweaverConfig,\n TypeweaverPlugin,\n} from \"@rexeus/typeweaver-gen\";\nimport TypesPlugin from \"@rexeus/typeweaver-types\";\nimport { PluginLoadingFailure } from \"./errors/PluginLoadingFailure\";\nimport type { PluginLoadError } from \"./errors/PluginLoadingFailure\";\n\nexport type PluginResolutionStrategy = \"npm\" | \"local\" | \"scoped\";\n\nexport type PluginLoadResult = {\n plugin: TypeweaverPlugin;\n source: string;\n};\n\ntype LoadResult<T, E> =\n | { success: true; value: T }\n | { success: false; error: E };\n\nexport async function loadPlugins(\n registry: PluginRegistryApi,\n requiredPlugins: [TypesPlugin],\n strategies: 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 let result: LoadResult<PluginLoadResult, PluginLoadError>;\n if (typeof plugin === \"string\") {\n result = await loadPlugin(plugin, strategies);\n } else {\n result = await loadPlugin(plugin[0], strategies);\n }\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);\n }\n\n reportSuccessfulLoads(successful);\n}\n\nasync function loadPlugin(\n pluginName: string,\n strategies: PluginResolutionStrategy[]\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 if (pluginPackage.default) {\n return {\n success: true,\n value: {\n plugin: new pluginPackage.default(),\n source: possiblePath,\n },\n };\n }\n attempts.push({\n path: possiblePath,\n error: \"No default export found\",\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 generatePluginPaths(\n pluginName: string,\n strategies: 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(pluginName);\n break;\n }\n }\n\n return paths;\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 { Rolldown } from \"tsdown\";\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, \"default\") ??',\n ' Reflect.get(specModule, \"spec\") ??',\n \" specModule;\",\n \"\",\n \"export default resolvedSpec;\",\n \"export const spec = resolvedSpec;\",\n \"\",\n ].join(\"\\n\")\n );\n\n try {\n await Rolldown.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 { pathToFileURL } from \"node:url\";\nimport type { SpecDefinition } from \"@rexeus/typeweaver-core\";\nimport { InvalidSpecEntrypointError } from \"./InvalidSpecEntrypointError\";\nimport { isSpecDefinition } from \"./specGuards\";\n\nexport async function importDefinition(\n bundledSpecFile: string\n): Promise<SpecDefinition> {\n const moduleUrl = pathToFileURL(bundledSpecFile).toString();\n const specModule = (await import(moduleUrl)) as {\n readonly default?: unknown;\n readonly spec?: unknown;\n };\n const definition = specModule.default ?? specModule.spec ?? 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\";\nimport { importDefinition } from \"./spec/specImporter\";\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 \"declare const _default: SpecDefinition;\",\n \"export default _default;\",\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\";\nimport { generateIndexFiles } from \"./indexFileGenerator\";\nimport { loadPlugins } from \"./pluginLoader\";\nimport { loadSpec } from \"./specLoader\";\nimport type { PluginResolutionStrategy } from \"./pluginLoader\";\n\nconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\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 ): Promise<void> {\n console.info(\"Starting generation...\");\n\n this.initializeDirectories(specFile, outputDir);\n\n if (config?.clean ?? true) {\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(specFile: string, outputDir: string): void {\n this.inputFile = specFile;\n this.outputDir = outputDir;\n this.responsesOutputDir = path.join(outputDir, \"responses\");\n this.specOutputDir = path.join(this.outputDir, \"spec\");\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport type { TypeweaverConfig } from \"@rexeus/typeweaver-gen\";\nimport { Command } from \"commander\";\nimport { Generator } from \"./generators/Generator\";\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(\"-c, --config <configFile>\", \"path to configuration file\")\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 = path.isAbsolute(options.config)\n ? options.config\n : path.join(execDir, options.config);\n\n try {\n const configUrl = pathToFileURL(configPath).toString();\n const configModule = await import(configUrl);\n config = configModule.default ?? configModule;\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 );\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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"}
|
|
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.join(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 function generateIndexFiles(\n templateDir: string,\n context: GeneratorContext\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 stripped = file.replace(/\\.ts$/, \"\");\n const firstSlash = stripped.indexOf(\"/\");\n\n if (firstSlash === -1) {\n rootFiles.add(`./${stripped}`);\n continue;\n }\n\n const firstSegment = stripped.slice(0, firstSlash);\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}`);\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}`);\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}`);\n }\n for (const barrelKey of existingBarrels) {\n rootIndexPaths.add(`./${barrelKey}`);\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 type {\n PluginRegistryApi,\n TypeweaverConfig,\n TypeweaverPlugin,\n} from \"@rexeus/typeweaver-gen\";\nimport { TypesPlugin } from \"@rexeus/typeweaver-types\";\nimport { PluginLoadingFailure } from \"./errors/PluginLoadingFailure\";\nimport type { PluginLoadError } from \"./errors/PluginLoadingFailure\";\n\nexport type PluginResolutionStrategy = \"npm\" | \"local\" | \"scoped\";\n\nexport type PluginLoadResult = {\n plugin: TypeweaverPlugin;\n source: string;\n};\n\ntype LoadResult<T, E> =\n | { success: true; value: T }\n | { success: false; error: E };\n\nexport async function loadPlugins(\n registry: PluginRegistryApi,\n requiredPlugins: [TypesPlugin],\n strategies: 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 let result: LoadResult<PluginLoadResult, PluginLoadError>;\n if (typeof plugin === \"string\") {\n result = await loadPlugin(plugin, strategies);\n } else {\n result = await loadPlugin(plugin[0], strategies);\n }\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);\n }\n\n reportSuccessfulLoads(successful);\n}\n\nasync function loadPlugin(\n pluginName: string,\n strategies: PluginResolutionStrategy[]\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 PluginClass = findPluginConstructor(pluginPackage);\n if (PluginClass) {\n return {\n success: true,\n value: {\n plugin: new PluginClass(),\n source: possiblePath,\n },\n };\n }\n attempts.push({\n path: possiblePath,\n error: \"No plugin class export found\",\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 findPluginConstructor(\n pluginModule: Record<string, unknown>\n): (new () => TypeweaverPlugin) | undefined {\n for (const [key, value] of Object.entries(pluginModule)) {\n if (key !== \"default\" && typeof value === \"function\") {\n return value as new () => TypeweaverPlugin;\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 return defaultExport as new () => TypeweaverPlugin;\n }\n\n return undefined;\n}\n\nfunction generatePluginPaths(\n pluginName: string,\n strategies: 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(pluginName);\n break;\n }\n }\n\n return paths;\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 { pathToFileURL } from \"node:url\";\nimport type { SpecDefinition } from \"@rexeus/typeweaver-core\";\nimport { InvalidSpecEntrypointError } from \"./InvalidSpecEntrypointError\";\nimport { isSpecDefinition } from \"./specGuards\";\n\nexport async function importDefinition(\n bundledSpecFile: string\n): Promise<SpecDefinition> {\n const moduleUrl = pathToFileURL(bundledSpecFile).toString();\n const specModule = (await import(moduleUrl)) 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\";\nimport { importDefinition } from \"./spec/specImporter\";\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\";\nimport { generateIndexFiles } from \"./indexFileGenerator\";\nimport { loadPlugins } from \"./pluginLoader\";\nimport { loadSpec } from \"./specLoader\";\nimport type { PluginResolutionStrategy } from \"./pluginLoader\";\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 resolvedOutputDir = path.resolve(\n resolvedWorkingDirectory,\n trimmedOutputDir\n );\n const filesystemRoot = path.parse(resolvedOutputDir).root;\n\n if (resolvedOutputDir === filesystemRoot) {\n throw new Error(\n `Refusing to clean '${outputDir}' because it resolves to the filesystem root.`\n );\n }\n\n if (resolvedOutputDir === resolvedWorkingDirectory) {\n throw new Error(\n `Refusing to clean '${outputDir}' because it resolves to the current working directory.`\n );\n }\n\n const protectedWorkspaceRoot = findProtectedWorkspaceRoot(\n resolvedWorkingDirectory\n );\n\n if (\n protectedWorkspaceRoot !== undefined &&\n resolvedOutputDir === protectedWorkspaceRoot\n ) {\n throw new Error(\n `Refusing to clean '${outputDir}' because it resolves to the inferred workspace root '${protectedWorkspaceRoot}'. 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","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\";\nimport { Generator } from \"./generators/Generator\";\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":"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"}
|
package/dist/entry.mjs
CHANGED
|
@@ -17,8 +17,7 @@ const getRuntimeDisplayName = (runtime) => {
|
|
|
17
17
|
const main = async () => {
|
|
18
18
|
const runtime = detectRuntime();
|
|
19
19
|
console.info(`Running on ${getRuntimeDisplayName(runtime)}`);
|
|
20
|
-
|
|
21
|
-
await import("./cli-CF2Dbqut.mjs");
|
|
20
|
+
await import("./cli-DTzc-YtR.mjs");
|
|
22
21
|
};
|
|
23
22
|
main().catch((error) => {
|
|
24
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.
|
|
3
|
+
"version": "0.10.1",
|
|
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,
|
|
@@ -52,17 +52,15 @@
|
|
|
52
52
|
"homepage": "https://github.com/rexeus/typeweaver#readme",
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"commander": "^14.0.3",
|
|
55
|
-
"ejs": "^5.0.1",
|
|
56
55
|
"oxc-transform": "^0.121.0",
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"@rexeus/typeweaver-clients": "^0.
|
|
60
|
-
"@rexeus/typeweaver-
|
|
61
|
-
"@rexeus/typeweaver-
|
|
62
|
-
"@rexeus/typeweaver-
|
|
63
|
-
"@rexeus/typeweaver-
|
|
64
|
-
"@rexeus/typeweaver-server": "^0.
|
|
65
|
-
"@rexeus/typeweaver-types": "^0.9.2"
|
|
56
|
+
"rolldown": "^1.0.0-rc.13",
|
|
57
|
+
"@rexeus/typeweaver-aws-cdk": "^0.10.1",
|
|
58
|
+
"@rexeus/typeweaver-clients": "^0.10.1",
|
|
59
|
+
"@rexeus/typeweaver-hono": "^0.10.1",
|
|
60
|
+
"@rexeus/typeweaver-gen": "^0.10.1",
|
|
61
|
+
"@rexeus/typeweaver-types": "^0.10.1",
|
|
62
|
+
"@rexeus/typeweaver-core": "^0.10.1",
|
|
63
|
+
"@rexeus/typeweaver-server": "^0.10.1"
|
|
66
64
|
},
|
|
67
65
|
"peerDependencies": {
|
|
68
66
|
"oxfmt": ">=0.30.0"
|
|
@@ -73,8 +71,8 @@
|
|
|
73
71
|
}
|
|
74
72
|
},
|
|
75
73
|
"devDependencies": {
|
|
76
|
-
"case": "^1.6.3",
|
|
77
74
|
"hono": "^4.12.9",
|
|
75
|
+
"tsx": "^4.21.0",
|
|
78
76
|
"zod": "^4.3.6"
|
|
79
77
|
},
|
|
80
78
|
"scripts": {
|
|
@@ -83,7 +81,7 @@
|
|
|
83
81
|
"cli:bun": "bun run src/entry.ts",
|
|
84
82
|
"typecheck": "tsc --noEmit",
|
|
85
83
|
"format": "oxfmt",
|
|
86
|
-
"build": "tsdown
|
|
84
|
+
"build": "tsdown",
|
|
87
85
|
"preversion": "npm run build",
|
|
88
86
|
"test:bundle": "pnpm run build && node dist/entry.mjs generate --output test/outputs/bundle --input ../test-utils/src/test-project/spec/index.ts --plugins clients,aws-cdk,hono",
|
|
89
87
|
"test:bundle:deno": "pnpm run build && deno run -A --sloppy-imports dist/entry.mjs generate --output test/outputs/bundle-deno --input ../test-utils/src/test-project/spec/index.ts --plugins clients,aws-cdk,hono",
|