@codewithagents/openapi-server 1.6.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/README.md +6 -6
- package/dist/cli-args.d.ts +1 -1
- package/dist/cli-args.d.ts.map +1 -1
- package/dist/cli-args.js +1 -1
- package/dist/cli-args.js.map +1 -1
- package/dist/cli.cjs +213 -254
- package/dist/config.d.ts +9 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +35 -21
- package/dist/config.js.map +1 -1
- package/dist/generator.d.ts.map +1 -1
- package/dist/generator.js +58 -63
- package/dist/generator.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/plugins/router.d.ts +1 -1
- package/dist/plugins/router.d.ts.map +1 -1
- package/dist/plugins/router.js +1 -167
- package/dist/plugins/router.js.map +1 -1
- package/dist/plugins/service.d.ts +1 -1
- package/dist/plugins/service.d.ts.map +1 -1
- package/dist/plugins/service.js +4 -172
- package/dist/plugins/service.js.map +1 -1
- package/dist/plugins/shared.d.ts +44 -0
- package/dist/plugins/shared.d.ts.map +1 -0
- package/dist/plugins/shared.js +180 -0
- package/dist/plugins/shared.js.map +1 -0
- package/package.json +2 -2
package/dist/cli.cjs
CHANGED
|
@@ -18414,7 +18414,7 @@ var import_node_path4 = require("node:path");
|
|
|
18414
18414
|
var import_promises2 = require("node:fs/promises");
|
|
18415
18415
|
var import_node_path2 = require("node:path");
|
|
18416
18416
|
|
|
18417
|
-
// ../openapi-
|
|
18417
|
+
// ../openapi-zod-ts/dist/config-core.js
|
|
18418
18418
|
var import_promises = require("node:fs/promises");
|
|
18419
18419
|
var import_node_path = require("node:path");
|
|
18420
18420
|
var import_node_url = require("node:url");
|
|
@@ -18475,44 +18475,46 @@ function validateInputPath(resolvedInput) {
|
|
|
18475
18475
|
}
|
|
18476
18476
|
}
|
|
18477
18477
|
}
|
|
18478
|
-
async function
|
|
18479
|
-
|
|
18480
|
-
|
|
18481
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,40 +18523,86 @@ ${message}`);
|
|
|
18521
18523
|
}
|
|
18522
18524
|
const input_openapi = raw["input_openapi"];
|
|
18523
18525
|
const output = raw["output"];
|
|
18524
|
-
validateInputPath((0, import_node_path.resolve)(
|
|
18525
|
-
validateOutputPath((0, import_node_path.resolve)(
|
|
18526
|
-
|
|
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
|
-
|
|
18531
|
-
|
|
18532
|
-
|
|
18533
|
-
|
|
18534
|
-
|
|
18535
|
-
|
|
18536
|
-
|
|
18537
|
-
|
|
18538
|
-
|
|
18539
|
-
|
|
18540
|
-
|
|
18541
|
-
|
|
18542
|
-
|
|
18543
|
-
|
|
18544
|
-
|
|
18545
|
-
|
|
18546
|
-
|
|
18547
|
-
|
|
18548
|
-
|
|
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
|
-
// ../openapi-
|
|
18602
|
+
// ../openapi-zod-ts/dist/parser.js
|
|
18555
18603
|
var import_swagger_parser = __toESM(require_lib4(), 1);
|
|
18556
18604
|
|
|
18557
|
-
// ../openapi-
|
|
18605
|
+
// ../openapi-zod-ts/dist/utils/schema-depth.js
|
|
18558
18606
|
var MAX_SCHEMA_DEPTH = 100;
|
|
18559
18607
|
function isRef(schema) {
|
|
18560
18608
|
return "$ref" in schema;
|
|
@@ -18594,7 +18642,7 @@ function assertBoundedDepth(root) {
|
|
|
18594
18642
|
}
|
|
18595
18643
|
}
|
|
18596
18644
|
|
|
18597
|
-
// ../openapi-
|
|
18645
|
+
// ../openapi-zod-ts/dist/utils/normalize-nullable.js
|
|
18598
18646
|
function isRef2(schema) {
|
|
18599
18647
|
return "$ref" in schema;
|
|
18600
18648
|
}
|
|
@@ -18765,7 +18813,7 @@ function normalizeNullable(spec) {
|
|
|
18765
18813
|
walkPathSchemas(spec, visited);
|
|
18766
18814
|
}
|
|
18767
18815
|
|
|
18768
|
-
// ../openapi-
|
|
18816
|
+
// ../openapi-zod-ts/dist/parser.js
|
|
18769
18817
|
async function parseSpec(inputPath) {
|
|
18770
18818
|
const api = await import_swagger_parser.default.bundle(inputPath);
|
|
18771
18819
|
for (const schema of Object.values(api.components?.schemas ?? {})) {
|
|
@@ -18775,7 +18823,7 @@ async function parseSpec(inputPath) {
|
|
|
18775
18823
|
return api;
|
|
18776
18824
|
}
|
|
18777
18825
|
|
|
18778
|
-
// ../openapi-
|
|
18826
|
+
// ../openapi-zod-ts/dist/utils/naming.js
|
|
18779
18827
|
function toTypeName(name) {
|
|
18780
18828
|
const parts = name.split(/[^a-zA-Z0-9]+/).filter(Boolean);
|
|
18781
18829
|
if (parts.length === 0)
|
|
@@ -18787,7 +18835,31 @@ function toTypeName(name) {
|
|
|
18787
18835
|
return safe.length > 0 ? safe : "_";
|
|
18788
18836
|
}
|
|
18789
18837
|
|
|
18790
|
-
// src/
|
|
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) =>
|
|
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 ||
|
|
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 && !
|
|
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 =
|
|
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 =
|
|
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 (
|
|
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
|
|
19276
|
+
for (const method of SUPPORTED_METHODS) {
|
|
19318
19277
|
const operation = pathItem[method];
|
|
19319
19278
|
if (operation === void 0) continue;
|
|
19320
|
-
const methodName =
|
|
19321
|
-
const pathParams =
|
|
19279
|
+
const methodName = deriveMethodName(operation.operationId, method, path);
|
|
19280
|
+
const pathParams = extractPathParamsFromPath(path);
|
|
19322
19281
|
const pathParamValidations = getPathParamValidations(operation, spec, pathParams);
|
|
19323
|
-
const queryParams =
|
|
19282
|
+
const queryParams = getQueryParams(operation, spec);
|
|
19324
19283
|
const headerParams = getHeaderParams(operation, spec);
|
|
19325
|
-
const bodyInfo =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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,66 +19699,66 @@ async function formatTs(content, filePath) {
|
|
|
19740
19699
|
const config = await resolveConfig(filePath);
|
|
19741
19700
|
return format(content, { ...config, parser: "typescript" });
|
|
19742
19701
|
}
|
|
19743
|
-
|
|
19744
|
-
|
|
19745
|
-
|
|
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
|
-
|
|
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
|
-
|
|
19753
|
-
|
|
19754
|
-
|
|
19755
|
-
}
|
|
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(
|
|
19723
|
+
console.log(`${prefix} \u2713 ${file.filename}`);
|
|
19766
19724
|
}
|
|
19767
|
-
if (
|
|
19768
|
-
|
|
19769
|
-
|
|
19770
|
-
|
|
19771
|
-
|
|
19772
|
-
|
|
19773
|
-
|
|
19774
|
-
|
|
19775
|
-
|
|
19776
|
-
|
|
19777
|
-
|
|
19778
|
-
|
|
19779
|
-
|
|
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
|
-
|
|
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
|
-
// ../openapi-
|
|
19761
|
+
// ../openapi-zod-ts/dist/cli-core.js
|
|
19803
19762
|
var import_node_path3 = require("node:path");
|
|
19804
19763
|
function parseBaseCliArgs(argv, cwd, usage) {
|
|
19805
19764
|
const args = argv.slice(2);
|
package/dist/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { validateConfigPath, validateInputPath, validateOutputPath } from '
|
|
1
|
+
import { validateConfigPath, validateInputPath, validateOutputPath } from 'openapi-zod-ts/config-core';
|
|
2
2
|
export { validateConfigPath, validateInputPath, validateOutputPath };
|
|
3
3
|
export interface ServerConfig {
|
|
4
4
|
/** Path to the OpenAPI 3.1 spec file (JSON or YAML) */
|
|
@@ -7,8 +7,15 @@ export interface ServerConfig {
|
|
|
7
7
|
output: string;
|
|
8
8
|
/** Framework to generate a router for. Default: 'none' */
|
|
9
9
|
framework?: 'hono' | 'express' | 'fastify' | 'none';
|
|
10
|
-
/** Path to user-owned Zod schema file (same file as openapi-
|
|
10
|
+
/** Path to user-owned Zod schema file (same file as openapi-zod-ts's input_schema). Optional. */
|
|
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
|