@cognisivelabs/openapi-to-express 0.1.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.
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Main generation orchestrator.
3
+ *
4
+ * Reads an OpenAPI spec, classifies schemas, and writes all generated files
5
+ * into the target directory with configurable folder names.
6
+ */
7
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
8
+ import { join, resolve, extname } from "node:path";
9
+ import YAML from "yaml";
10
+ import { parseSpec, classifySchemas } from "./parser/spec-parser.js";
11
+ import { generateTypesFile } from "./generators/types-generator.js";
12
+ import { generateControllerInterface } from "./generators/controller-generator.js";
13
+ import { generateExpressRoutes } from "./generators/routes-express-generator.js";
14
+ const HEADER = `// ============================================================================
15
+ // AUTO-GENERATED by openapi-to-express — do not edit manually.
16
+ // Regenerate with: npm run generate
17
+ // ============================================================================
18
+
19
+ `;
20
+ const DEFAULT_DIRS = {
21
+ types: "types",
22
+ controllers: "controllers",
23
+ routes: "routes",
24
+ };
25
+ function parseSpecContent(raw, hint) {
26
+ const trimmed = raw.trimStart();
27
+ // Try JSON first if it looks like JSON or hint says so
28
+ if (trimmed.startsWith("{") || hint === ".json") {
29
+ try {
30
+ return JSON.parse(raw);
31
+ }
32
+ catch {
33
+ // Fall through to YAML
34
+ }
35
+ }
36
+ // Try YAML (also handles JSON since JSON is valid YAML)
37
+ try {
38
+ return YAML.parse(raw);
39
+ }
40
+ catch {
41
+ throw new Error("Failed to parse input as JSON or YAML.");
42
+ }
43
+ }
44
+ async function resolveInput(input) {
45
+ // URL
46
+ if (input.startsWith("http://") || input.startsWith("https://")) {
47
+ const res = await fetch(input);
48
+ if (!res.ok)
49
+ throw new Error(`Failed to fetch spec from ${input}: ${res.status} ${res.statusText}`);
50
+ const raw = await res.text();
51
+ return parseSpecContent(raw, extname(new URL(input).pathname));
52
+ }
53
+ // File path
54
+ const filePath = resolve(input);
55
+ if (existsSync(filePath)) {
56
+ const raw = readFileSync(filePath, "utf-8");
57
+ return parseSpecContent(raw, extname(filePath));
58
+ }
59
+ // String content (JSON or YAML)
60
+ const trimmed = input.trimStart();
61
+ if (trimmed.startsWith("{") || trimmed.startsWith("openapi")) {
62
+ return parseSpecContent(input);
63
+ }
64
+ throw new Error(`Cannot resolve input: "${input}" is not a valid file path, URL, or JSON/YAML string.`);
65
+ }
66
+ export async function generate(options) {
67
+ const outDir = resolve(options.output);
68
+ const dirs = { ...DEFAULT_DIRS, ...options.dirs };
69
+ const dryRun = options.dryRun ?? false;
70
+ const spec = await resolveInput(options.input);
71
+ const parsed = parseSpec(spec);
72
+ const { common, perTag } = classifySchemas(parsed.byTag, parsed.schemas);
73
+ const commonSet = new Set(common);
74
+ if (!dryRun) {
75
+ mkdirSync(join(outDir, dirs.types), { recursive: true });
76
+ mkdirSync(join(outDir, dirs.controllers), { recursive: true });
77
+ mkdirSync(join(outDir, dirs.routes), { recursive: true });
78
+ }
79
+ const AUTO_GENERATED_MARKER = "AUTO-GENERATED by openapi-to-express";
80
+ let totalFiles = 0;
81
+ let skippedFiles = 0;
82
+ const filesPerDir = new Map();
83
+ function write(dir, name, content) {
84
+ const filePath = join(outDir, dir, name);
85
+ // Overwrite protection: skip files that exist but don't have our marker
86
+ if (!dryRun && existsSync(filePath)) {
87
+ const existing = readFileSync(filePath, "utf-8");
88
+ if (!existing.includes(AUTO_GENERATED_MARKER)) {
89
+ console.log(` ${dir}/${name} (skipped — manually modified)`);
90
+ skippedFiles++;
91
+ return;
92
+ }
93
+ }
94
+ if (!dryRun) {
95
+ writeFileSync(filePath, HEADER + content, "utf-8");
96
+ }
97
+ const list = filesPerDir.get(dir) ?? [];
98
+ list.push(name);
99
+ filesPerDir.set(dir, list);
100
+ console.log(` ${dir}/${name}`);
101
+ totalFiles++;
102
+ }
103
+ // 1. Common types (only if shared schemas exist)
104
+ if (common.length > 0) {
105
+ const { content } = generateTypesFile(common, parsed.schemas, new Set());
106
+ write(dirs.types, "common.types.ts", content);
107
+ }
108
+ // 2. Per-tag files
109
+ for (const [tag, operations] of parsed.byTag) {
110
+ const tagLower = tag.toLowerCase();
111
+ const tagSchemas = (perTag.get(tag) ?? []).sort();
112
+ // Types
113
+ const { content, imports } = generateTypesFile(tagSchemas, parsed.schemas, commonSet);
114
+ let typesContent = "";
115
+ if (imports.length > 0) {
116
+ typesContent += `import type { ${imports.join(", ")} } from "./common.types";\n\n`;
117
+ }
118
+ typesContent += content;
119
+ // Ensure file is a valid module even if no schemas were generated
120
+ if (!typesContent.trim()) {
121
+ typesContent = "export {};\n";
122
+ }
123
+ write(dirs.types, `${tagLower}.types.ts`, typesContent);
124
+ // Controller interface
125
+ write(dirs.controllers, `${tagLower}.controller.interface.ts`, generateControllerInterface(tag, operations));
126
+ // Routes
127
+ write(dirs.routes, `${tagLower}.routes.ts`, generateExpressRoutes(tag, operations, dirs));
128
+ }
129
+ // 3. Barrel (index.ts) files per directory
130
+ for (const [dir, files] of filesPerDir) {
131
+ const exports = files
132
+ .map((f) => `export * from "./${f.replace(/\.ts$/, "")}";`)
133
+ .join("\n");
134
+ write(dir, "index.ts", exports + "\n");
135
+ }
136
+ const prefix = dryRun ? "Would generate" : "Generated";
137
+ let summary = `\n${prefix} ${totalFiles} files from ${parsed.byTag.size} tag(s)` +
138
+ (common.length > 0 ? ` (${common.length} shared types in common.types.ts)` : "");
139
+ if (skippedFiles > 0) {
140
+ summary += ` — ${skippedFiles} file(s) skipped (manually modified)`;
141
+ }
142
+ console.log(summary + ".");
143
+ }
144
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AAEjF,MAAM,MAAM,GAAG;;;;;CAKd,CAAC;AAsBF,MAAM,YAAY,GAAoB;IACpC,KAAK,EAAE,OAAO;IACd,WAAW,EAAE,aAAa;IAC1B,MAAM,EAAE,QAAQ;CACjB,CAAC;AAEF,SAAS,gBAAgB,CAAC,GAAW,EAAE,IAAa;IAClD,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,EAAE,CAAC;IAEhC,uDAAuD;IACvD,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QAChD,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,uBAAuB;QACzB,CAAC;IACH,CAAC;IAED,wDAAwD;IACxD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,KAAa;IACvC,MAAM;IACN,IAAI,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAChE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,KAAK,KAAK,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;QACpG,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC7B,OAAO,gBAAgB,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IACjE,CAAC;IAED,YAAY;IACZ,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC5C,OAAO,gBAAgB,CAAC,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,gCAAgC;IAChC,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;IAClC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7D,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,0BAA0B,KAAK,uDAAuD,CAAC,CAAC;AAC1G,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAAwB;IACrD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,IAAI,GAAoB,EAAE,GAAG,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAEnE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC;IACvC,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IAElC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,qBAAqB,GAAG,sCAAsC,CAAC;IACrE,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,MAAM,WAAW,GAAG,IAAI,GAAG,EAAoB,CAAC;IAEhD,SAAS,KAAK,CAAC,GAAW,EAAE,IAAY,EAAE,OAAe;QACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QAEzC,wEAAwE;QACxE,IAAI,CAAC,MAAM,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpC,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACjD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;gBAC9C,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,IAAI,gCAAgC,CAAC,CAAC;gBAC9D,YAAY,EAAE,CAAC;gBACf,OAAO;YACT,CAAC;QACH,CAAC;QAED,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,OAAO,CAAC,CAAC;QACrD,CAAC;QACD,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChB,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,CAAC;QAChC,UAAU,EAAE,CAAC;IACf,CAAC;IAED,iDAAiD;IACjD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,EAAE,OAAO,EAAE,GAAG,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QACzE,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,iBAAiB,EAAE,OAAO,CAAC,CAAC;IAChD,CAAC;IAED,mBAAmB;IACnB,KAAK,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAC7C,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;QACnC,MAAM,UAAU,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAElD,QAAQ;QACR,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,iBAAiB,CAAC,UAAU,EAAE,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACtF,IAAI,YAAY,GAAG,EAAE,CAAC;QACtB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,YAAY,IAAI,iBAAiB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,+BAA+B,CAAC;QACrF,CAAC;QACD,YAAY,IAAI,OAAO,CAAC;QACxB,kEAAkE;QAClE,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC;YACzB,YAAY,GAAG,cAAc,CAAC;QAChC,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,QAAQ,WAAW,EAAE,YAAY,CAAC,CAAC;QAExD,uBAAuB;QACvB,KAAK,CACH,IAAI,CAAC,WAAW,EAChB,GAAG,QAAQ,0BAA0B,EACrC,2BAA2B,CAAC,GAAG,EAAE,UAAU,CAAC,CAC7C,CAAC;QAEF,SAAS;QACT,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,QAAQ,YAAY,EAAE,qBAAqB,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;IAC5F,CAAC;IAED,2CAA2C;IAC3C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,KAAK;aAClB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,oBAAoB,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC;aAC1D,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,KAAK,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,GAAG,IAAI,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,WAAW,CAAC;IACvD,IAAI,OAAO,GACT,KAAK,MAAM,IAAI,UAAU,eAAe,MAAM,CAAC,KAAK,CAAC,IAAI,SAAS;QAClE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,mCAAmC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACnF,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,IAAI,MAAM,YAAY,sCAAsC,CAAC;IACtE,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Generates controller interface files from parsed operations.
3
+ *
4
+ * The controller owns the HTTP layer — it receives Request/Response
5
+ * and is responsible for param extraction, response formatting, and error handling.
6
+ */
7
+ import type { OperationInfo } from "../parser/spec-parser.js";
8
+ export declare function generateControllerInterface(tag: string, operations: OperationInfo[]): string;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Generates controller interface files from parsed operations.
3
+ *
4
+ * The controller owns the HTTP layer — it receives Request/Response
5
+ * and is responsible for param extraction, response formatting, and error handling.
6
+ */
7
+ import { toPascalCase, toMethodName, toJsDocLines } from "../utils/strings.js";
8
+ export function generateControllerInterface(tag, operations) {
9
+ const interfaceName = `${toPascalCase(tag)}Controller`;
10
+ const lines = [];
11
+ lines.push(`import type { Request, Response } from "express";`);
12
+ lines.push("");
13
+ lines.push(`export interface ${interfaceName} {`);
14
+ for (const op of operations) {
15
+ const methodName = toMethodName(op.operationId);
16
+ if (op.summary || op.description || op.deprecated) {
17
+ lines.push(` /**`);
18
+ if (op.summary)
19
+ lines.push(...toJsDocLines(op.summary));
20
+ if (op.summary && op.description)
21
+ lines.push(` *`);
22
+ if (op.description)
23
+ lines.push(...toJsDocLines(op.description));
24
+ if (op.deprecated)
25
+ lines.push(` * @deprecated`);
26
+ lines.push(` */`);
27
+ }
28
+ lines.push(` ${methodName}(req: Request, res: Response): Promise<void>;`);
29
+ }
30
+ lines.push(`}`, "");
31
+ return lines.join("\n");
32
+ }
33
+ //# sourceMappingURL=controller-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller-generator.js","sourceRoot":"","sources":["../../src/generators/controller-generator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAE/E,MAAM,UAAU,2BAA2B,CACzC,GAAW,EACX,UAA2B;IAE3B,MAAM,aAAa,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC;IACvD,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;IAChE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,KAAK,CAAC,IAAI,CAAC,oBAAoB,aAAa,IAAI,CAAC,CAAC;IAClD,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;QAC5B,MAAM,UAAU,GAAG,YAAY,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC;QAChD,IAAI,EAAE,CAAC,OAAO,IAAI,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC,UAAU,EAAE,CAAC;YAClD,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACpB,IAAI,EAAE,CAAC,OAAO;gBAAE,KAAK,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;YACxD,IAAI,EAAE,CAAC,OAAO,IAAI,EAAE,CAAC,WAAW;gBAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACrD,IAAI,EAAE,CAAC,WAAW;gBAAE,KAAK,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;YAChE,IAAI,EAAE,CAAC,UAAU;gBAAE,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;YAClD,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtB,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,KAAK,UAAU,+CAA+C,CAAC,CAAC;IAC7E,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAEpB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Generates lean Express router files — one line per endpoint.
3
+ *
4
+ * Routes are pure wiring: HTTP method + path → controller method.
5
+ * The controller handles param extraction, response formatting, and errors.
6
+ */
7
+ import type { OperationInfo } from "../parser/spec-parser.js";
8
+ import type { DirectoryConfig } from "../generate.js";
9
+ export declare function generateExpressRoutes(tag: string, operations: OperationInfo[], dirs: DirectoryConfig): string;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Generates lean Express router files — one line per endpoint.
3
+ *
4
+ * Routes are pure wiring: HTTP method + path → controller method.
5
+ * The controller handles param extraction, response formatting, and errors.
6
+ */
7
+ import { computeRelativeImport } from "../utils/paths.js";
8
+ import { toPascalCase, toMethodName } from "../utils/strings.js";
9
+ function toExpressPath(path) {
10
+ return path.replace(/\{(\w+)\}/g, ":$1");
11
+ }
12
+ export function generateExpressRoutes(tag, operations, dirs) {
13
+ const pascalTag = toPascalCase(tag);
14
+ const interfaceName = `${pascalTag}Controller`;
15
+ const tagLower = tag.toLowerCase();
16
+ const toControllers = computeRelativeImport(dirs.routes, dirs.controllers);
17
+ const lines = [
18
+ `import { Router } from "express";`,
19
+ `import type { ${interfaceName} } from "${toControllers}/${tagLower}.controller.interface";`,
20
+ ``,
21
+ `export function create${pascalTag}Router(controller: ${interfaceName}, middleware?: any[]): Router {`,
22
+ ` const router = Router();`,
23
+ ``,
24
+ ` if (middleware) {`,
25
+ ` middleware.forEach((mw) => router.use(mw));`,
26
+ ` }`,
27
+ ``,
28
+ ];
29
+ for (const op of operations) {
30
+ const expressPath = toExpressPath(op.path);
31
+ const methodName = toMethodName(op.operationId);
32
+ lines.push(` router.${op.method}("${expressPath}", (req, res) => controller.${methodName}(req, res));`);
33
+ }
34
+ lines.push(``);
35
+ lines.push(` return router;`);
36
+ lines.push(`}`, "");
37
+ return lines.join("\n");
38
+ }
39
+ //# sourceMappingURL=routes-express-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes-express-generator.js","sourceRoot":"","sources":["../../src/generators/routes-express-generator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEjE,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,GAAW,EACX,UAA2B,EAC3B,IAAqB;IAErB,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,aAAa,GAAG,GAAG,SAAS,YAAY,CAAC;IAC/C,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IACnC,MAAM,aAAa,GAAG,qBAAqB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAE3E,MAAM,KAAK,GAAG;QACZ,mCAAmC;QACnC,iBAAiB,aAAa,YAAY,aAAa,IAAI,QAAQ,yBAAyB;QAC5F,EAAE;QACF,yBAAyB,SAAS,sBAAsB,aAAa,iCAAiC;QACtG,4BAA4B;QAC5B,EAAE;QACF,qBAAqB;QACrB,iDAAiD;QACjD,KAAK;QACL,EAAE;KACH,CAAC;IAEF,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;QAC5B,MAAM,WAAW,GAAG,aAAa,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,UAAU,GAAG,YAAY,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC;QAChD,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,MAAM,KAAK,WAAW,+BAA+B,UAAU,cAAc,CAAC,CAAC;IAC3G,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC/B,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACpB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Generates plain TypeScript interfaces from OpenAPI component schemas.
3
+ *
4
+ * Supports:
5
+ * - type: "object" with properties
6
+ * - allOf (intersection / extends)
7
+ * - oneOf / anyOf (union types)
8
+ * - $ref, enum, array, primitives
9
+ * - nullable
10
+ */
11
+ export declare function generateTypesFile(schemaNames: string[], allSchemas: Record<string, any>, definedElsewhere: Set<string>): {
12
+ content: string;
13
+ imports: string[];
14
+ };
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Generates plain TypeScript interfaces from OpenAPI component schemas.
3
+ *
4
+ * Supports:
5
+ * - type: "object" with properties
6
+ * - allOf (intersection / extends)
7
+ * - oneOf / anyOf (union types)
8
+ * - $ref, enum, array, primitives
9
+ * - nullable
10
+ */
11
+ import { refToTypeName, collectRefsFromSchema } from "../parser/spec-parser.js";
12
+ import { capitalize, enumKeyFromValue, safePropertyName, escapeJsDoc } from "../utils/strings.js";
13
+ function toTsType(schema) {
14
+ if (!schema)
15
+ return "unknown";
16
+ if (schema.$ref)
17
+ return refToTypeName(schema.$ref);
18
+ if (schema.enum)
19
+ return schema.enum.map((v) => typeof v === "string" ? `"${v}"` : String(v)).join(" | ");
20
+ if (schema.oneOf)
21
+ return schema.oneOf.map((s) => toTsType(s)).join(" | ");
22
+ if (schema.anyOf)
23
+ return schema.anyOf.map((s) => toTsType(s)).join(" | ");
24
+ if (schema.allOf)
25
+ return schema.allOf.map((s) => toTsType(s)).join(" & ");
26
+ if (schema.type === "string")
27
+ return "string";
28
+ if (schema.type === "integer" || schema.type === "number")
29
+ return "number";
30
+ if (schema.type === "boolean")
31
+ return "boolean";
32
+ if (schema.type === "array")
33
+ return `${toTsType(schema.items)}[]`;
34
+ if (schema.type === "object" && schema.properties) {
35
+ const required = new Set(schema.required ?? []);
36
+ const fields = Object.entries(schema.properties)
37
+ .map(([k, v]) => `${safePropertyName(k)}${required.has(k) ? "" : "?"}: ${toTsType(v)}`)
38
+ .join("; ");
39
+ return `{ ${fields} }`;
40
+ }
41
+ if (schema.type === "object" && schema.additionalProperties) {
42
+ const valType = schema.additionalProperties === true ? "unknown" : toTsType(schema.additionalProperties);
43
+ return `Record<string, ${valType}>`;
44
+ }
45
+ if (schema.type === "object")
46
+ return "Record<string, unknown>";
47
+ return "unknown";
48
+ }
49
+ function addNullable(tsType, schema) {
50
+ if (schema.nullable)
51
+ return `${tsType} | null`;
52
+ return tsType;
53
+ }
54
+ /**
55
+ * Determines if a schema is a composition type (allOf/oneOf/anyOf at the top level
56
+ * without its own properties) and should be generated as a type alias rather than interface.
57
+ */
58
+ function isTypeAlias(schema) {
59
+ if (schema.oneOf || schema.anyOf)
60
+ return true;
61
+ if (schema.allOf) {
62
+ // If any sub-schema has properties, this is "extends" → interface, not type alias
63
+ const hasInlineProperties = schema.properties || schema.allOf.some((s) => s.properties);
64
+ return !hasInlineProperties;
65
+ }
66
+ return false;
67
+ }
68
+ /**
69
+ * For allOf schemas that mix $ref with inline properties, collect all inline properties
70
+ * and all $ref base types. This is the "extends" pattern:
71
+ * allOf:
72
+ * - $ref: "#/components/schemas/Base"
73
+ * - type: object
74
+ * properties: { extra: ... }
75
+ */
76
+ function decomposeAllOf(schema) {
77
+ const bases = [];
78
+ let properties = {};
79
+ let required = [];
80
+ for (const sub of schema.allOf) {
81
+ if (sub.$ref) {
82
+ bases.push(refToTypeName(sub.$ref));
83
+ }
84
+ else if (sub.properties || sub.type === "object") {
85
+ properties = { ...properties, ...sub.properties };
86
+ required = [...required, ...(sub.required ?? [])];
87
+ }
88
+ }
89
+ // Also merge top-level properties if present alongside allOf
90
+ if (schema.properties) {
91
+ properties = { ...properties, ...schema.properties };
92
+ required = [...required, ...(schema.required ?? [])];
93
+ }
94
+ return { bases, properties, required };
95
+ }
96
+ export function generateTypesFile(schemaNames, allSchemas, definedElsewhere) {
97
+ const defined = new Set(schemaNames);
98
+ const imports = new Set();
99
+ const lines = [];
100
+ const enums = [];
101
+ for (const name of schemaNames.sort()) {
102
+ const schema = allSchemas[name];
103
+ if (!schema)
104
+ continue;
105
+ // Collect all referenced types to determine imports
106
+ const refs = new Set();
107
+ collectRefsFromSchema(schema, refs);
108
+ for (const ref of refs) {
109
+ if (!defined.has(ref) && definedElsewhere.has(ref)) {
110
+ imports.add(ref);
111
+ }
112
+ }
113
+ // --- Type alias: oneOf / anyOf / pure allOf ---
114
+ if (isTypeAlias(schema)) {
115
+ const discriminator = schema.discriminator?.propertyName;
116
+ if (schema.description && !discriminator) {
117
+ lines.push(`/** ${escapeJsDoc(schema.description)} */`);
118
+ }
119
+ else if (schema.description || discriminator) {
120
+ lines.push(`/**`);
121
+ if (schema.description)
122
+ lines.push(` * ${escapeJsDoc(schema.description)}`);
123
+ if (discriminator)
124
+ lines.push(` * @discriminator ${discriminator}`);
125
+ lines.push(` */`);
126
+ }
127
+ if (schema.allOf && !schema.properties) {
128
+ const parts = schema.allOf.map((s) => toTsType(s));
129
+ lines.push(`export type ${name} = ${parts.join(" & ")};`);
130
+ }
131
+ else if (schema.oneOf) {
132
+ const parts = schema.oneOf.map((s) => toTsType(s));
133
+ lines.push(`export type ${name} = ${parts.join(" | ")};`);
134
+ }
135
+ else if (schema.anyOf) {
136
+ const parts = schema.anyOf.map((s) => toTsType(s));
137
+ lines.push(`export type ${name} = ${parts.join(" | ")};`);
138
+ }
139
+ lines.push("");
140
+ continue;
141
+ }
142
+ // --- Interface: object with properties, or allOf with inline properties ---
143
+ let properties = {};
144
+ let required = new Set();
145
+ let extendsClause = "";
146
+ if (schema.allOf) {
147
+ const decomposed = decomposeAllOf(schema);
148
+ properties = decomposed.properties;
149
+ required = new Set(decomposed.required);
150
+ if (decomposed.bases.length > 0) {
151
+ extendsClause = ` extends ${decomposed.bases.join(", ")}`;
152
+ }
153
+ }
154
+ else if (schema.type === "object" || schema.properties) {
155
+ properties = schema.properties ?? {};
156
+ required = new Set(schema.required ?? []);
157
+ }
158
+ else {
159
+ // Primitive type alias: type: string, enum, array, etc.
160
+ if (schema.description) {
161
+ lines.push(`/** ${escapeJsDoc(schema.description)} */`);
162
+ }
163
+ const tsType = toTsType(schema);
164
+ lines.push(`export type ${name} = ${tsType};`);
165
+ lines.push("");
166
+ continue;
167
+ }
168
+ if (schema.description || schema.deprecated) {
169
+ if (schema.description && !schema.deprecated) {
170
+ lines.push(`/** ${escapeJsDoc(schema.description)} */`);
171
+ }
172
+ else {
173
+ lines.push(`/**`);
174
+ if (schema.description)
175
+ lines.push(` * ${escapeJsDoc(schema.description)}`);
176
+ if (schema.deprecated)
177
+ lines.push(` * @deprecated`);
178
+ lines.push(` */`);
179
+ }
180
+ }
181
+ lines.push(`export interface ${name}${extendsClause} {`);
182
+ for (const [prop, propDef] of Object.entries(properties)) {
183
+ const optional = required.has(prop) ? "" : "?";
184
+ let tsType;
185
+ if (propDef.enum) {
186
+ // Generate a named enum const — use InterfaceProp naming
187
+ const enumName = `${name}${capitalize(prop)}`;
188
+ enums.push({ name: enumName, values: propDef.enum });
189
+ tsType = enumName;
190
+ }
191
+ else {
192
+ tsType = toTsType(propDef);
193
+ }
194
+ tsType = addNullable(tsType, propDef);
195
+ // JSDoc: description + annotations
196
+ const docParts = [];
197
+ if (propDef.description)
198
+ docParts.push(escapeJsDoc(propDef.description));
199
+ if (propDef.format)
200
+ docParts.push(`@format ${propDef.format}`);
201
+ if (propDef.readOnly)
202
+ docParts.push(`@readonly`);
203
+ if (propDef.writeOnly)
204
+ docParts.push(`@writeOnly`);
205
+ if (propDef.default !== undefined) {
206
+ const defaultVal = typeof propDef.default === "string" ? `"${propDef.default}"` : String(propDef.default);
207
+ docParts.push(`@default ${defaultVal}`);
208
+ }
209
+ if (propDef.deprecated)
210
+ docParts.push(`@deprecated`);
211
+ if (docParts.length === 1) {
212
+ lines.push(` /** ${docParts[0]} */`);
213
+ }
214
+ else if (docParts.length > 1) {
215
+ lines.push(` /**`);
216
+ for (const part of docParts)
217
+ lines.push(` * ${part}`);
218
+ lines.push(` */`);
219
+ }
220
+ lines.push(` ${safePropertyName(prop)}${optional}: ${tsType};`);
221
+ }
222
+ lines.push(`}`, "");
223
+ }
224
+ // Append enum const objects
225
+ if (enums.length > 0) {
226
+ for (const e of enums) {
227
+ lines.push(`export const ${e.name} = {`);
228
+ for (const val of e.values) {
229
+ const key = typeof val === "string" ? enumKeyFromValue(val) : `Value${val}`;
230
+ const literal = typeof val === "string" ? `"${val}"` : String(val);
231
+ lines.push(` ${key}: ${literal},`);
232
+ }
233
+ lines.push(`} as const;`);
234
+ lines.push(`export type ${e.name} = (typeof ${e.name})[keyof typeof ${e.name}];`);
235
+ lines.push("");
236
+ }
237
+ }
238
+ return { content: lines.join("\n"), imports: Array.from(imports).sort() };
239
+ }
240
+ //# sourceMappingURL=types-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-generator.js","sourceRoot":"","sources":["../../src/generators/types-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { generate } from "./generate.js";
2
+ export type { GenerateOptions, DirectoryConfig } from "./generate.js";
3
+ export { loadConfig } from "./config.js";
4
+ export type { ConfigFile } from "./config.js";
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { generate } from "./generate.js";
2
+ export { loadConfig } from "./config.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Parses an OpenAPI 3.x spec and extracts structured data for code generation.
3
+ */
4
+ export interface ParamInfo {
5
+ name: string;
6
+ in: "path" | "query" | "header";
7
+ required: boolean;
8
+ type: string;
9
+ }
10
+ export interface OperationInfo {
11
+ path: string;
12
+ method: string;
13
+ operationId: string;
14
+ requestType: string | null;
15
+ requestRequired: boolean;
16
+ responseType: string;
17
+ errorTypes: {
18
+ status: string;
19
+ type: string;
20
+ }[];
21
+ tag: string;
22
+ pathParams: ParamInfo[];
23
+ queryParams: ParamInfo[];
24
+ headerParams: ParamInfo[];
25
+ summary?: string;
26
+ description?: string;
27
+ deprecated?: boolean;
28
+ }
29
+ export interface ParsedSpec {
30
+ operations: OperationInfo[];
31
+ schemas: Record<string, any>;
32
+ byTag: Map<string, OperationInfo[]>;
33
+ }
34
+ export declare function refToTypeName(ref: string): string;
35
+ export declare function parseSpec(spec: any): ParsedSpec;
36
+ /**
37
+ * Collect all $ref type names from a schema node (non-recursive into schemas map).
38
+ */
39
+ export declare function collectRefsFromSchema(schema: any, refs: Set<string>): void;
40
+ /**
41
+ * Walk a named schema recursively through the schemas map, collecting
42
+ * all transitively referenced schema names.
43
+ */
44
+ export declare function walkSchemaRefs(name: string, schemas: Record<string, any>, collected: Set<string>): void;
45
+ /**
46
+ * Classify schemas into common (multi-tag) vs tag-specific.
47
+ */
48
+ export declare function classifySchemas(byTag: Map<string, OperationInfo[]>, schemas: Record<string, any>): {
49
+ common: string[];
50
+ perTag: Map<string, string[]>;
51
+ };