@rexeus/typeweaver 0.6.4 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,9 +5,147 @@ import { fileURLToPath, pathToFileURL } from "node:url";
5
5
  import { Command } from "commander";
6
6
  import { PluginContextBuilder, PluginRegistry } from "@rexeus/typeweaver-gen";
7
7
  import TypesPlugin from "@rexeus/typeweaver-types";
8
+ import { transformSync } from "oxc-transform";
8
9
  import { render } from "ejs";
9
10
  import { HttpMethod, HttpOperationDefinition, HttpResponseDefinition, HttpStatusCode, HttpStatusCodeNameMap } from "@rexeus/typeweaver-core";
10
11
 
12
+ //#region src/generators/errors/DefinitionCompilationError.ts
13
+ var DefinitionCompilationError = class extends Error {
14
+ constructor(filePath, details) {
15
+ super(`Failed to compile definition at \`${filePath}\`. ${details}`);
16
+ this.filePath = filePath;
17
+ this.details = details;
18
+ }
19
+ };
20
+
21
+ //#endregion
22
+ //#region src/generators/DefinitionCompiler.ts
23
+ /**
24
+ * Compiles TypeScript definition files to JavaScript + declaration stubs.
25
+ *
26
+ * Definition files contain Zod schemas that cause tsc to exhaust memory
27
+ * when type-checking due to Zod v4's deeply recursive type inference.
28
+ * By pre-compiling definitions to .js + .d.ts, tsc only sees lightweight
29
+ * type stubs (everything typed as `any`) while runtime behavior is preserved.
30
+ */
31
+ var DefinitionCompiler = class DefinitionCompiler {
32
+ static GENERATED_HEADER = [
33
+ "/* eslint-disable */",
34
+ "/**",
35
+ " * This file was automatically generated by typeweaver.",
36
+ " * DO NOT EDIT. Instead, modify the source definition file and generate again.",
37
+ " *",
38
+ " * @generated by @rexeus/typeweaver",
39
+ " */"
40
+ ].join("\n");
41
+ /**
42
+ * Compiles all .ts definition files in-place to .js + .d.ts stubs.
43
+ * The original .ts files are removed after compilation.
44
+ */
45
+ compileInPlace(definitionDir) {
46
+ const errors = [];
47
+ this.processDirectory(definitionDir, errors);
48
+ if (errors.length > 0) {
49
+ const summary = errors.map((e) => ` - ${e.filePath}: ${e.details}`).join("\n");
50
+ throw new DefinitionCompilationError(definitionDir, `${errors.length} file(s) failed to compile:\n${summary}`);
51
+ }
52
+ }
53
+ processDirectory(dir, errors) {
54
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
55
+ for (const entry of entries) {
56
+ const fullPath = path.join(dir, entry.name);
57
+ if (entry.isDirectory()) {
58
+ this.processDirectory(fullPath, errors);
59
+ continue;
60
+ }
61
+ if (entry.isFile() && entry.name.endsWith(".ts") && !entry.name.endsWith(".d.ts")) try {
62
+ this.compileFile(fullPath, dir, entry.name);
63
+ } catch (error) {
64
+ errors.push(error instanceof DefinitionCompilationError ? error : new DefinitionCompilationError(fullPath, String(error)));
65
+ }
66
+ }
67
+ }
68
+ compileFile(srcPath, dir, fileName) {
69
+ try {
70
+ const source = fs.readFileSync(srcPath, "utf-8");
71
+ const baseName = fileName.replace(/\.ts$/, "");
72
+ const jsCode = this.transpileToJs(fileName, source);
73
+ const dtsCode = this.generateDtsStub(source);
74
+ fs.writeFileSync(path.join(dir, `${baseName}.js`), jsCode);
75
+ fs.writeFileSync(path.join(dir, `${baseName}.d.ts`), dtsCode);
76
+ fs.unlinkSync(srcPath);
77
+ } catch (error) {
78
+ throw new DefinitionCompilationError(srcPath, error instanceof DefinitionCompilationError ? error.details : error instanceof Error ? error.message : String(error));
79
+ }
80
+ }
81
+ transpileToJs(fileName, source) {
82
+ const result = transformSync(fileName, source, {
83
+ lang: "ts",
84
+ sourceType: "module"
85
+ });
86
+ const errors = result.errors.filter((e) => e.severity === "Error");
87
+ if (errors.length > 0) throw new DefinitionCompilationError(fileName, errors.map((e) => e.message).join("; "));
88
+ return result.code;
89
+ }
90
+ /**
91
+ * Generates a minimal .d.ts stub from TypeScript source.
92
+ * All value exports are typed as `any` to avoid pulling in Zod's type system.
93
+ * Re-exports are preserved so barrel files chain correctly.
94
+ */
95
+ generateDtsStub(source) {
96
+ if (source.startsWith(DefinitionCompiler.GENERATED_HEADER)) return source;
97
+ const lines = [DefinitionCompiler.GENERATED_HEADER];
98
+ let hasDefaultExport = false;
99
+ let pastLeadingComments = false;
100
+ let exportBlock = null;
101
+ for (const line of source.split("\n")) {
102
+ const trimmed = line.trim();
103
+ if (exportBlock !== null) {
104
+ exportBlock += " " + trimmed;
105
+ if (trimmed.includes("}")) {
106
+ lines.push(exportBlock);
107
+ exportBlock = null;
108
+ }
109
+ continue;
110
+ }
111
+ if (!pastLeadingComments) {
112
+ if (trimmed.startsWith("/*") || trimmed.startsWith("//") || trimmed.startsWith("*") || trimmed === "") {
113
+ if (trimmed !== "" && !trimmed.includes("@generated")) lines.push(trimmed);
114
+ continue;
115
+ }
116
+ pastLeadingComments = true;
117
+ }
118
+ if (trimmed.startsWith("export {") || trimmed.startsWith("export *")) {
119
+ if (trimmed.startsWith("export {") && !trimmed.includes("}")) {
120
+ exportBlock = trimmed;
121
+ continue;
122
+ }
123
+ lines.push(trimmed);
124
+ continue;
125
+ }
126
+ if (trimmed.startsWith("export default") && !hasDefaultExport) {
127
+ lines.push("declare const _default: any;");
128
+ lines.push("export default _default;");
129
+ hasDefaultExport = true;
130
+ continue;
131
+ }
132
+ const constMatch = trimmed.match(/^export\s+(?:const|let|var)\s+(\w+)/);
133
+ if (constMatch) {
134
+ lines.push(`export declare const ${constMatch[1]}: any;`);
135
+ continue;
136
+ }
137
+ const funcMatch = trimmed.match(/^export\s+(?:async\s+)?function\s*\*?\s+(\w+)/);
138
+ if (funcMatch) {
139
+ lines.push(`export declare function ${funcMatch[1]}(...args: any[]): any;`);
140
+ continue;
141
+ }
142
+ if (trimmed.startsWith("export") && !trimmed.startsWith("export {") && !trimmed.startsWith("export *") && !trimmed.startsWith("export default") && !trimmed.startsWith("export type")) console.warn(`[DefinitionCompiler] Unrecognized export pattern in definition stub: ${trimmed}`);
143
+ }
144
+ return lines.join("\n") + "\n";
145
+ }
146
+ };
147
+
148
+ //#endregion
11
149
  //#region src/generators/Formatter.ts
12
150
  var Formatter = class {
13
151
  constructor(outputDir) {
@@ -46,10 +184,48 @@ var IndexFileGenerator = class {
46
184
  generate(context) {
47
185
  const templateFilePath = path.join(this.templateDir, "Index.ejs");
48
186
  const template = fs.readFileSync(templateFilePath, "utf8");
49
- const indexPaths = /* @__PURE__ */ new Set();
50
- for (const generatedFile of context.getGeneratedFiles()) indexPaths.add(`./${generatedFile.replace(/\.ts$/, "")}`);
51
- const content = render(template, { indexPaths: Array.from(indexPaths).sort() });
52
- fs.writeFileSync(path.join(context.outputDir, "index.ts"), content);
187
+ const generatedFiles = context.getGeneratedFiles();
188
+ const groups = /* @__PURE__ */ new Map();
189
+ const rootFiles = /* @__PURE__ */ new Set();
190
+ const existingBarrels = /* @__PURE__ */ new Set();
191
+ for (const file of generatedFiles) {
192
+ const stripped = file.replace(/\.ts$/, "");
193
+ const firstSlash = stripped.indexOf("/");
194
+ if (firstSlash === -1) {
195
+ rootFiles.add(`./${stripped}`);
196
+ continue;
197
+ }
198
+ const firstSegment = stripped.slice(0, firstSlash);
199
+ if (firstSegment === "lib") {
200
+ const secondSlash = stripped.indexOf("/", firstSlash + 1);
201
+ const groupKey = secondSlash === -1 ? stripped : stripped.slice(0, secondSlash);
202
+ const entryName = stripped.slice(groupKey.length + 1);
203
+ if (entryName === "index") existingBarrels.add(groupKey);
204
+ else {
205
+ if (!groups.has(groupKey)) groups.set(groupKey, /* @__PURE__ */ new Set());
206
+ groups.get(groupKey).add(`./${entryName}`);
207
+ }
208
+ } else {
209
+ const entryName = stripped.slice(firstSlash + 1);
210
+ if (entryName === "index") existingBarrels.add(firstSegment);
211
+ else {
212
+ if (!groups.has(firstSegment)) groups.set(firstSegment, /* @__PURE__ */ new Set());
213
+ groups.get(firstSegment).add(`./${entryName}`);
214
+ }
215
+ }
216
+ }
217
+ for (const [groupKey, entries] of groups) {
218
+ if (existingBarrels.has(groupKey)) continue;
219
+ const domainBarrelContent = render(template, { indexPaths: Array.from(entries).sort() });
220
+ const domainIndexPath = path.join(context.outputDir, groupKey, "index.ts");
221
+ fs.mkdirSync(path.dirname(domainIndexPath), { recursive: true });
222
+ fs.writeFileSync(domainIndexPath, domainBarrelContent);
223
+ }
224
+ const rootIndexPaths = new Set(rootFiles);
225
+ for (const groupKey of groups.keys()) rootIndexPaths.add(`./${groupKey}`);
226
+ for (const barrelKey of existingBarrels) rootIndexPaths.add(`./${barrelKey}`);
227
+ const rootContent = render(template, { indexPaths: Array.from(rootIndexPaths).sort() });
228
+ fs.writeFileSync(path.join(context.outputDir, "index.ts"), rootContent);
53
229
  }
54
230
  };
55
231
 
@@ -4116,6 +4292,7 @@ var Generator = class {
4116
4292
  contextBuilder;
4117
4293
  pluginLoader;
4118
4294
  indexFileGenerator;
4295
+ definitionCompiler;
4119
4296
  resourceReader = null;
4120
4297
  formatter = null;
4121
4298
  inputDir = "";
@@ -4129,6 +4306,7 @@ var Generator = class {
4129
4306
  this.contextBuilder = contextBuilder ?? new PluginContextBuilder();
4130
4307
  this.pluginLoader = pluginLoader ?? new PluginLoader(this.registry, requiredPlugins);
4131
4308
  this.indexFileGenerator = indexFileGenerator ?? new IndexFileGenerator(this.templateDir);
4309
+ this.definitionCompiler = new DefinitionCompiler();
4132
4310
  }
4133
4311
  /**
4134
4312
  * Generate code using the plugin system
@@ -4187,6 +4365,8 @@ var Generator = class {
4187
4365
  this.indexFileGenerator.generate(generatorContext);
4188
4366
  console.info("Finalizing plugins...");
4189
4367
  for (const registration of this.registry.getAll()) if (registration.plugin.finalize) await registration.plugin.finalize(pluginContext);
4368
+ console.info("Compiling definitions...");
4369
+ this.definitionCompiler.compileInPlace(this.sourceDir);
4190
4370
  if (config?.format ?? true) await this.formatter.formatCode();
4191
4371
  console.info("Generation complete!");
4192
4372
  console.info(`Generated files: ${this.contextBuilder.getGeneratedFiles().length}`);
package/dist/cli.cjs CHANGED
@@ -34,9 +34,147 @@ let commander = require("commander");
34
34
  let _rexeus_typeweaver_gen = require("@rexeus/typeweaver-gen");
35
35
  let _rexeus_typeweaver_types = require("@rexeus/typeweaver-types");
36
36
  _rexeus_typeweaver_types = __toESM(_rexeus_typeweaver_types);
37
+ let oxc_transform = require("oxc-transform");
37
38
  let ejs = require("ejs");
38
39
  let _rexeus_typeweaver_core = require("@rexeus/typeweaver-core");
39
40
 
41
+ //#region src/generators/errors/DefinitionCompilationError.ts
42
+ var DefinitionCompilationError = class extends Error {
43
+ constructor(filePath, details) {
44
+ super(`Failed to compile definition at \`${filePath}\`. ${details}`);
45
+ this.filePath = filePath;
46
+ this.details = details;
47
+ }
48
+ };
49
+
50
+ //#endregion
51
+ //#region src/generators/DefinitionCompiler.ts
52
+ /**
53
+ * Compiles TypeScript definition files to JavaScript + declaration stubs.
54
+ *
55
+ * Definition files contain Zod schemas that cause tsc to exhaust memory
56
+ * when type-checking due to Zod v4's deeply recursive type inference.
57
+ * By pre-compiling definitions to .js + .d.ts, tsc only sees lightweight
58
+ * type stubs (everything typed as `any`) while runtime behavior is preserved.
59
+ */
60
+ var DefinitionCompiler = class DefinitionCompiler {
61
+ static GENERATED_HEADER = [
62
+ "/* eslint-disable */",
63
+ "/**",
64
+ " * This file was automatically generated by typeweaver.",
65
+ " * DO NOT EDIT. Instead, modify the source definition file and generate again.",
66
+ " *",
67
+ " * @generated by @rexeus/typeweaver",
68
+ " */"
69
+ ].join("\n");
70
+ /**
71
+ * Compiles all .ts definition files in-place to .js + .d.ts stubs.
72
+ * The original .ts files are removed after compilation.
73
+ */
74
+ compileInPlace(definitionDir) {
75
+ const errors = [];
76
+ this.processDirectory(definitionDir, errors);
77
+ if (errors.length > 0) {
78
+ const summary = errors.map((e) => ` - ${e.filePath}: ${e.details}`).join("\n");
79
+ throw new DefinitionCompilationError(definitionDir, `${errors.length} file(s) failed to compile:\n${summary}`);
80
+ }
81
+ }
82
+ processDirectory(dir, errors) {
83
+ const entries = node_fs.default.readdirSync(dir, { withFileTypes: true });
84
+ for (const entry of entries) {
85
+ const fullPath = node_path.default.join(dir, entry.name);
86
+ if (entry.isDirectory()) {
87
+ this.processDirectory(fullPath, errors);
88
+ continue;
89
+ }
90
+ if (entry.isFile() && entry.name.endsWith(".ts") && !entry.name.endsWith(".d.ts")) try {
91
+ this.compileFile(fullPath, dir, entry.name);
92
+ } catch (error) {
93
+ errors.push(error instanceof DefinitionCompilationError ? error : new DefinitionCompilationError(fullPath, String(error)));
94
+ }
95
+ }
96
+ }
97
+ compileFile(srcPath, dir, fileName) {
98
+ try {
99
+ const source = node_fs.default.readFileSync(srcPath, "utf-8");
100
+ const baseName = fileName.replace(/\.ts$/, "");
101
+ const jsCode = this.transpileToJs(fileName, source);
102
+ const dtsCode = this.generateDtsStub(source);
103
+ node_fs.default.writeFileSync(node_path.default.join(dir, `${baseName}.js`), jsCode);
104
+ node_fs.default.writeFileSync(node_path.default.join(dir, `${baseName}.d.ts`), dtsCode);
105
+ node_fs.default.unlinkSync(srcPath);
106
+ } catch (error) {
107
+ throw new DefinitionCompilationError(srcPath, error instanceof DefinitionCompilationError ? error.details : error instanceof Error ? error.message : String(error));
108
+ }
109
+ }
110
+ transpileToJs(fileName, source) {
111
+ const result = (0, oxc_transform.transformSync)(fileName, source, {
112
+ lang: "ts",
113
+ sourceType: "module"
114
+ });
115
+ const errors = result.errors.filter((e) => e.severity === "Error");
116
+ if (errors.length > 0) throw new DefinitionCompilationError(fileName, errors.map((e) => e.message).join("; "));
117
+ return result.code;
118
+ }
119
+ /**
120
+ * Generates a minimal .d.ts stub from TypeScript source.
121
+ * All value exports are typed as `any` to avoid pulling in Zod's type system.
122
+ * Re-exports are preserved so barrel files chain correctly.
123
+ */
124
+ generateDtsStub(source) {
125
+ if (source.startsWith(DefinitionCompiler.GENERATED_HEADER)) return source;
126
+ const lines = [DefinitionCompiler.GENERATED_HEADER];
127
+ let hasDefaultExport = false;
128
+ let pastLeadingComments = false;
129
+ let exportBlock = null;
130
+ for (const line of source.split("\n")) {
131
+ const trimmed = line.trim();
132
+ if (exportBlock !== null) {
133
+ exportBlock += " " + trimmed;
134
+ if (trimmed.includes("}")) {
135
+ lines.push(exportBlock);
136
+ exportBlock = null;
137
+ }
138
+ continue;
139
+ }
140
+ if (!pastLeadingComments) {
141
+ if (trimmed.startsWith("/*") || trimmed.startsWith("//") || trimmed.startsWith("*") || trimmed === "") {
142
+ if (trimmed !== "" && !trimmed.includes("@generated")) lines.push(trimmed);
143
+ continue;
144
+ }
145
+ pastLeadingComments = true;
146
+ }
147
+ if (trimmed.startsWith("export {") || trimmed.startsWith("export *")) {
148
+ if (trimmed.startsWith("export {") && !trimmed.includes("}")) {
149
+ exportBlock = trimmed;
150
+ continue;
151
+ }
152
+ lines.push(trimmed);
153
+ continue;
154
+ }
155
+ if (trimmed.startsWith("export default") && !hasDefaultExport) {
156
+ lines.push("declare const _default: any;");
157
+ lines.push("export default _default;");
158
+ hasDefaultExport = true;
159
+ continue;
160
+ }
161
+ const constMatch = trimmed.match(/^export\s+(?:const|let|var)\s+(\w+)/);
162
+ if (constMatch) {
163
+ lines.push(`export declare const ${constMatch[1]}: any;`);
164
+ continue;
165
+ }
166
+ const funcMatch = trimmed.match(/^export\s+(?:async\s+)?function\s*\*?\s+(\w+)/);
167
+ if (funcMatch) {
168
+ lines.push(`export declare function ${funcMatch[1]}(...args: any[]): any;`);
169
+ continue;
170
+ }
171
+ if (trimmed.startsWith("export") && !trimmed.startsWith("export {") && !trimmed.startsWith("export *") && !trimmed.startsWith("export default") && !trimmed.startsWith("export type")) console.warn(`[DefinitionCompiler] Unrecognized export pattern in definition stub: ${trimmed}`);
172
+ }
173
+ return lines.join("\n") + "\n";
174
+ }
175
+ };
176
+
177
+ //#endregion
40
178
  //#region src/generators/Formatter.ts
41
179
  var Formatter = class {
42
180
  constructor(outputDir) {
@@ -75,10 +213,48 @@ var IndexFileGenerator = class {
75
213
  generate(context) {
76
214
  const templateFilePath = node_path.default.join(this.templateDir, "Index.ejs");
77
215
  const template = node_fs.default.readFileSync(templateFilePath, "utf8");
78
- const indexPaths = /* @__PURE__ */ new Set();
79
- for (const generatedFile of context.getGeneratedFiles()) indexPaths.add(`./${generatedFile.replace(/\.ts$/, "")}`);
80
- const content = (0, ejs.render)(template, { indexPaths: Array.from(indexPaths).sort() });
81
- node_fs.default.writeFileSync(node_path.default.join(context.outputDir, "index.ts"), content);
216
+ const generatedFiles = context.getGeneratedFiles();
217
+ const groups = /* @__PURE__ */ new Map();
218
+ const rootFiles = /* @__PURE__ */ new Set();
219
+ const existingBarrels = /* @__PURE__ */ new Set();
220
+ for (const file of generatedFiles) {
221
+ const stripped = file.replace(/\.ts$/, "");
222
+ const firstSlash = stripped.indexOf("/");
223
+ if (firstSlash === -1) {
224
+ rootFiles.add(`./${stripped}`);
225
+ continue;
226
+ }
227
+ const firstSegment = stripped.slice(0, firstSlash);
228
+ if (firstSegment === "lib") {
229
+ const secondSlash = stripped.indexOf("/", firstSlash + 1);
230
+ const groupKey = secondSlash === -1 ? stripped : stripped.slice(0, secondSlash);
231
+ const entryName = stripped.slice(groupKey.length + 1);
232
+ if (entryName === "index") existingBarrels.add(groupKey);
233
+ else {
234
+ if (!groups.has(groupKey)) groups.set(groupKey, /* @__PURE__ */ new Set());
235
+ groups.get(groupKey).add(`./${entryName}`);
236
+ }
237
+ } else {
238
+ const entryName = stripped.slice(firstSlash + 1);
239
+ if (entryName === "index") existingBarrels.add(firstSegment);
240
+ else {
241
+ if (!groups.has(firstSegment)) groups.set(firstSegment, /* @__PURE__ */ new Set());
242
+ groups.get(firstSegment).add(`./${entryName}`);
243
+ }
244
+ }
245
+ }
246
+ for (const [groupKey, entries] of groups) {
247
+ if (existingBarrels.has(groupKey)) continue;
248
+ const domainBarrelContent = (0, ejs.render)(template, { indexPaths: Array.from(entries).sort() });
249
+ const domainIndexPath = node_path.default.join(context.outputDir, groupKey, "index.ts");
250
+ node_fs.default.mkdirSync(node_path.default.dirname(domainIndexPath), { recursive: true });
251
+ node_fs.default.writeFileSync(domainIndexPath, domainBarrelContent);
252
+ }
253
+ const rootIndexPaths = new Set(rootFiles);
254
+ for (const groupKey of groups.keys()) rootIndexPaths.add(`./${groupKey}`);
255
+ for (const barrelKey of existingBarrels) rootIndexPaths.add(`./${barrelKey}`);
256
+ const rootContent = (0, ejs.render)(template, { indexPaths: Array.from(rootIndexPaths).sort() });
257
+ node_fs.default.writeFileSync(node_path.default.join(context.outputDir, "index.ts"), rootContent);
82
258
  }
83
259
  };
84
260
 
@@ -4145,6 +4321,7 @@ var Generator = class {
4145
4321
  contextBuilder;
4146
4322
  pluginLoader;
4147
4323
  indexFileGenerator;
4324
+ definitionCompiler;
4148
4325
  resourceReader = null;
4149
4326
  formatter = null;
4150
4327
  inputDir = "";
@@ -4158,6 +4335,7 @@ var Generator = class {
4158
4335
  this.contextBuilder = contextBuilder ?? new _rexeus_typeweaver_gen.PluginContextBuilder();
4159
4336
  this.pluginLoader = pluginLoader ?? new PluginLoader(this.registry, requiredPlugins);
4160
4337
  this.indexFileGenerator = indexFileGenerator ?? new IndexFileGenerator(this.templateDir);
4338
+ this.definitionCompiler = new DefinitionCompiler();
4161
4339
  }
4162
4340
  /**
4163
4341
  * Generate code using the plugin system
@@ -4216,6 +4394,8 @@ var Generator = class {
4216
4394
  this.indexFileGenerator.generate(generatorContext);
4217
4395
  console.info("Finalizing plugins...");
4218
4396
  for (const registration of this.registry.getAll()) if (registration.plugin.finalize) await registration.plugin.finalize(pluginContext);
4397
+ console.info("Compiling definitions...");
4398
+ this.definitionCompiler.compileInPlace(this.sourceDir);
4219
4399
  if (config?.format ?? true) await this.formatter.formatCode();
4220
4400
  console.info("Generation complete!");
4221
4401
  console.info(`Generated files: ${this.contextBuilder.getGeneratedFiles().length}`);
package/dist/cli.mjs CHANGED
@@ -4,9 +4,147 @@ import { fileURLToPath, pathToFileURL } from "node:url";
4
4
  import { Command } from "commander";
5
5
  import { PluginContextBuilder, PluginRegistry } from "@rexeus/typeweaver-gen";
6
6
  import TypesPlugin from "@rexeus/typeweaver-types";
7
+ import { transformSync } from "oxc-transform";
7
8
  import { render } from "ejs";
8
9
  import { HttpMethod, HttpOperationDefinition, HttpResponseDefinition, HttpStatusCode, HttpStatusCodeNameMap } from "@rexeus/typeweaver-core";
9
10
 
11
+ //#region src/generators/errors/DefinitionCompilationError.ts
12
+ var DefinitionCompilationError = class extends Error {
13
+ constructor(filePath, details) {
14
+ super(`Failed to compile definition at \`${filePath}\`. ${details}`);
15
+ this.filePath = filePath;
16
+ this.details = details;
17
+ }
18
+ };
19
+
20
+ //#endregion
21
+ //#region src/generators/DefinitionCompiler.ts
22
+ /**
23
+ * Compiles TypeScript definition files to JavaScript + declaration stubs.
24
+ *
25
+ * Definition files contain Zod schemas that cause tsc to exhaust memory
26
+ * when type-checking due to Zod v4's deeply recursive type inference.
27
+ * By pre-compiling definitions to .js + .d.ts, tsc only sees lightweight
28
+ * type stubs (everything typed as `any`) while runtime behavior is preserved.
29
+ */
30
+ var DefinitionCompiler = class DefinitionCompiler {
31
+ static GENERATED_HEADER = [
32
+ "/* eslint-disable */",
33
+ "/**",
34
+ " * This file was automatically generated by typeweaver.",
35
+ " * DO NOT EDIT. Instead, modify the source definition file and generate again.",
36
+ " *",
37
+ " * @generated by @rexeus/typeweaver",
38
+ " */"
39
+ ].join("\n");
40
+ /**
41
+ * Compiles all .ts definition files in-place to .js + .d.ts stubs.
42
+ * The original .ts files are removed after compilation.
43
+ */
44
+ compileInPlace(definitionDir) {
45
+ const errors = [];
46
+ this.processDirectory(definitionDir, errors);
47
+ if (errors.length > 0) {
48
+ const summary = errors.map((e) => ` - ${e.filePath}: ${e.details}`).join("\n");
49
+ throw new DefinitionCompilationError(definitionDir, `${errors.length} file(s) failed to compile:\n${summary}`);
50
+ }
51
+ }
52
+ processDirectory(dir, errors) {
53
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
54
+ for (const entry of entries) {
55
+ const fullPath = path.join(dir, entry.name);
56
+ if (entry.isDirectory()) {
57
+ this.processDirectory(fullPath, errors);
58
+ continue;
59
+ }
60
+ if (entry.isFile() && entry.name.endsWith(".ts") && !entry.name.endsWith(".d.ts")) try {
61
+ this.compileFile(fullPath, dir, entry.name);
62
+ } catch (error) {
63
+ errors.push(error instanceof DefinitionCompilationError ? error : new DefinitionCompilationError(fullPath, String(error)));
64
+ }
65
+ }
66
+ }
67
+ compileFile(srcPath, dir, fileName) {
68
+ try {
69
+ const source = fs.readFileSync(srcPath, "utf-8");
70
+ const baseName = fileName.replace(/\.ts$/, "");
71
+ const jsCode = this.transpileToJs(fileName, source);
72
+ const dtsCode = this.generateDtsStub(source);
73
+ fs.writeFileSync(path.join(dir, `${baseName}.js`), jsCode);
74
+ fs.writeFileSync(path.join(dir, `${baseName}.d.ts`), dtsCode);
75
+ fs.unlinkSync(srcPath);
76
+ } catch (error) {
77
+ throw new DefinitionCompilationError(srcPath, error instanceof DefinitionCompilationError ? error.details : error instanceof Error ? error.message : String(error));
78
+ }
79
+ }
80
+ transpileToJs(fileName, source) {
81
+ const result = transformSync(fileName, source, {
82
+ lang: "ts",
83
+ sourceType: "module"
84
+ });
85
+ const errors = result.errors.filter((e) => e.severity === "Error");
86
+ if (errors.length > 0) throw new DefinitionCompilationError(fileName, errors.map((e) => e.message).join("; "));
87
+ return result.code;
88
+ }
89
+ /**
90
+ * Generates a minimal .d.ts stub from TypeScript source.
91
+ * All value exports are typed as `any` to avoid pulling in Zod's type system.
92
+ * Re-exports are preserved so barrel files chain correctly.
93
+ */
94
+ generateDtsStub(source) {
95
+ if (source.startsWith(DefinitionCompiler.GENERATED_HEADER)) return source;
96
+ const lines = [DefinitionCompiler.GENERATED_HEADER];
97
+ let hasDefaultExport = false;
98
+ let pastLeadingComments = false;
99
+ let exportBlock = null;
100
+ for (const line of source.split("\n")) {
101
+ const trimmed = line.trim();
102
+ if (exportBlock !== null) {
103
+ exportBlock += " " + trimmed;
104
+ if (trimmed.includes("}")) {
105
+ lines.push(exportBlock);
106
+ exportBlock = null;
107
+ }
108
+ continue;
109
+ }
110
+ if (!pastLeadingComments) {
111
+ if (trimmed.startsWith("/*") || trimmed.startsWith("//") || trimmed.startsWith("*") || trimmed === "") {
112
+ if (trimmed !== "" && !trimmed.includes("@generated")) lines.push(trimmed);
113
+ continue;
114
+ }
115
+ pastLeadingComments = true;
116
+ }
117
+ if (trimmed.startsWith("export {") || trimmed.startsWith("export *")) {
118
+ if (trimmed.startsWith("export {") && !trimmed.includes("}")) {
119
+ exportBlock = trimmed;
120
+ continue;
121
+ }
122
+ lines.push(trimmed);
123
+ continue;
124
+ }
125
+ if (trimmed.startsWith("export default") && !hasDefaultExport) {
126
+ lines.push("declare const _default: any;");
127
+ lines.push("export default _default;");
128
+ hasDefaultExport = true;
129
+ continue;
130
+ }
131
+ const constMatch = trimmed.match(/^export\s+(?:const|let|var)\s+(\w+)/);
132
+ if (constMatch) {
133
+ lines.push(`export declare const ${constMatch[1]}: any;`);
134
+ continue;
135
+ }
136
+ const funcMatch = trimmed.match(/^export\s+(?:async\s+)?function\s*\*?\s+(\w+)/);
137
+ if (funcMatch) {
138
+ lines.push(`export declare function ${funcMatch[1]}(...args: any[]): any;`);
139
+ continue;
140
+ }
141
+ if (trimmed.startsWith("export") && !trimmed.startsWith("export {") && !trimmed.startsWith("export *") && !trimmed.startsWith("export default") && !trimmed.startsWith("export type")) console.warn(`[DefinitionCompiler] Unrecognized export pattern in definition stub: ${trimmed}`);
142
+ }
143
+ return lines.join("\n") + "\n";
144
+ }
145
+ };
146
+
147
+ //#endregion
10
148
  //#region src/generators/Formatter.ts
11
149
  var Formatter = class {
12
150
  constructor(outputDir) {
@@ -45,10 +183,48 @@ var IndexFileGenerator = class {
45
183
  generate(context) {
46
184
  const templateFilePath = path.join(this.templateDir, "Index.ejs");
47
185
  const template = fs.readFileSync(templateFilePath, "utf8");
48
- const indexPaths = /* @__PURE__ */ new Set();
49
- for (const generatedFile of context.getGeneratedFiles()) indexPaths.add(`./${generatedFile.replace(/\.ts$/, "")}`);
50
- const content = render(template, { indexPaths: Array.from(indexPaths).sort() });
51
- fs.writeFileSync(path.join(context.outputDir, "index.ts"), content);
186
+ const generatedFiles = context.getGeneratedFiles();
187
+ const groups = /* @__PURE__ */ new Map();
188
+ const rootFiles = /* @__PURE__ */ new Set();
189
+ const existingBarrels = /* @__PURE__ */ new Set();
190
+ for (const file of generatedFiles) {
191
+ const stripped = file.replace(/\.ts$/, "");
192
+ const firstSlash = stripped.indexOf("/");
193
+ if (firstSlash === -1) {
194
+ rootFiles.add(`./${stripped}`);
195
+ continue;
196
+ }
197
+ const firstSegment = stripped.slice(0, firstSlash);
198
+ if (firstSegment === "lib") {
199
+ const secondSlash = stripped.indexOf("/", firstSlash + 1);
200
+ const groupKey = secondSlash === -1 ? stripped : stripped.slice(0, secondSlash);
201
+ const entryName = stripped.slice(groupKey.length + 1);
202
+ if (entryName === "index") existingBarrels.add(groupKey);
203
+ else {
204
+ if (!groups.has(groupKey)) groups.set(groupKey, /* @__PURE__ */ new Set());
205
+ groups.get(groupKey).add(`./${entryName}`);
206
+ }
207
+ } else {
208
+ const entryName = stripped.slice(firstSlash + 1);
209
+ if (entryName === "index") existingBarrels.add(firstSegment);
210
+ else {
211
+ if (!groups.has(firstSegment)) groups.set(firstSegment, /* @__PURE__ */ new Set());
212
+ groups.get(firstSegment).add(`./${entryName}`);
213
+ }
214
+ }
215
+ }
216
+ for (const [groupKey, entries] of groups) {
217
+ if (existingBarrels.has(groupKey)) continue;
218
+ const domainBarrelContent = render(template, { indexPaths: Array.from(entries).sort() });
219
+ const domainIndexPath = path.join(context.outputDir, groupKey, "index.ts");
220
+ fs.mkdirSync(path.dirname(domainIndexPath), { recursive: true });
221
+ fs.writeFileSync(domainIndexPath, domainBarrelContent);
222
+ }
223
+ const rootIndexPaths = new Set(rootFiles);
224
+ for (const groupKey of groups.keys()) rootIndexPaths.add(`./${groupKey}`);
225
+ for (const barrelKey of existingBarrels) rootIndexPaths.add(`./${barrelKey}`);
226
+ const rootContent = render(template, { indexPaths: Array.from(rootIndexPaths).sort() });
227
+ fs.writeFileSync(path.join(context.outputDir, "index.ts"), rootContent);
52
228
  }
53
229
  };
54
230
 
@@ -4115,6 +4291,7 @@ var Generator = class {
4115
4291
  contextBuilder;
4116
4292
  pluginLoader;
4117
4293
  indexFileGenerator;
4294
+ definitionCompiler;
4118
4295
  resourceReader = null;
4119
4296
  formatter = null;
4120
4297
  inputDir = "";
@@ -4128,6 +4305,7 @@ var Generator = class {
4128
4305
  this.contextBuilder = contextBuilder ?? new PluginContextBuilder();
4129
4306
  this.pluginLoader = pluginLoader ?? new PluginLoader(this.registry, requiredPlugins);
4130
4307
  this.indexFileGenerator = indexFileGenerator ?? new IndexFileGenerator(this.templateDir);
4308
+ this.definitionCompiler = new DefinitionCompiler();
4131
4309
  }
4132
4310
  /**
4133
4311
  * Generate code using the plugin system
@@ -4186,6 +4364,8 @@ var Generator = class {
4186
4364
  this.indexFileGenerator.generate(generatorContext);
4187
4365
  console.info("Finalizing plugins...");
4188
4366
  for (const registration of this.registry.getAll()) if (registration.plugin.finalize) await registration.plugin.finalize(pluginContext);
4367
+ console.info("Compiling definitions...");
4368
+ this.definitionCompiler.compileInPlace(this.sourceDir);
4189
4369
  if (config?.format ?? true) await this.formatter.formatCode();
4190
4370
  console.info("Generation complete!");
4191
4371
  console.info(`Generated files: ${this.contextBuilder.getGeneratedFiles().length}`);