@codewithagents/openapi-server 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -18475,44 +18475,46 @@ function validateInputPath(resolvedInput) {
18475
18475
  }
18476
18476
  }
18477
18477
  }
18478
- async function loadConfigFile(opts) {
18479
- const resolvedConfigPath = opts.configPath ?? (0, import_node_path.join)(opts.cwd, opts.defaultFileName);
18480
- if (opts.configPath !== void 0) {
18481
- validateConfigPath(opts.configPath);
18478
+ async function loadJsConfig(resolvedConfigPath) {
18479
+ let mod;
18480
+ try {
18481
+ mod = await import((0, import_node_url.pathToFileURL)(resolvedConfigPath).href);
18482
+ } catch (err) {
18483
+ const message = err instanceof Error ? err.message : String(err);
18484
+ throw new Error(`Failed to load JS config file: ${resolvedConfigPath}
18485
+ ${message}`);
18482
18486
  }
18483
- let raw;
18487
+ const exported = mod["default"] ?? mod;
18488
+ if (typeof exported !== "object" || exported === null) {
18489
+ throw new Error("Config must be a JSON object");
18490
+ }
18491
+ return exported;
18492
+ }
18493
+ async function loadJsonConfig(resolvedConfigPath) {
18494
+ let fileContents;
18495
+ try {
18496
+ fileContents = await (0, import_promises.readFile)(resolvedConfigPath, "utf-8");
18497
+ } catch {
18498
+ throw new Error(`Config file not found: ${resolvedConfigPath}`);
18499
+ }
18500
+ let parsed2;
18501
+ try {
18502
+ parsed2 = JSON.parse(fileContents);
18503
+ } catch {
18504
+ throw new Error(`Config file is not valid JSON: ${resolvedConfigPath}`);
18505
+ }
18506
+ if (typeof parsed2 !== "object" || parsed2 === null) {
18507
+ throw new Error("Config must be a JSON object");
18508
+ }
18509
+ return parsed2;
18510
+ }
18511
+ async function loadRawConfig(resolvedConfigPath) {
18484
18512
  if (isJsConfigPath(resolvedConfigPath)) {
18485
- let mod;
18486
- try {
18487
- mod = await import((0, import_node_url.pathToFileURL)(resolvedConfigPath).href);
18488
- } catch (err) {
18489
- const message = err instanceof Error ? err.message : String(err);
18490
- throw new Error(`Failed to load JS config file: ${resolvedConfigPath}
18491
- ${message}`);
18492
- }
18493
- const exported = mod["default"] ?? mod;
18494
- if (typeof exported !== "object" || exported === null) {
18495
- throw new Error("Config must be a JSON object");
18496
- }
18497
- raw = exported;
18498
- } else {
18499
- let fileContents;
18500
- try {
18501
- fileContents = await (0, import_promises.readFile)(resolvedConfigPath, "utf-8");
18502
- } catch {
18503
- throw new Error(`Config file not found: ${resolvedConfigPath}`);
18504
- }
18505
- let parsed2;
18506
- try {
18507
- parsed2 = JSON.parse(fileContents);
18508
- } catch {
18509
- throw new Error(`Config file is not valid JSON: ${resolvedConfigPath}`);
18510
- }
18511
- if (typeof parsed2 !== "object" || parsed2 === null) {
18512
- throw new Error("Config must be a JSON object");
18513
- }
18514
- raw = parsed2;
18513
+ return loadJsConfig(resolvedConfigPath);
18515
18514
  }
18515
+ return loadJsonConfig(resolvedConfigPath);
18516
+ }
18517
+ function parseBaseConfig(raw, cwd) {
18516
18518
  if (typeof raw["input_openapi"] !== "string" || !raw["input_openapi"]) {
18517
18519
  throw new Error('Config missing required field: "input_openapi" (path to OpenAPI 3.1 spec)');
18518
18520
  }
@@ -18521,34 +18523,80 @@ ${message}`);
18521
18523
  }
18522
18524
  const input_openapi = raw["input_openapi"];
18523
18525
  const output = raw["output"];
18524
- validateInputPath((0, import_node_path.resolve)(opts.cwd, input_openapi));
18525
- validateOutputPath((0, import_node_path.resolve)(opts.cwd, output));
18526
- const base = { input_openapi, output };
18527
- return opts.parse(raw, base, opts.cwd);
18526
+ validateInputPath((0, import_node_path.resolve)(cwd, input_openapi));
18527
+ validateOutputPath((0, import_node_path.resolve)(cwd, output));
18528
+ return { input_openapi, output };
18528
18529
  }
18529
-
18530
- // src/config.ts
18531
- async function loadConfig(cwd, configPath) {
18532
- return loadConfigFile({
18533
- cwd,
18534
- configPath,
18535
- defaultFileName: "openapi-server.config.json",
18536
- parse: (raw) => {
18537
- const framework = raw["framework"];
18538
- if (framework !== void 0 && framework !== "hono" && framework !== "express" && framework !== "fastify" && framework !== "none") {
18539
- throw new Error('"framework" must be one of: "hono", "express", "fastify", or "none"');
18540
- }
18541
- if (raw["input_schema"] !== void 0 && (typeof raw["input_schema"] !== "string" || !raw["input_schema"])) {
18542
- throw new Error('"input_schema" must be a non-empty string path to your Zod schema file');
18543
- }
18544
- return {
18545
- input_openapi: raw["input_openapi"],
18546
- output: raw["output"],
18547
- framework,
18548
- input_schema: raw["input_schema"]
18549
- };
18530
+ async function prepareRaw(opts) {
18531
+ const resolvedConfigPath = opts.configPath ?? (0, import_node_path.join)(opts.cwd, opts.defaultFileName);
18532
+ if (opts.configPath !== void 0) {
18533
+ validateConfigPath(opts.configPath);
18534
+ }
18535
+ return { raw: await loadRawConfig(resolvedConfigPath) };
18536
+ }
18537
+ function parseProjectEntry(entry, index, opts) {
18538
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
18539
+ throw new Error(`projects[${index}]: entry must be a config object`);
18540
+ }
18541
+ const projectRaw = entry;
18542
+ let base;
18543
+ try {
18544
+ base = parseBaseConfig(projectRaw, opts.cwd);
18545
+ } catch (err) {
18546
+ const message = err instanceof Error ? err.message : String(err);
18547
+ throw new Error(`projects[${index}]: ${message}`);
18548
+ }
18549
+ try {
18550
+ return opts.parse(projectRaw, base, opts.cwd);
18551
+ } catch (err) {
18552
+ const message = err instanceof Error ? err.message : String(err);
18553
+ throw new Error(`projects[${index}]: ${message}`);
18554
+ }
18555
+ }
18556
+ async function loadConfigsFile(opts) {
18557
+ const { raw } = await prepareRaw(opts);
18558
+ if ("projects" in raw) {
18559
+ return parseProjectsArray(raw, opts);
18560
+ }
18561
+ const base = parseBaseConfig(raw, opts.cwd);
18562
+ return [opts.parse(raw, base, opts.cwd)];
18563
+ }
18564
+ function parseProjectsArray(raw, opts) {
18565
+ const hasTopLevelInput = "input_openapi" in raw && raw["input_openapi"] !== void 0;
18566
+ const hasTopLevelOutput = "output" in raw && raw["output"] !== void 0;
18567
+ if (hasTopLevelInput || hasTopLevelOutput) {
18568
+ throw new Error('Config cannot have both top-level "input_openapi"/"output" and a "projects" array. Use one form or the other.');
18569
+ }
18570
+ const projects = raw["projects"];
18571
+ if (!Array.isArray(projects)) {
18572
+ throw new Error('"projects" must be an array of config objects');
18573
+ }
18574
+ if (projects.length === 0) {
18575
+ throw new Error('"projects" array must contain at least one config entry');
18576
+ }
18577
+ return projects.map((entry, index) => parseProjectEntry(entry, index, opts));
18578
+ }
18579
+ async function runProjects(configs, generateOne2) {
18580
+ if (configs.length === 0) {
18581
+ throw new Error("runProjects requires at least one config entry");
18582
+ }
18583
+ if (configs.length === 1) {
18584
+ await generateOne2(configs[0]);
18585
+ return;
18586
+ }
18587
+ for (let i = 0; i < configs.length; i++) {
18588
+ const label = `${i + 1}/${configs.length}`;
18589
+ console.log(`
18590
+ [${label}] generating ${configs[i].input_openapi}...`);
18591
+ try {
18592
+ await generateOne2(configs[i], label);
18593
+ } catch (err) {
18594
+ const message = err instanceof Error ? err.message : String(err);
18595
+ throw new Error(`[${label}] Project failed (${configs[i].input_openapi}): ${message}`);
18550
18596
  }
18551
- });
18597
+ }
18598
+ console.log(`
18599
+ All ${configs.length} projects generated successfully.`);
18552
18600
  }
18553
18601
 
18554
18602
  // ../openapi-zod-ts/dist/parser.js
@@ -18787,7 +18835,31 @@ function toTypeName(name) {
18787
18835
  return safe.length > 0 ? safe : "_";
18788
18836
  }
18789
18837
 
18790
- // src/plugins/service.ts
18838
+ // src/config.ts
18839
+ function parseServerConfig(raw, base) {
18840
+ const framework = raw["framework"];
18841
+ if (framework !== void 0 && framework !== "hono" && framework !== "express" && framework !== "fastify" && framework !== "none") {
18842
+ throw new Error('"framework" must be one of: "hono", "express", "fastify", or "none"');
18843
+ }
18844
+ if (raw["input_schema"] !== void 0 && (typeof raw["input_schema"] !== "string" || !raw["input_schema"])) {
18845
+ throw new Error('"input_schema" must be a non-empty string path to your Zod schema file');
18846
+ }
18847
+ return {
18848
+ ...base,
18849
+ framework,
18850
+ input_schema: raw["input_schema"]
18851
+ };
18852
+ }
18853
+ async function loadConfigs2(cwd, configPath) {
18854
+ return loadConfigsFile({
18855
+ cwd,
18856
+ configPath,
18857
+ defaultFileName: "openapi-server.config.json",
18858
+ parse: parseServerConfig
18859
+ });
18860
+ }
18861
+
18862
+ // src/plugins/shared.ts
18791
18863
  var SUPPORTED_METHODS = ["get", "post", "put", "patch", "delete"];
18792
18864
  function isRef3(obj) {
18793
18865
  return typeof obj === "object" && obj !== null && "$ref" in obj;
@@ -18799,7 +18871,7 @@ function refToName(ref) {
18799
18871
  function extractPathParamsFromPath(path) {
18800
18872
  const matches = path.match(/\{([^}]+)\}/g);
18801
18873
  if (matches === null) return [];
18802
- return matches.map((m) => sanitizeOperationId2(m.slice(1, -1)));
18874
+ return matches.map((m) => m.slice(1, -1));
18803
18875
  }
18804
18876
  function resolveParam(p, spec) {
18805
18877
  if (!isRef3(p)) return p;
@@ -18866,6 +18938,13 @@ function normalizeParamName(name) {
18866
18938
  const camel = parts.map((part, i) => i === 0 ? part : part[0].toUpperCase() + part.slice(1)).join("");
18867
18939
  return /^[^a-zA-Z_$]/.test(camel) ? `_${camel}` : camel;
18868
18940
  }
18941
+ function schemaToTsType(schema) {
18942
+ if (schema === void 0 || isRef3(schema)) return "string";
18943
+ const s = schema;
18944
+ if (s.type === "number" || s.type === "integer") return "number";
18945
+ if (s.type === "boolean") return "boolean";
18946
+ return "string";
18947
+ }
18869
18948
  function getQueryParams(operation, spec) {
18870
18949
  const parameters = operation.parameters;
18871
18950
  if (parameters === void 0) return [];
@@ -18874,15 +18953,9 @@ function getQueryParams(operation, spec) {
18874
18953
  const resolved = resolveParam(p, spec);
18875
18954
  if (resolved === void 0 || resolved.in !== "query") continue;
18876
18955
  const schema = resolved.schema;
18877
- let tsType = "string";
18878
- if (schema !== void 0 && !isRef3(schema)) {
18879
- const s = schema;
18880
- if (s.type === "number" || s.type === "integer") tsType = "number";
18881
- else if (s.type === "boolean") tsType = "boolean";
18882
- }
18883
18956
  result.push({
18884
18957
  name: normalizeParamName(resolved.name),
18885
- tsType,
18958
+ tsType: schemaToTsType(schema),
18886
18959
  required: resolved.required === true
18887
18960
  });
18888
18961
  }
@@ -18903,6 +18976,8 @@ function getBodyInfo(operation) {
18903
18976
  }
18904
18977
  return { typeName: void 0 };
18905
18978
  }
18979
+
18980
+ // src/plugins/service.ts
18906
18981
  function getReturnInfo(operation) {
18907
18982
  const responses = operation.responses;
18908
18983
  if (responses === void 0) return { typeName: void 0, isArray: false, isVoid: true };
@@ -18978,7 +19053,7 @@ function collectOperations(spec) {
18978
19053
  function buildMethodSignature(op) {
18979
19054
  const args = [];
18980
19055
  for (const p of op.pathParams) {
18981
- args.push(`${p}: string`);
19056
+ args.push(`${sanitizeOperationId2(p)}: string`);
18982
19057
  }
18983
19058
  if (op.bodyInfo !== void 0) {
18984
19059
  const typeName = op.bodyInfo.typeName ?? "unknown";
@@ -19028,110 +19103,9 @@ function generateService(spec) {
19028
19103
  }
19029
19104
 
19030
19105
  // src/plugins/router.ts
19031
- var SUPPORTED_METHODS2 = ["get", "post", "put", "patch", "delete"];
19032
- function isRef4(obj) {
19033
- return typeof obj === "object" && obj !== null && "$ref" in obj;
19034
- }
19035
- function refToName2(ref) {
19036
- const parts = ref.split("/");
19037
- return toTypeName(parts[parts.length - 1]);
19038
- }
19039
- function extractPathParamsFromPath2(path) {
19040
- const matches = path.match(/\{([^}]+)\}/g);
19041
- if (matches === null) return [];
19042
- return matches.map((m) => m.slice(1, -1));
19043
- }
19044
19106
  function toHonoPath(openapiPath) {
19045
19107
  return openapiPath.replace(/\{([^}]+)\}/g, ":$1");
19046
19108
  }
19047
- function resolveParam2(p, spec) {
19048
- if (!isRef4(p)) return p;
19049
- const refStr = p.$ref;
19050
- const name = refToName2(refStr);
19051
- const components = spec.components;
19052
- if (components?.parameters === void 0) return void 0;
19053
- const resolved = components.parameters[name];
19054
- if (resolved === void 0 || isRef4(resolved)) return void 0;
19055
- return resolved;
19056
- }
19057
- function deriveServiceName2(spec) {
19058
- const title = spec.info?.title ?? "";
19059
- const pascal = title.replace(/[^a-zA-Z0-9 ]/g, "").split(/\s+/).filter((s) => s.length > 0).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
19060
- if (pascal.length === 0) return "ApiService";
19061
- const safePascal = /^[0-9]/.test(pascal) ? `_${pascal}` : pascal;
19062
- if (safePascal.endsWith("Service")) return safePascal;
19063
- return `${safePascal}Service`;
19064
- }
19065
- function sanitizeOperationId3(id) {
19066
- const parts = id.replace(/'/g, "").split(/[^a-zA-Z0-9]+/).filter(Boolean);
19067
- if (parts.length === 0) return "unknown";
19068
- const [first = "", ...rest] = parts;
19069
- const camel = first.charAt(0).toLowerCase() + first.slice(1) + rest.map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("");
19070
- return /^[0-9]/.test(camel) ? `_${camel}` : camel;
19071
- }
19072
- function deriveMethodName2(operationId, method, path) {
19073
- if (operationId !== void 0 && operationId.length > 0) {
19074
- return sanitizeOperationId3(operationId);
19075
- }
19076
- return deriveOperationName3(method, path);
19077
- }
19078
- function deriveOperationName3(method, path) {
19079
- const prefixMap = {
19080
- get: "get",
19081
- post: "create",
19082
- put: "update",
19083
- patch: "patch",
19084
- delete: "delete"
19085
- };
19086
- const prefix = prefixMap[method] ?? method;
19087
- const segments = path.replace(/^\/api\/v\d+\//, "").replace(/^\//, "");
19088
- const parts = segments.split("/").map((seg) => {
19089
- const paramMatches = seg.match(/\{([^}]+)\}/g);
19090
- if (paramMatches !== null && !(seg.startsWith("{") && seg.endsWith("}"))) {
19091
- return paramMatches.map((m) => {
19092
- const name = sanitizeOperationId3(m.slice(1, -1));
19093
- return "By" + name.charAt(0).toUpperCase() + name.slice(1);
19094
- }).join("");
19095
- }
19096
- if (seg.startsWith("{") && seg.endsWith("}")) {
19097
- const name = seg.slice(1, -1);
19098
- const sanitized = sanitizeOperationId3(name);
19099
- return "By" + sanitized.charAt(0).toUpperCase() + sanitized.slice(1);
19100
- }
19101
- return toTypeName(seg);
19102
- });
19103
- return prefix + parts.join("");
19104
- }
19105
- function normalizeParamName2(name) {
19106
- const stripped = name.replace(/\[\]$/, "").replace(/'/g, "");
19107
- const parts = stripped.split(/[^a-zA-Z0-9]+/).filter(Boolean);
19108
- if (parts.length === 0) return "_";
19109
- const camel = parts.map((part, i) => i === 0 ? part : part[0].toUpperCase() + part.slice(1)).join("");
19110
- return /^[^a-zA-Z_$]/.test(camel) ? `_${camel}` : camel;
19111
- }
19112
- function schemaToTsType(schema) {
19113
- if (schema === void 0 || isRef4(schema)) return "string";
19114
- const s = schema;
19115
- if (s.type === "number" || s.type === "integer") return "number";
19116
- if (s.type === "boolean") return "boolean";
19117
- return "string";
19118
- }
19119
- function getQueryParams2(operation, spec) {
19120
- const parameters = operation.parameters;
19121
- if (parameters === void 0) return [];
19122
- const result = [];
19123
- for (const p of parameters) {
19124
- const resolved = resolveParam2(p, spec);
19125
- if (resolved === void 0 || resolved.in !== "query") continue;
19126
- const schema = resolved.schema;
19127
- result.push({
19128
- name: normalizeParamName2(resolved.name),
19129
- tsType: schemaToTsType(schema),
19130
- required: resolved.required === true
19131
- });
19132
- }
19133
- return result;
19134
- }
19135
19109
  function formatToZodModifier(format) {
19136
19110
  switch (format) {
19137
19111
  case "uuid":
@@ -19148,7 +19122,7 @@ function formatToZodModifier(format) {
19148
19122
  }
19149
19123
  }
19150
19124
  function pathParamZodExpr(schema) {
19151
- if (schema === void 0 || isRef4(schema)) return void 0;
19125
+ if (schema === void 0 || isRef3(schema)) return void 0;
19152
19126
  const s = schema;
19153
19127
  if (s.type !== "string") return void 0;
19154
19128
  const format = s.format;
@@ -19164,7 +19138,7 @@ function paramZodExpr(tsType, required, schema) {
19164
19138
  } else if (tsType === "boolean") {
19165
19139
  base = "z.boolean()";
19166
19140
  } else {
19167
- if (schema !== void 0 && !isRef4(schema)) {
19141
+ if (schema !== void 0 && !isRef3(schema)) {
19168
19142
  const s = schema;
19169
19143
  const format = s.format;
19170
19144
  const modifier = format !== void 0 ? formatToZodModifier(format) : "";
@@ -19180,7 +19154,7 @@ function getPathParamValidations(operation, spec, rawPathParamNames) {
19180
19154
  if (parameters === void 0) return [];
19181
19155
  const zodByName = /* @__PURE__ */ new Map();
19182
19156
  for (const p of parameters) {
19183
- const resolved = resolveParam2(p, spec);
19157
+ const resolved = resolveParam(p, spec);
19184
19158
  if (resolved === void 0 || resolved.in !== "path") continue;
19185
19159
  const schema = resolved.schema;
19186
19160
  const zodExpr = pathParamZodExpr(schema);
@@ -19198,7 +19172,7 @@ function getHeaderParams(operation, spec) {
19198
19172
  if (parameters === void 0) return [];
19199
19173
  const result = [];
19200
19174
  for (const p of parameters) {
19201
- const resolved = resolveParam2(p, spec);
19175
+ const resolved = resolveParam(p, spec);
19202
19176
  if (resolved === void 0 || resolved.in !== "header") continue;
19203
19177
  result.push({
19204
19178
  rawName: resolved.name,
@@ -19275,23 +19249,8 @@ function emitHeaderValidation(lines, headerParams, indent, framework) {
19275
19249
  lines.push(rawFields);
19276
19250
  lines.push(`${inner}})`);
19277
19251
  }
19278
- function getBodyInfo2(operation) {
19279
- const requestBody = operation.requestBody;
19280
- if (requestBody === void 0) return void 0;
19281
- if (isRef4(requestBody)) return { typeName: void 0 };
19282
- const rb = requestBody;
19283
- const content = rb.content;
19284
- if (content === void 0) return { typeName: void 0 };
19285
- const jsonContent = content["application/json"];
19286
- if (jsonContent === void 0 || jsonContent.schema === void 0) return { typeName: void 0 };
19287
- const schema = jsonContent.schema;
19288
- if (isRef4(schema)) {
19289
- return { typeName: refToName2(schema.$ref) };
19290
- }
19291
- return { typeName: void 0 };
19292
- }
19293
19252
  function response200IsVoid(resp) {
19294
- if (isRef4(resp)) return false;
19253
+ if (isRef3(resp)) return false;
19295
19254
  const r = resp;
19296
19255
  const content = r.content;
19297
19256
  return content === void 0 || Object.keys(content).length === 0;
@@ -19314,15 +19273,15 @@ function collectOperations2(spec) {
19314
19273
  if (paths === void 0) return [];
19315
19274
  const operations = [];
19316
19275
  for (const [path, pathItem] of Object.entries(paths)) {
19317
- for (const method of SUPPORTED_METHODS2) {
19276
+ for (const method of SUPPORTED_METHODS) {
19318
19277
  const operation = pathItem[method];
19319
19278
  if (operation === void 0) continue;
19320
- const methodName = deriveMethodName2(operation.operationId, method, path);
19321
- const pathParams = extractPathParamsFromPath2(path);
19279
+ const methodName = deriveMethodName(operation.operationId, method, path);
19280
+ const pathParams = extractPathParamsFromPath(path);
19322
19281
  const pathParamValidations = getPathParamValidations(operation, spec, pathParams);
19323
- const queryParams = getQueryParams2(operation, spec);
19282
+ const queryParams = getQueryParams(operation, spec);
19324
19283
  const headerParams = getHeaderParams(operation, spec);
19325
- const bodyInfo = getBodyInfo2(operation);
19284
+ const bodyInfo = getBodyInfo(operation);
19326
19285
  const responseStatus = getResponseStatus(operation, method);
19327
19286
  operations.push({
19328
19287
  methodName,
@@ -19628,7 +19587,7 @@ function operationsNeedZodForParams(operations) {
19628
19587
  return false;
19629
19588
  }
19630
19589
  function generateExpressRouter(spec, options) {
19631
- const serviceName = deriveServiceName2(spec);
19590
+ const serviceName = deriveServiceName(spec);
19632
19591
  const operations = collectOperations2(spec);
19633
19592
  const { sortedBodyTypes, usedSchemaNames, needsZod } = collectGeneratorSetup(operations, options);
19634
19593
  const lines = [];
@@ -19667,7 +19626,7 @@ function generateExpressRouter(spec, options) {
19667
19626
  };
19668
19627
  }
19669
19628
  function generateFastifyRouter(spec, options) {
19670
- const serviceName = deriveServiceName2(spec);
19629
+ const serviceName = deriveServiceName(spec);
19671
19630
  const operations = collectOperations2(spec);
19672
19631
  const { sortedBodyTypes, usedSchemaNames, needsZod } = collectGeneratorSetup(operations, options);
19673
19632
  const lines = [];
@@ -19699,7 +19658,7 @@ function generateFastifyRouter(spec, options) {
19699
19658
  };
19700
19659
  }
19701
19660
  function generateRouter(spec, options) {
19702
- const serviceName = deriveServiceName2(spec);
19661
+ const serviceName = deriveServiceName(spec);
19703
19662
  const operations = collectOperations2(spec);
19704
19663
  const { sortedBodyTypes, usedSchemaNames, needsZod } = collectGeneratorSetup(operations, options);
19705
19664
  const lines = [];
@@ -19740,63 +19699,63 @@ async function formatTs(content, filePath) {
19740
19699
  const config = await resolveConfig(filePath);
19741
19700
  return format(content, { ...config, parser: "typescript" });
19742
19701
  }
19743
- async function generate2(cwd, configPath) {
19744
- console.log("Loading config...");
19745
- const config = await loadConfig(cwd, configPath);
19702
+ function buildRouterFile(spec, framework, options) {
19703
+ if (framework === "hono") return generateRouter(spec, options);
19704
+ if (framework === "express") return generateExpressRouter(spec, options);
19705
+ return generateFastifyRouter(spec, options);
19706
+ }
19707
+ async function generateOne(cwd, config, label) {
19746
19708
  const inputPath = (0, import_node_path2.resolve)(cwd, config.input_openapi);
19747
19709
  const outputDir = (0, import_node_path2.resolve)(cwd, config.output);
19748
19710
  const framework = config.framework ?? "none";
19749
- console.log(`Parsing spec: ${inputPath}`);
19711
+ const prefix = label !== void 0 ? `[${label}] ` : "";
19712
+ console.log(`${prefix}Parsing spec: ${inputPath}`);
19750
19713
  const spec = await parseSpec(inputPath);
19751
- const generatedFiles = [];
19752
- generatedFiles.push(generateService(spec));
19753
- if (framework === "hono") {
19754
- generatedFiles.push(generateRouter(spec));
19755
- } else if (framework === "express") {
19756
- generatedFiles.push(generateExpressRouter(spec));
19757
- } else if (framework === "fastify") {
19758
- generatedFiles.push(generateFastifyRouter(spec));
19759
- }
19760
- console.log(`Writing output to: ${outputDir}`);
19714
+ const generatedFiles = [generateService(spec)];
19715
+ if (framework !== "none") {
19716
+ generatedFiles.push(buildRouterFile(spec, framework));
19717
+ }
19718
+ console.log(`${prefix}Writing output to: ${outputDir}`);
19761
19719
  await (0, import_promises2.mkdir)(outputDir, { recursive: true });
19762
19720
  for (const file of generatedFiles) {
19763
19721
  const filePath = (0, import_node_path2.join)(outputDir, file.filename);
19764
19722
  await (0, import_promises2.writeFile)(filePath, await formatTs(file.content, filePath), "utf-8");
19765
- console.log(` \u2713 ${file.filename}`);
19723
+ console.log(`${prefix} \u2713 ${file.filename}`);
19766
19724
  }
19767
- if ((framework === "hono" || framework === "express" || framework === "fastify") && config.input_schema !== void 0) {
19768
- const schemaPath = (0, import_node_path2.resolve)(cwd, config.input_schema);
19769
- let schemaContent;
19770
- try {
19771
- schemaContent = await (0, import_promises2.readFile)(schemaPath, "utf-8");
19772
- } catch {
19773
- console.log(` \u2139 input_schema not found at ${schemaPath}, skipping Zod validation`);
19774
- console.log(`Done! Generated ${generatedFiles.length} file(s).`);
19775
- return;
19776
- }
19777
- const exportedSchemas = /* @__PURE__ */ new Set();
19778
- for (const match of schemaContent.matchAll(/^export\s+const\s+(\w+Schema)\b/gm)) {
19779
- exportedSchemas.add(match[1]);
19780
- }
19781
- if (exportedSchemas.size > 0) {
19782
- const relPath = (0, import_node_path2.relative)(outputDir, schemaPath).replace(/\\/g, "/");
19783
- const schemaImportPath = relPath.startsWith(".") ? relPath : `./${relPath}`;
19784
- const schemaImportPathJs = schemaImportPath.replace(/\.ts$/, ".js");
19785
- const routerOptions = { schemaNames: exportedSchemas, schemaImportPath: schemaImportPathJs };
19786
- let routerFile;
19787
- if (framework === "hono") {
19788
- routerFile = generateRouter(spec, routerOptions);
19789
- } else if (framework === "express") {
19790
- routerFile = generateExpressRouter(spec, routerOptions);
19791
- } else {
19792
- routerFile = generateFastifyRouter(spec, routerOptions);
19793
- }
19794
- const routerPath = (0, import_node_path2.join)(outputDir, routerFile.filename);
19795
- await (0, import_promises2.writeFile)(routerPath, await formatTs(routerFile.content, routerPath), "utf-8");
19796
- console.log(` \u2713 router.ts (with Zod validation for ${exportedSchemas.size} schema(s))`);
19797
- }
19725
+ if (framework !== "none" && config.input_schema !== void 0) {
19726
+ await generateSchemaEnhancedRouter(cwd, config, spec, framework, outputDir, prefix);
19727
+ }
19728
+ console.log(`${prefix}Done! Generated ${generatedFiles.length} file(s).`);
19729
+ }
19730
+ async function generateSchemaEnhancedRouter(cwd, config, spec, framework, outputDir, prefix) {
19731
+ const schemaPath = (0, import_node_path2.resolve)(cwd, config.input_schema);
19732
+ let schemaContent;
19733
+ try {
19734
+ schemaContent = await (0, import_promises2.readFile)(schemaPath, "utf-8");
19735
+ } catch {
19736
+ console.log(`${prefix} input_schema not found at ${schemaPath}, skipping Zod validation`);
19737
+ return;
19798
19738
  }
19799
- console.log(`Done! Generated ${generatedFiles.length} file(s).`);
19739
+ const exportedSchemas = /* @__PURE__ */ new Set();
19740
+ for (const match of schemaContent.matchAll(/^export\s+const\s+(\w+Schema)\b/gm)) {
19741
+ exportedSchemas.add(match[1]);
19742
+ }
19743
+ if (exportedSchemas.size === 0) return;
19744
+ const relPath = (0, import_node_path2.relative)(outputDir, schemaPath).replace(/\\/g, "/");
19745
+ const schemaImportPath = relPath.startsWith(".") ? relPath : `./${relPath}`;
19746
+ const schemaImportPathJs = schemaImportPath.replace(/\.ts$/, ".js");
19747
+ const routerFile = buildRouterFile(spec, framework, {
19748
+ schemaNames: exportedSchemas,
19749
+ schemaImportPath: schemaImportPathJs
19750
+ });
19751
+ const routerPath = (0, import_node_path2.join)(outputDir, routerFile.filename);
19752
+ await (0, import_promises2.writeFile)(routerPath, await formatTs(routerFile.content, routerPath), "utf-8");
19753
+ console.log(`${prefix} \u2713 router.ts (with Zod validation for ${exportedSchemas.size} schema(s))`);
19754
+ }
19755
+ async function generate2(cwd, configPath) {
19756
+ console.log("Loading config...");
19757
+ const configs = await loadConfigs2(cwd, configPath);
19758
+ await runProjects(configs, (config, label) => generateOne(cwd, config, label));
19800
19759
  }
19801
19760
 
19802
19761
  // ../openapi-zod-ts/dist/cli-core.js
package/dist/config.d.ts CHANGED
@@ -11,4 +11,11 @@ export interface ServerConfig {
11
11
  input_schema?: string;
12
12
  }
13
13
  export declare function loadConfig(cwd: string, configPath?: string): Promise<ServerConfig>;
14
+ /**
15
+ * Load a config file and return all configs as a normalized array.
16
+ *
17
+ * Single-spec config: returns a one-element array.
18
+ * Multi-spec config with "projects" key: returns N-element array.
19
+ */
20
+ export declare function loadConfigs(cwd: string, configPath?: string): Promise<ServerConfig[]>;
14
21
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,4BAA4B,CAAA;AAEnC,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,CAAA;AAEpE,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,aAAa,EAAE,MAAM,CAAA;IACrB,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAA;IACd,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAA;IACnD,iGAAiG;IACjG,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CA8BxF"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,4BAA4B,CAAA;AAEnC,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,CAAA;AAEpE,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,aAAa,EAAE,MAAM,CAAA;IACrB,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAA;IACd,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAA;IACnD,iGAAiG;IACjG,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AA6BD,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAOxF;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAO3F"}