@codewithagents/openapi-server 1.8.0 → 1.9.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 +551 -105
- package/dist/plugins/router.d.ts.map +1 -1
- package/dist/plugins/router.js +543 -93
- package/dist/plugins/router.js.map +1 -1
- package/dist/plugins/service.d.ts.map +1 -1
- package/dist/plugins/service.js +67 -24
- package/dist/plugins/service.js.map +1 -1
- package/dist/plugins/shared.d.ts +46 -0
- package/dist/plugins/shared.d.ts.map +1 -1
- package/dist/plugins/shared.js +122 -12
- package/dist/plugins/shared.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.cjs
CHANGED
|
@@ -18953,35 +18953,131 @@ function getQueryParams(operation, spec) {
|
|
|
18953
18953
|
const resolved = resolveParam(p, spec);
|
|
18954
18954
|
if (resolved === void 0 || resolved.in !== "query") continue;
|
|
18955
18955
|
const schema = resolved.schema;
|
|
18956
|
-
|
|
18956
|
+
const resolvedStyle = resolved.style;
|
|
18957
|
+
const resolvedExplode = resolved.explode;
|
|
18958
|
+
const param = {
|
|
18957
18959
|
name: normalizeParamName(resolved.name),
|
|
18960
|
+
rawName: resolved.name,
|
|
18958
18961
|
tsType: schemaToTsType(schema),
|
|
18959
18962
|
required: resolved.required === true
|
|
18960
|
-
}
|
|
18963
|
+
};
|
|
18964
|
+
if (resolvedStyle === "deepObject" && schema !== void 0 && !isRef3(schema)) {
|
|
18965
|
+
const s = schema;
|
|
18966
|
+
if (s.type === "object" && s.properties !== void 0) {
|
|
18967
|
+
param.isDeepObject = true;
|
|
18968
|
+
param.deepObjectProperties = Object.entries(s.properties).map(([key, propSchema]) => ({
|
|
18969
|
+
key,
|
|
18970
|
+
tsType: schemaToTsType(propSchema)
|
|
18971
|
+
}));
|
|
18972
|
+
}
|
|
18973
|
+
}
|
|
18974
|
+
if (!param.isDeepObject && schema !== void 0 && !isRef3(schema) && schema.type === "array" && resolvedExplode === false) {
|
|
18975
|
+
if (resolvedStyle === "spaceDelimited") {
|
|
18976
|
+
param.delimiterStyle = "ssv";
|
|
18977
|
+
} else if (resolvedStyle === "pipeDelimited") {
|
|
18978
|
+
param.delimiterStyle = "psv";
|
|
18979
|
+
} else {
|
|
18980
|
+
param.delimiterStyle = "csv";
|
|
18981
|
+
}
|
|
18982
|
+
}
|
|
18983
|
+
if (schema !== void 0 && !isRef3(schema)) {
|
|
18984
|
+
const s = schema;
|
|
18985
|
+
if (Array.isArray(s.enum)) param.enum = s.enum;
|
|
18986
|
+
if (typeof s.minimum === "number") param.minimum = s.minimum;
|
|
18987
|
+
if (typeof s.maximum === "number") param.maximum = s.maximum;
|
|
18988
|
+
if (typeof s.exclusiveMinimum === "number") param.exclusiveMinimum = s.exclusiveMinimum;
|
|
18989
|
+
if (typeof s.exclusiveMaximum === "number") param.exclusiveMaximum = s.exclusiveMaximum;
|
|
18990
|
+
if (typeof s.minLength === "number") param.minLength = s.minLength;
|
|
18991
|
+
if (typeof s.maxLength === "number") param.maxLength = s.maxLength;
|
|
18992
|
+
if (typeof s.pattern === "string") param.pattern = s.pattern;
|
|
18993
|
+
}
|
|
18994
|
+
result.push(param);
|
|
18961
18995
|
}
|
|
18962
18996
|
return result;
|
|
18963
18997
|
}
|
|
18964
18998
|
function getBodyInfo(operation) {
|
|
18965
18999
|
const requestBody = operation.requestBody;
|
|
18966
19000
|
if (requestBody === void 0) return void 0;
|
|
18967
|
-
if (isRef3(requestBody))
|
|
19001
|
+
if (isRef3(requestBody)) {
|
|
19002
|
+
return { typeName: void 0, contentType: "application/json", isSynthesized: false };
|
|
19003
|
+
}
|
|
18968
19004
|
const rb = requestBody;
|
|
18969
19005
|
const content = rb.content;
|
|
18970
|
-
if (content === void 0)
|
|
19006
|
+
if (content === void 0) {
|
|
19007
|
+
return { typeName: void 0, contentType: "application/json", isSynthesized: false };
|
|
19008
|
+
}
|
|
18971
19009
|
const jsonContent = content["application/json"];
|
|
18972
|
-
if (jsonContent
|
|
18973
|
-
|
|
18974
|
-
|
|
18975
|
-
|
|
19010
|
+
if (jsonContent !== void 0 && jsonContent.schema !== void 0) {
|
|
19011
|
+
const schema = jsonContent.schema;
|
|
19012
|
+
if (isRef3(schema)) {
|
|
19013
|
+
return {
|
|
19014
|
+
typeName: refToName(schema.$ref),
|
|
19015
|
+
contentType: "application/json",
|
|
19016
|
+
isSynthesized: false
|
|
19017
|
+
};
|
|
19018
|
+
}
|
|
19019
|
+
const operationId = operation.operationId;
|
|
19020
|
+
if (operationId !== void 0 && operationId.length > 0) {
|
|
19021
|
+
return { typeName: toTypeName(operationId), contentType: "application/json", isSynthesized: true };
|
|
19022
|
+
}
|
|
19023
|
+
return { typeName: void 0, contentType: "application/json", isSynthesized: false };
|
|
18976
19024
|
}
|
|
18977
|
-
|
|
19025
|
+
const formContent = content["application/x-www-form-urlencoded"];
|
|
19026
|
+
if (formContent !== void 0) {
|
|
19027
|
+
const schema = formContent.schema;
|
|
19028
|
+
if (schema !== void 0 && isRef3(schema)) {
|
|
19029
|
+
return {
|
|
19030
|
+
typeName: refToName(schema.$ref),
|
|
19031
|
+
contentType: "application/x-www-form-urlencoded",
|
|
19032
|
+
isSynthesized: false
|
|
19033
|
+
};
|
|
19034
|
+
}
|
|
19035
|
+
const operationId = operation.operationId;
|
|
19036
|
+
if (operationId !== void 0 && operationId.length > 0) {
|
|
19037
|
+
return {
|
|
19038
|
+
typeName: toTypeName(operationId),
|
|
19039
|
+
contentType: "application/x-www-form-urlencoded",
|
|
19040
|
+
isSynthesized: true
|
|
19041
|
+
};
|
|
19042
|
+
}
|
|
19043
|
+
return { typeName: void 0, contentType: "application/x-www-form-urlencoded", isSynthesized: false };
|
|
19044
|
+
}
|
|
19045
|
+
const multipartContent = content["multipart/form-data"];
|
|
19046
|
+
if (multipartContent !== void 0) {
|
|
19047
|
+
const schema = multipartContent.schema;
|
|
19048
|
+
if (schema !== void 0 && isRef3(schema)) {
|
|
19049
|
+
return {
|
|
19050
|
+
typeName: refToName(schema.$ref),
|
|
19051
|
+
contentType: "multipart/form-data",
|
|
19052
|
+
isSynthesized: false
|
|
19053
|
+
};
|
|
19054
|
+
}
|
|
19055
|
+
const operationId = operation.operationId;
|
|
19056
|
+
if (operationId !== void 0 && operationId.length > 0) {
|
|
19057
|
+
return {
|
|
19058
|
+
typeName: toTypeName(operationId),
|
|
19059
|
+
contentType: "multipart/form-data",
|
|
19060
|
+
isSynthesized: true
|
|
19061
|
+
};
|
|
19062
|
+
}
|
|
19063
|
+
return { typeName: void 0, contentType: "multipart/form-data", isSynthesized: false };
|
|
19064
|
+
}
|
|
19065
|
+
return { typeName: void 0, contentType: "application/json", isSynthesized: false };
|
|
18978
19066
|
}
|
|
18979
19067
|
|
|
18980
19068
|
// src/plugins/service.ts
|
|
19069
|
+
function collectContentfulTwoxxCodes(responses) {
|
|
19070
|
+
return Object.keys(responses).filter((k) => /^2\d\d$/.test(k) && k !== "204").sort();
|
|
19071
|
+
}
|
|
18981
19072
|
function getReturnInfo(operation) {
|
|
18982
19073
|
const responses = operation.responses;
|
|
18983
19074
|
if (responses === void 0) return { typeName: void 0, isArray: false, isVoid: true };
|
|
18984
|
-
|
|
19075
|
+
const contentfulCodes = collectContentfulTwoxxCodes(responses);
|
|
19076
|
+
const isMultiStatus = contentfulCodes.length > 1;
|
|
19077
|
+
const twoxxCodes = ["200", "201", ...Object.keys(responses).filter(
|
|
19078
|
+
(k) => /^2\d\d$/.test(k) && k !== "200" && k !== "201" && k !== "204"
|
|
19079
|
+
)];
|
|
19080
|
+
for (const code of twoxxCodes) {
|
|
18985
19081
|
const response = responses[code];
|
|
18986
19082
|
if (response === void 0) continue;
|
|
18987
19083
|
if (isRef3(response)) continue;
|
|
@@ -18989,28 +19085,37 @@ function getReturnInfo(operation) {
|
|
|
18989
19085
|
const content = resp.content;
|
|
18990
19086
|
if (content === void 0) continue;
|
|
18991
19087
|
const jsonContent = content["application/json"];
|
|
18992
|
-
if (jsonContent
|
|
18993
|
-
|
|
18994
|
-
|
|
18995
|
-
return {
|
|
18996
|
-
typeName: refToName(schema.$ref),
|
|
18997
|
-
isArray: false,
|
|
18998
|
-
isVoid: false
|
|
18999
|
-
};
|
|
19000
|
-
}
|
|
19001
|
-
const s = schema;
|
|
19002
|
-
if (s.type === "array") {
|
|
19003
|
-
const items = s.items;
|
|
19004
|
-
if (items !== void 0 && isRef3(items)) {
|
|
19088
|
+
if (jsonContent !== void 0 && jsonContent.schema !== void 0) {
|
|
19089
|
+
const schema = jsonContent.schema;
|
|
19090
|
+
if (isRef3(schema)) {
|
|
19005
19091
|
return {
|
|
19006
|
-
typeName: refToName(
|
|
19007
|
-
isArray:
|
|
19008
|
-
isVoid: false
|
|
19092
|
+
typeName: refToName(schema.$ref),
|
|
19093
|
+
isArray: false,
|
|
19094
|
+
isVoid: false,
|
|
19095
|
+
isMultiStatus
|
|
19009
19096
|
};
|
|
19010
19097
|
}
|
|
19011
|
-
|
|
19098
|
+
const s = schema;
|
|
19099
|
+
if (s.type === "array") {
|
|
19100
|
+
const items = s.items;
|
|
19101
|
+
if (items !== void 0 && isRef3(items)) {
|
|
19102
|
+
return {
|
|
19103
|
+
typeName: refToName(items.$ref),
|
|
19104
|
+
isArray: true,
|
|
19105
|
+
isVoid: false,
|
|
19106
|
+
isMultiStatus
|
|
19107
|
+
};
|
|
19108
|
+
}
|
|
19109
|
+
return { typeName: void 0, isArray: true, isVoid: false, isMultiStatus };
|
|
19110
|
+
}
|
|
19111
|
+
return { typeName: void 0, isArray: false, isVoid: false, isMultiStatus };
|
|
19112
|
+
}
|
|
19113
|
+
if (content["text/plain"] !== void 0) {
|
|
19114
|
+
return { typeName: void 0, isArray: false, isVoid: false, primitiveType: "string" };
|
|
19115
|
+
}
|
|
19116
|
+
if (content["application/octet-stream"] !== void 0) {
|
|
19117
|
+
return { typeName: void 0, isArray: false, isVoid: false, primitiveType: "Uint8Array" };
|
|
19012
19118
|
}
|
|
19013
|
-
return { typeName: void 0, isArray: false, isVoid: false };
|
|
19014
19119
|
}
|
|
19015
19120
|
if (responses["204"] !== void 0) {
|
|
19016
19121
|
return { typeName: void 0, isArray: false, isVoid: true };
|
|
@@ -19019,6 +19124,16 @@ function getReturnInfo(operation) {
|
|
|
19019
19124
|
}
|
|
19020
19125
|
function buildReturnType(info) {
|
|
19021
19126
|
if (info.isVoid) return "Promise<void>";
|
|
19127
|
+
if (info.primitiveType !== void 0) return `Promise<${info.primitiveType}>`;
|
|
19128
|
+
if (info.isMultiStatus === true) {
|
|
19129
|
+
let bodyType;
|
|
19130
|
+
if (info.typeName !== void 0) {
|
|
19131
|
+
bodyType = info.isArray ? `${info.typeName}[]` : info.typeName;
|
|
19132
|
+
} else {
|
|
19133
|
+
bodyType = info.isArray ? "unknown[]" : "unknown";
|
|
19134
|
+
}
|
|
19135
|
+
return `Promise<{ status: number; body: ${bodyType} }>`;
|
|
19136
|
+
}
|
|
19022
19137
|
if (info.typeName !== void 0) {
|
|
19023
19138
|
return info.isArray ? `Promise<${info.typeName}[]>` : `Promise<${info.typeName}>`;
|
|
19024
19139
|
}
|
|
@@ -19056,7 +19171,7 @@ function buildMethodSignature(op) {
|
|
|
19056
19171
|
args.push(`${sanitizeOperationId2(p)}: string`);
|
|
19057
19172
|
}
|
|
19058
19173
|
if (op.bodyInfo !== void 0) {
|
|
19059
|
-
const typeName = op.bodyInfo.typeName
|
|
19174
|
+
const typeName = op.bodyInfo.typeName !== void 0 && !op.bodyInfo.isSynthesized ? op.bodyInfo.typeName : "unknown";
|
|
19060
19175
|
args.push(`body: ${typeName}`);
|
|
19061
19176
|
}
|
|
19062
19177
|
if (op.queryParams.length > 0) {
|
|
@@ -19074,7 +19189,7 @@ function generateService(spec) {
|
|
|
19074
19189
|
const operations = collectOperations(spec);
|
|
19075
19190
|
const importTypes = /* @__PURE__ */ new Set();
|
|
19076
19191
|
for (const op of operations) {
|
|
19077
|
-
if (op.bodyInfo?.typeName !== void 0) {
|
|
19192
|
+
if (op.bodyInfo?.typeName !== void 0 && !op.bodyInfo.isSynthesized) {
|
|
19078
19193
|
importTypes.add(op.bodyInfo.typeName);
|
|
19079
19194
|
}
|
|
19080
19195
|
if (op.returnInfo.typeName !== void 0) {
|
|
@@ -19124,6 +19239,21 @@ function formatToZodModifier(format) {
|
|
|
19124
19239
|
function pathParamZodExpr(schema) {
|
|
19125
19240
|
if (schema === void 0 || isRef3(schema)) return void 0;
|
|
19126
19241
|
const s = schema;
|
|
19242
|
+
if (s.type === "integer" || s.type === "number") {
|
|
19243
|
+
const hasMin = typeof s.minimum === "number";
|
|
19244
|
+
const hasMax = typeof s.maximum === "number";
|
|
19245
|
+
const hasExcMin = typeof s.exclusiveMinimum === "number";
|
|
19246
|
+
const hasExcMax = typeof s.exclusiveMaximum === "number";
|
|
19247
|
+
if (hasMin || hasMax || hasExcMin || hasExcMax) {
|
|
19248
|
+
let expr = "z.coerce.number()";
|
|
19249
|
+
if (hasMin) expr += `.min(${s.minimum})`;
|
|
19250
|
+
if (hasMax) expr += `.max(${s.maximum})`;
|
|
19251
|
+
if (hasExcMin) expr += `.gt(${s.exclusiveMinimum})`;
|
|
19252
|
+
if (hasExcMax) expr += `.lt(${s.exclusiveMaximum})`;
|
|
19253
|
+
return expr;
|
|
19254
|
+
}
|
|
19255
|
+
return void 0;
|
|
19256
|
+
}
|
|
19127
19257
|
if (s.type !== "string") return void 0;
|
|
19128
19258
|
const format = s.format;
|
|
19129
19259
|
if (format === void 0) return void 0;
|
|
@@ -19131,23 +19261,64 @@ function pathParamZodExpr(schema) {
|
|
|
19131
19261
|
if (modifier === "") return void 0;
|
|
19132
19262
|
return `z.string()${modifier}`;
|
|
19133
19263
|
}
|
|
19134
|
-
function
|
|
19264
|
+
function queryParamDelimitedZodBase(_param) {
|
|
19265
|
+
return "z.array(z.string())";
|
|
19266
|
+
}
|
|
19267
|
+
function queryParamDeepObjectZodBase(param) {
|
|
19268
|
+
const propFields = (param.deepObjectProperties ?? []).map((p) => {
|
|
19269
|
+
const coerced = p.tsType === "number" ? "z.coerce.number()" : "z.string()";
|
|
19270
|
+
return `${p.key}: ${coerced}.optional()`;
|
|
19271
|
+
});
|
|
19272
|
+
return `z.object({ ${propFields.join(", ")} })`;
|
|
19273
|
+
}
|
|
19274
|
+
function queryParamNumberZodBase(param) {
|
|
19275
|
+
let base = "z.number()";
|
|
19276
|
+
if (param.minimum !== void 0) base += `.min(${param.minimum})`;
|
|
19277
|
+
if (param.maximum !== void 0) base += `.max(${param.maximum})`;
|
|
19278
|
+
if (param.exclusiveMinimum !== void 0) base += `.gt(${param.exclusiveMinimum})`;
|
|
19279
|
+
if (param.exclusiveMaximum !== void 0) base += `.lt(${param.exclusiveMaximum})`;
|
|
19280
|
+
return base;
|
|
19281
|
+
}
|
|
19282
|
+
function queryParamStringZodBase(param) {
|
|
19135
19283
|
let base;
|
|
19136
|
-
if (
|
|
19137
|
-
|
|
19138
|
-
|
|
19284
|
+
if (param.enum !== void 0 && param.enum.length > 0) {
|
|
19285
|
+
const members = param.enum.map((v) => JSON.stringify(v)).join(", ");
|
|
19286
|
+
base = `z.enum([${members}])`;
|
|
19287
|
+
} else {
|
|
19288
|
+
base = "z.string()";
|
|
19289
|
+
}
|
|
19290
|
+
if (param.minLength !== void 0) base += `.min(${param.minLength})`;
|
|
19291
|
+
if (param.maxLength !== void 0) base += `.max(${param.maxLength})`;
|
|
19292
|
+
if (param.pattern !== void 0) base += `.regex(/${param.pattern}/)`;
|
|
19293
|
+
return base;
|
|
19294
|
+
}
|
|
19295
|
+
function queryParamZodExpr(param) {
|
|
19296
|
+
let base;
|
|
19297
|
+
if (param.delimiterStyle !== void 0) {
|
|
19298
|
+
base = queryParamDelimitedZodBase(param);
|
|
19299
|
+
} else if (param.isDeepObject === true && param.deepObjectProperties !== void 0) {
|
|
19300
|
+
base = queryParamDeepObjectZodBase(param);
|
|
19301
|
+
} else if (param.tsType === "number") {
|
|
19302
|
+
base = queryParamNumberZodBase(param);
|
|
19303
|
+
} else if (param.tsType === "boolean") {
|
|
19139
19304
|
base = "z.boolean()";
|
|
19140
19305
|
} else {
|
|
19141
|
-
|
|
19142
|
-
|
|
19143
|
-
|
|
19144
|
-
|
|
19145
|
-
|
|
19146
|
-
|
|
19147
|
-
|
|
19148
|
-
|
|
19306
|
+
base = queryParamStringZodBase(param);
|
|
19307
|
+
}
|
|
19308
|
+
return param.required ? base : `${base}.optional()`;
|
|
19309
|
+
}
|
|
19310
|
+
function headerParamZodExpr(param) {
|
|
19311
|
+
let base;
|
|
19312
|
+
if (param.enum !== void 0 && param.enum.length > 0) {
|
|
19313
|
+
const members = param.enum.map((v) => JSON.stringify(v)).join(", ");
|
|
19314
|
+
base = `z.enum([${members}])`;
|
|
19315
|
+
} else {
|
|
19316
|
+
base = "z.string()";
|
|
19149
19317
|
}
|
|
19150
|
-
|
|
19318
|
+
if (param.minLength !== void 0) base += `.min(${param.minLength})`;
|
|
19319
|
+
if (param.maxLength !== void 0) base += `.max(${param.maxLength})`;
|
|
19320
|
+
if (param.pattern !== void 0) base += `.regex(/${param.pattern}/)`;
|
|
19321
|
+
return param.required ? base : `${base}.optional()`;
|
|
19151
19322
|
}
|
|
19152
19323
|
function getPathParamValidations(operation, spec, rawPathParamNames) {
|
|
19153
19324
|
const parameters = operation.parameters;
|
|
@@ -19174,21 +19345,51 @@ function getHeaderParams(operation, spec) {
|
|
|
19174
19345
|
for (const p of parameters) {
|
|
19175
19346
|
const resolved = resolveParam(p, spec);
|
|
19176
19347
|
if (resolved === void 0 || resolved.in !== "header") continue;
|
|
19177
|
-
|
|
19348
|
+
const param = {
|
|
19178
19349
|
rawName: resolved.name,
|
|
19179
19350
|
required: resolved.required === true
|
|
19180
|
-
}
|
|
19351
|
+
};
|
|
19352
|
+
const schema = resolved.schema;
|
|
19353
|
+
if (schema !== void 0 && !isRef3(schema)) {
|
|
19354
|
+
const s = schema;
|
|
19355
|
+
if (Array.isArray(s.enum)) param.enum = s.enum;
|
|
19356
|
+
if (typeof s.minLength === "number") param.minLength = s.minLength;
|
|
19357
|
+
if (typeof s.maxLength === "number") param.maxLength = s.maxLength;
|
|
19358
|
+
if (typeof s.pattern === "string") param.pattern = s.pattern;
|
|
19359
|
+
}
|
|
19360
|
+
result.push(param);
|
|
19181
19361
|
}
|
|
19182
19362
|
return result;
|
|
19183
19363
|
}
|
|
19364
|
+
function queryParamHasConstraints(q) {
|
|
19365
|
+
const constraintFields = [
|
|
19366
|
+
q.enum,
|
|
19367
|
+
q.minimum,
|
|
19368
|
+
q.maximum,
|
|
19369
|
+
q.exclusiveMinimum,
|
|
19370
|
+
q.exclusiveMaximum,
|
|
19371
|
+
q.minLength,
|
|
19372
|
+
q.maxLength,
|
|
19373
|
+
q.pattern,
|
|
19374
|
+
q.delimiterStyle
|
|
19375
|
+
];
|
|
19376
|
+
return constraintFields.some((f) => f !== void 0) || q.isDeepObject === true;
|
|
19377
|
+
}
|
|
19184
19378
|
function queryParamsNeedValidation(queryParams) {
|
|
19185
|
-
return queryParams.some(
|
|
19379
|
+
return queryParams.some(
|
|
19380
|
+
(q) => q.required || q.tsType !== "string" || queryParamHasConstraints(q)
|
|
19381
|
+
);
|
|
19382
|
+
}
|
|
19383
|
+
function delimiterChar(style) {
|
|
19384
|
+
if (style === "ssv") return " ";
|
|
19385
|
+
if (style === "psv") return "|";
|
|
19386
|
+
return ",";
|
|
19186
19387
|
}
|
|
19187
19388
|
function emitQueryValidation(lines, queryParams, indent) {
|
|
19188
19389
|
const inner = `${indent} `;
|
|
19189
19390
|
const fieldIndent = `${indent} `;
|
|
19190
19391
|
const fields = queryParams.map((q) => {
|
|
19191
|
-
const expr =
|
|
19392
|
+
const expr = queryParamZodExpr(q);
|
|
19192
19393
|
return `${fieldIndent}${q.name}: ${expr}`;
|
|
19193
19394
|
}).join(",\n");
|
|
19194
19395
|
lines.push(`${inner}// Validate query parameters: returns 422 with Zod issues on failure`);
|
|
@@ -19227,7 +19428,7 @@ function emitHeaderValidation(lines, headerParams, indent, framework) {
|
|
|
19227
19428
|
const fieldIndent = `${indent} `;
|
|
19228
19429
|
const schemaFields = headerParams.map((h) => {
|
|
19229
19430
|
const key = JSON.stringify(h.rawName);
|
|
19230
|
-
const expr = h
|
|
19431
|
+
const expr = headerParamZodExpr(h);
|
|
19231
19432
|
return `${fieldIndent}${key}: ${expr}`;
|
|
19232
19433
|
}).join(",\n");
|
|
19233
19434
|
const rawFields = headerParams.map((h) => {
|
|
@@ -19255,18 +19456,63 @@ function response200IsVoid(resp) {
|
|
|
19255
19456
|
const content = r.content;
|
|
19256
19457
|
return content === void 0 || Object.keys(content).length === 0;
|
|
19257
19458
|
}
|
|
19459
|
+
function detectResponseContentType(resp) {
|
|
19460
|
+
if (isRef3(resp)) return "application/json";
|
|
19461
|
+
const r = resp;
|
|
19462
|
+
const content = r.content;
|
|
19463
|
+
if (content === void 0) return "application/json";
|
|
19464
|
+
if ("text/plain" in content) return "text/plain";
|
|
19465
|
+
if ("application/octet-stream" in content) return "application/octet-stream";
|
|
19466
|
+
return "application/json";
|
|
19467
|
+
}
|
|
19258
19468
|
function getResponseStatus(operation, httpMethod) {
|
|
19259
19469
|
const responses = operation.responses;
|
|
19260
19470
|
if (responses === void 0) {
|
|
19261
|
-
return httpMethod === "delete" ? { status: 204, isVoid: true } : { status: 200, isVoid: false };
|
|
19471
|
+
return httpMethod === "delete" ? { status: 204, isVoid: true, responseContentType: "application/json" } : { status: 200, isVoid: false, responseContentType: "application/json" };
|
|
19472
|
+
}
|
|
19473
|
+
const contentfulTwoxxKeys = Object.keys(responses).filter((k) => /^2\d\d$/.test(k) && k !== "204").sort();
|
|
19474
|
+
if (contentfulTwoxxKeys.length > 1) {
|
|
19475
|
+
return {
|
|
19476
|
+
status: 200,
|
|
19477
|
+
isVoid: false,
|
|
19478
|
+
responseContentType: "application/json",
|
|
19479
|
+
isMultiStatus: true
|
|
19480
|
+
};
|
|
19481
|
+
}
|
|
19482
|
+
if (responses["201"] !== void 0) {
|
|
19483
|
+
return {
|
|
19484
|
+
status: 201,
|
|
19485
|
+
isVoid: false,
|
|
19486
|
+
responseContentType: detectResponseContentType(responses["201"])
|
|
19487
|
+
};
|
|
19488
|
+
}
|
|
19489
|
+
if (responses["204"] !== void 0) {
|
|
19490
|
+
return { status: 204, isVoid: true, responseContentType: "application/json" };
|
|
19262
19491
|
}
|
|
19263
|
-
if (responses["201"] !== void 0) return { status: 201, isVoid: false };
|
|
19264
|
-
if (responses["204"] !== void 0) return { status: 204, isVoid: true };
|
|
19265
19492
|
if (responses["200"] !== void 0) {
|
|
19266
|
-
if (response200IsVoid(responses["200"]))
|
|
19267
|
-
|
|
19493
|
+
if (response200IsVoid(responses["200"])) {
|
|
19494
|
+
return { status: 204, isVoid: true, responseContentType: "application/json" };
|
|
19495
|
+
}
|
|
19496
|
+
return {
|
|
19497
|
+
status: 200,
|
|
19498
|
+
isVoid: false,
|
|
19499
|
+
responseContentType: detectResponseContentType(responses["200"])
|
|
19500
|
+
};
|
|
19268
19501
|
}
|
|
19269
|
-
|
|
19502
|
+
const twoxxKeys = Object.keys(responses).filter(
|
|
19503
|
+
(k) => /^2\d\d$/.test(k) && k !== "200" && k !== "201" && k !== "204"
|
|
19504
|
+
);
|
|
19505
|
+
if (twoxxKeys.length === 1) {
|
|
19506
|
+
const code = parseInt(twoxxKeys[0], 10);
|
|
19507
|
+
const resp = responses[twoxxKeys[0]];
|
|
19508
|
+
const isVoid = isRef3(resp) ? false : (() => {
|
|
19509
|
+
const r = resp;
|
|
19510
|
+
const content = r.content;
|
|
19511
|
+
return content === void 0 || Object.keys(content).length === 0;
|
|
19512
|
+
})();
|
|
19513
|
+
return { status: code, isVoid, responseContentType: detectResponseContentType(resp) };
|
|
19514
|
+
}
|
|
19515
|
+
return httpMethod === "delete" ? { status: 204, isVoid: true, responseContentType: "application/json" } : { status: 200, isVoid: false, responseContentType: "application/json" };
|
|
19270
19516
|
}
|
|
19271
19517
|
function collectOperations2(spec) {
|
|
19272
19518
|
const paths = spec.paths;
|
|
@@ -19302,7 +19548,9 @@ function collectOperations2(spec) {
|
|
|
19302
19548
|
function collectSortedBodyTypes(operations) {
|
|
19303
19549
|
const bodyTypes = /* @__PURE__ */ new Set();
|
|
19304
19550
|
for (const op of operations) {
|
|
19305
|
-
if (op.bodyInfo?.typeName !== void 0
|
|
19551
|
+
if (op.bodyInfo?.typeName !== void 0 && !op.bodyInfo.isSynthesized) {
|
|
19552
|
+
bodyTypes.add(op.bodyInfo.typeName);
|
|
19553
|
+
}
|
|
19306
19554
|
}
|
|
19307
19555
|
return Array.from(bodyTypes).sort();
|
|
19308
19556
|
}
|
|
@@ -19334,7 +19582,27 @@ function buildRouteHandler(op, indent, schemaNames) {
|
|
|
19334
19582
|
lines.push(`${indent} }`);
|
|
19335
19583
|
}
|
|
19336
19584
|
if (op.queryParams.length > 0) {
|
|
19585
|
+
const deepObjectParams = op.queryParams.filter((q) => q.isDeepObject === true);
|
|
19586
|
+
if (deepObjectParams.length > 0) {
|
|
19587
|
+
lines.push(`${indent} const _dq = c.req.queries()`);
|
|
19588
|
+
for (const q of deepObjectParams) {
|
|
19589
|
+
const prefixLen = q.rawName.length + 1;
|
|
19590
|
+
const bracketPrefix = q.rawName + "[";
|
|
19591
|
+
lines.push(`${indent} const ${q.name} = Object.fromEntries(`);
|
|
19592
|
+
lines.push(
|
|
19593
|
+
`${indent} Object.entries(_dq).filter(([k]) => k.startsWith('${bracketPrefix}') && k.endsWith(']')).map(([k, vs]) => [k.slice(${prefixLen}, -1), vs[0]])`
|
|
19594
|
+
);
|
|
19595
|
+
lines.push(`${indent} )`);
|
|
19596
|
+
}
|
|
19597
|
+
}
|
|
19337
19598
|
const fields = op.queryParams.map((q) => {
|
|
19599
|
+
if (q.isDeepObject === true) {
|
|
19600
|
+
return ` ${q.name}`;
|
|
19601
|
+
}
|
|
19602
|
+
if (q.delimiterStyle !== void 0) {
|
|
19603
|
+
const delim = JSON.stringify(delimiterChar(q.delimiterStyle));
|
|
19604
|
+
return ` ${q.name}: c.req.query('${q.rawName}') !== undefined ? c.req.query('${q.rawName}')!.split(${delim}) : undefined`;
|
|
19605
|
+
}
|
|
19338
19606
|
if (q.tsType === "number") {
|
|
19339
19607
|
return ` ${q.name}: c.req.query('${q.name}') !== undefined ? Number(c.req.query('${q.name}')) : undefined`;
|
|
19340
19608
|
}
|
|
@@ -19362,8 +19630,32 @@ function buildRouteHandler(op, indent, schemaNames) {
|
|
|
19362
19630
|
}
|
|
19363
19631
|
let bodyVarName = "body";
|
|
19364
19632
|
if (op.bodyInfo !== void 0) {
|
|
19365
|
-
const
|
|
19366
|
-
|
|
19633
|
+
const typeDecl = op.bodyInfo.typeName !== void 0 && !op.bodyInfo.isSynthesized ? op.bodyInfo.typeName : "unknown";
|
|
19634
|
+
if (op.bodyInfo.contentType === "application/x-www-form-urlencoded") {
|
|
19635
|
+
lines.push(`${indent} const _ct = c.req.header('content-type') ?? ''`);
|
|
19636
|
+
lines.push(
|
|
19637
|
+
`${indent} if (!_ct.toLowerCase().startsWith('application/x-www-form-urlencoded')) {`
|
|
19638
|
+
);
|
|
19639
|
+
lines.push(`${indent} return c.json({ error: 'Unsupported Media Type' }, 415)`);
|
|
19640
|
+
lines.push(`${indent} }`);
|
|
19641
|
+
lines.push(`${indent} const body: unknown = await c.req.parseBody()`);
|
|
19642
|
+
} else if (op.bodyInfo.contentType === "multipart/form-data") {
|
|
19643
|
+
lines.push(
|
|
19644
|
+
`${indent} // multipart/form-data: parseBody({ all: true }) collects repeated keys into arrays.`
|
|
19645
|
+
);
|
|
19646
|
+
lines.push(`${indent} const body: unknown = await c.req.parseBody({ all: true })`);
|
|
19647
|
+
} else {
|
|
19648
|
+
lines.push(`${indent} const _ct = c.req.header('content-type') ?? ''`);
|
|
19649
|
+
lines.push(`${indent} if (!_ct.toLowerCase().startsWith('application/json')) {`);
|
|
19650
|
+
lines.push(`${indent} return c.json({ error: 'Unsupported Media Type' }, 415)`);
|
|
19651
|
+
lines.push(`${indent} }`);
|
|
19652
|
+
lines.push(`${indent} let body: ${typeDecl}`);
|
|
19653
|
+
lines.push(`${indent} try {`);
|
|
19654
|
+
lines.push(`${indent} body = JSON.parse(await c.req.text()) as ${typeDecl}`);
|
|
19655
|
+
lines.push(`${indent} } catch {`);
|
|
19656
|
+
lines.push(`${indent} return c.json({ error: 'Invalid JSON body' }, 400)`);
|
|
19657
|
+
lines.push(`${indent} }`);
|
|
19658
|
+
}
|
|
19367
19659
|
const schemaName = op.bodyInfo.typeName !== void 0 ? `${op.bodyInfo.typeName}Schema` : void 0;
|
|
19368
19660
|
if (schemaName !== void 0 && schemaNames !== void 0 && schemaNames.has(schemaName)) {
|
|
19369
19661
|
lines.push(`${indent} // Validate request body: returns 422 with Zod issues on failure`);
|
|
@@ -19388,14 +19680,44 @@ function buildRouteHandler(op, indent, schemaNames) {
|
|
|
19388
19680
|
serviceArgs.push("params");
|
|
19389
19681
|
}
|
|
19390
19682
|
const serviceCall = `service.${op.methodName}(${serviceArgs.join(", ")})`;
|
|
19683
|
+
lines.push(`${indent} try {`);
|
|
19391
19684
|
if (op.responseStatus.isVoid) {
|
|
19392
|
-
lines.push(`${indent}
|
|
19393
|
-
lines.push(`${indent}
|
|
19394
|
-
} else if (op.responseStatus.
|
|
19395
|
-
lines.push(`${indent}
|
|
19685
|
+
lines.push(`${indent} await ${serviceCall}`);
|
|
19686
|
+
lines.push(`${indent} return new Response(null, { status: ${op.responseStatus.status} })`);
|
|
19687
|
+
} else if (op.responseStatus.isMultiStatus === true) {
|
|
19688
|
+
lines.push(`${indent} const _envelope = await ${serviceCall}`);
|
|
19689
|
+
lines.push(`${indent} return c.json(_envelope.body, _envelope.status as any)`);
|
|
19690
|
+
} else if (op.responseStatus.responseContentType === "text/plain") {
|
|
19691
|
+
if (op.responseStatus.status === 200) {
|
|
19692
|
+
lines.push(`${indent} return c.text(await ${serviceCall})`);
|
|
19693
|
+
} else {
|
|
19694
|
+
lines.push(`${indent} return c.text(await ${serviceCall}, ${op.responseStatus.status})`);
|
|
19695
|
+
}
|
|
19696
|
+
} else if (op.responseStatus.responseContentType === "application/octet-stream") {
|
|
19697
|
+
if (op.responseStatus.status === 200) {
|
|
19698
|
+
lines.push(`${indent} const _result = await ${serviceCall}`);
|
|
19699
|
+
lines.push(
|
|
19700
|
+
`${indent} return new Response(_result, { headers: { 'content-type': 'application/octet-stream' } })`
|
|
19701
|
+
);
|
|
19702
|
+
} else {
|
|
19703
|
+
lines.push(`${indent} const _result = await ${serviceCall}`);
|
|
19704
|
+
lines.push(
|
|
19705
|
+
`${indent} return new Response(_result, { status: ${op.responseStatus.status}, headers: { 'content-type': 'application/octet-stream' } })`
|
|
19706
|
+
);
|
|
19707
|
+
}
|
|
19708
|
+
} else if (op.responseStatus.status === 200) {
|
|
19709
|
+
lines.push(`${indent} return c.json(await ${serviceCall})`);
|
|
19396
19710
|
} else {
|
|
19397
|
-
lines.push(`${indent}
|
|
19711
|
+
lines.push(`${indent} return c.json(await ${serviceCall}, ${op.responseStatus.status})`);
|
|
19398
19712
|
}
|
|
19713
|
+
lines.push(`${indent} } catch (err) {`);
|
|
19714
|
+
lines.push(`${indent} if (err instanceof HttpError) {`);
|
|
19715
|
+
lines.push(
|
|
19716
|
+
`${indent} return new Response(JSON.stringify({ error: err.message }), { status: err.status, headers: { 'content-type': 'application/json' } })`
|
|
19717
|
+
);
|
|
19718
|
+
lines.push(`${indent} }`);
|
|
19719
|
+
lines.push(`${indent} throw err`);
|
|
19720
|
+
lines.push(`${indent} }`);
|
|
19399
19721
|
lines.push(`${indent}})`);
|
|
19400
19722
|
return lines.join("\n");
|
|
19401
19723
|
}
|
|
@@ -19414,6 +19736,13 @@ function buildExpressRouteHandler(op, indent, schemaNames) {
|
|
|
19414
19736
|
}
|
|
19415
19737
|
if (op.queryParams.length > 0) {
|
|
19416
19738
|
const fields = op.queryParams.map((q) => {
|
|
19739
|
+
if (q.isDeepObject === true) {
|
|
19740
|
+
return ` ${q.name}: (req.query['${q.rawName}'] ?? {}) as Record<string, string | undefined>`;
|
|
19741
|
+
}
|
|
19742
|
+
if (q.delimiterStyle !== void 0) {
|
|
19743
|
+
const delim = JSON.stringify(delimiterChar(q.delimiterStyle));
|
|
19744
|
+
return ` ${q.name}: typeof req.query['${q.rawName}'] === 'string' ? (req.query['${q.rawName}'] as string).split(${delim}) : undefined`;
|
|
19745
|
+
}
|
|
19417
19746
|
if (q.tsType === "number") {
|
|
19418
19747
|
return ` ${q.name}: Number(req.query['${q.name}'] as string)`;
|
|
19419
19748
|
}
|
|
@@ -19444,21 +19773,28 @@ function buildExpressRouteHandler(op, indent, schemaNames) {
|
|
|
19444
19773
|
}
|
|
19445
19774
|
let bodyVarName = "body";
|
|
19446
19775
|
if (op.bodyInfo !== void 0) {
|
|
19447
|
-
|
|
19448
|
-
const useZod = schemaName !== void 0 && schemaNames !== void 0 && schemaNames.has(schemaName);
|
|
19449
|
-
if (useZod) {
|
|
19450
|
-
lines.push(`${indent} // Validate request body: returns 422 with Zod issues on failure`);
|
|
19451
|
-
lines.push(`${indent} const parseResult = ${schemaName}.safeParse(req.body)`);
|
|
19452
|
-
lines.push(`${indent} if (!parseResult.success) {`);
|
|
19776
|
+
if (op.bodyInfo.contentType === "multipart/form-data") {
|
|
19453
19777
|
lines.push(
|
|
19454
|
-
`${indent}
|
|
19778
|
+
`${indent} // multipart/form-data: assumes multer middleware has populated req.files + req.body.`
|
|
19455
19779
|
);
|
|
19456
|
-
lines.push(`${indent} }`);
|
|
19457
|
-
lines.push(`${indent} const validatedBody = parseResult.data`);
|
|
19458
|
-
bodyVarName = "validatedBody";
|
|
19780
|
+
lines.push(`${indent} const body = { ...req.body, ...(req as any).files } as unknown`);
|
|
19459
19781
|
} else {
|
|
19460
|
-
const
|
|
19461
|
-
|
|
19782
|
+
const schemaName = op.bodyInfo.typeName !== void 0 ? `${op.bodyInfo.typeName}Schema` : void 0;
|
|
19783
|
+
const useZod = schemaName !== void 0 && schemaNames !== void 0 && schemaNames.has(schemaName);
|
|
19784
|
+
if (useZod) {
|
|
19785
|
+
lines.push(`${indent} // Validate request body: returns 422 with Zod issues on failure`);
|
|
19786
|
+
lines.push(`${indent} const parseResult = ${schemaName}.safeParse(req.body)`);
|
|
19787
|
+
lines.push(`${indent} if (!parseResult.success) {`);
|
|
19788
|
+
lines.push(
|
|
19789
|
+
`${indent} return void res.status(422).json({ error: 'Invalid request body', issues: parseResult.error.issues })`
|
|
19790
|
+
);
|
|
19791
|
+
lines.push(`${indent} }`);
|
|
19792
|
+
lines.push(`${indent} const validatedBody = parseResult.data`);
|
|
19793
|
+
bodyVarName = "validatedBody";
|
|
19794
|
+
} else {
|
|
19795
|
+
const typeAnnotation = op.bodyInfo.typeName !== void 0 && !op.bodyInfo.isSynthesized ? ` as ${op.bodyInfo.typeName}` : "";
|
|
19796
|
+
lines.push(`${indent} const body = req.body${typeAnnotation}`);
|
|
19797
|
+
}
|
|
19462
19798
|
}
|
|
19463
19799
|
}
|
|
19464
19800
|
const serviceArgs = [];
|
|
@@ -19472,14 +19808,42 @@ function buildExpressRouteHandler(op, indent, schemaNames) {
|
|
|
19472
19808
|
serviceArgs.push("params");
|
|
19473
19809
|
}
|
|
19474
19810
|
const serviceCall = `service.${op.methodName}(${serviceArgs.join(", ")})`;
|
|
19811
|
+
lines.push(`${indent} try {`);
|
|
19475
19812
|
if (op.responseStatus.isVoid) {
|
|
19476
|
-
lines.push(`${indent}
|
|
19477
|
-
lines.push(`${indent}
|
|
19478
|
-
} else if (op.responseStatus.
|
|
19479
|
-
lines.push(`${indent}
|
|
19813
|
+
lines.push(`${indent} await ${serviceCall}`);
|
|
19814
|
+
lines.push(`${indent} res.status(${op.responseStatus.status}).end()`);
|
|
19815
|
+
} else if (op.responseStatus.isMultiStatus === true) {
|
|
19816
|
+
lines.push(`${indent} const _envelope = await ${serviceCall}`);
|
|
19817
|
+
lines.push(`${indent} res.status(_envelope.status).json(_envelope.body)`);
|
|
19818
|
+
} else if (op.responseStatus.responseContentType === "text/plain") {
|
|
19819
|
+
if (op.responseStatus.status === 200) {
|
|
19820
|
+
lines.push(`${indent} res.type('text/plain').send(await ${serviceCall})`);
|
|
19821
|
+
} else {
|
|
19822
|
+
lines.push(
|
|
19823
|
+
`${indent} res.status(${op.responseStatus.status}).type('text/plain').send(await ${serviceCall})`
|
|
19824
|
+
);
|
|
19825
|
+
}
|
|
19826
|
+
} else if (op.responseStatus.responseContentType === "application/octet-stream") {
|
|
19827
|
+
if (op.responseStatus.status === 200) {
|
|
19828
|
+
lines.push(
|
|
19829
|
+
`${indent} res.setHeader('Content-Type', 'application/octet-stream').send(Buffer.from(await ${serviceCall}))`
|
|
19830
|
+
);
|
|
19831
|
+
} else {
|
|
19832
|
+
lines.push(
|
|
19833
|
+
`${indent} res.status(${op.responseStatus.status}).setHeader('Content-Type', 'application/octet-stream').send(Buffer.from(await ${serviceCall}))`
|
|
19834
|
+
);
|
|
19835
|
+
}
|
|
19836
|
+
} else if (op.responseStatus.status === 200) {
|
|
19837
|
+
lines.push(`${indent} res.json(await ${serviceCall})`);
|
|
19480
19838
|
} else {
|
|
19481
|
-
lines.push(`${indent}
|
|
19482
|
-
}
|
|
19839
|
+
lines.push(`${indent} res.status(${op.responseStatus.status}).json(await ${serviceCall})`);
|
|
19840
|
+
}
|
|
19841
|
+
lines.push(`${indent} } catch (err) {`);
|
|
19842
|
+
lines.push(`${indent} if (err instanceof HttpError) {`);
|
|
19843
|
+
lines.push(`${indent} return void res.status(err.status).json({ error: err.message })`);
|
|
19844
|
+
lines.push(`${indent} }`);
|
|
19845
|
+
lines.push(`${indent} throw err`);
|
|
19846
|
+
lines.push(`${indent} }`);
|
|
19483
19847
|
lines.push(`${indent}})`);
|
|
19484
19848
|
return lines.join("\n");
|
|
19485
19849
|
}
|
|
@@ -19487,14 +19851,23 @@ function buildFastifyRouteHandler(op, indent, schemaNames) {
|
|
|
19487
19851
|
const lines = [];
|
|
19488
19852
|
const genericParts = [];
|
|
19489
19853
|
if (op.queryParams.length > 0) {
|
|
19490
|
-
const
|
|
19491
|
-
|
|
19492
|
-
|
|
19493
|
-
|
|
19494
|
-
|
|
19495
|
-
|
|
19496
|
-
|
|
19497
|
-
|
|
19854
|
+
const hasDeepOrDelimited = op.queryParams.some(
|
|
19855
|
+
(q) => q.isDeepObject === true || q.delimiterStyle !== void 0
|
|
19856
|
+
);
|
|
19857
|
+
let querystringType;
|
|
19858
|
+
if (hasDeepOrDelimited) {
|
|
19859
|
+
querystringType = "Record<string, string | string[] | undefined>";
|
|
19860
|
+
} else {
|
|
19861
|
+
const queryFields = op.queryParams.map((q) => {
|
|
19862
|
+
if (q.tsType === "number") return `${q.name}?: number`;
|
|
19863
|
+
if (q.tsType === "boolean") return `${q.name}?: boolean`;
|
|
19864
|
+
return `${q.name}?: string`;
|
|
19865
|
+
}).join("; ");
|
|
19866
|
+
querystringType = `{ ${queryFields} }`;
|
|
19867
|
+
}
|
|
19868
|
+
genericParts.push(`Querystring: ${querystringType}`);
|
|
19869
|
+
}
|
|
19870
|
+
if (op.bodyInfo !== void 0 && op.bodyInfo.typeName !== void 0 && !op.bodyInfo.isSynthesized) {
|
|
19498
19871
|
genericParts.push(`Body: ${op.bodyInfo.typeName}`);
|
|
19499
19872
|
} else if (op.bodyInfo !== void 0) {
|
|
19500
19873
|
genericParts.push("Body: unknown");
|
|
@@ -19517,7 +19890,36 @@ function buildFastifyRouteHandler(op, indent, schemaNames) {
|
|
|
19517
19890
|
lines.push(`${indent} }`);
|
|
19518
19891
|
}
|
|
19519
19892
|
if (op.queryParams.length > 0) {
|
|
19520
|
-
const
|
|
19893
|
+
const deepObjectParams = op.queryParams.filter((q) => q.isDeepObject === true);
|
|
19894
|
+
const hasDeepOrDelimited = op.queryParams.some(
|
|
19895
|
+
(q) => q.isDeepObject === true || q.delimiterStyle !== void 0
|
|
19896
|
+
);
|
|
19897
|
+
if (hasDeepOrDelimited) {
|
|
19898
|
+
lines.push(
|
|
19899
|
+
`${indent} const _dq = req.query as unknown as Record<string, string | undefined>`
|
|
19900
|
+
);
|
|
19901
|
+
}
|
|
19902
|
+
if (deepObjectParams.length > 0) {
|
|
19903
|
+
for (const q of deepObjectParams) {
|
|
19904
|
+
const prefixLen = q.rawName.length + 1;
|
|
19905
|
+
const bracketPrefix = q.rawName + "[";
|
|
19906
|
+
lines.push(`${indent} const ${q.name} = Object.fromEntries(`);
|
|
19907
|
+
lines.push(
|
|
19908
|
+
`${indent} Object.entries(_dq).filter(([k]) => k.startsWith('${bracketPrefix}') && k.endsWith(']')).map(([k, v]) => [k.slice(${prefixLen}, -1), v])`
|
|
19909
|
+
);
|
|
19910
|
+
lines.push(`${indent} )`);
|
|
19911
|
+
}
|
|
19912
|
+
}
|
|
19913
|
+
const fields = op.queryParams.map((q) => {
|
|
19914
|
+
if (q.isDeepObject === true) {
|
|
19915
|
+
return ` ${q.name}`;
|
|
19916
|
+
}
|
|
19917
|
+
if (q.delimiterStyle !== void 0) {
|
|
19918
|
+
const delim = JSON.stringify(delimiterChar(q.delimiterStyle));
|
|
19919
|
+
return ` ${q.name}: typeof _dq['${q.rawName}'] === 'string' ? _dq['${q.rawName}']!.split(${delim}) : undefined`;
|
|
19920
|
+
}
|
|
19921
|
+
return hasDeepOrDelimited ? ` ${q.name}: _dq['${q.rawName}']` : ` ${q.name}: req.query.${q.name}`;
|
|
19922
|
+
}).join(",\n");
|
|
19521
19923
|
lines.push(`${indent} const params = {`);
|
|
19522
19924
|
lines.push(fields);
|
|
19523
19925
|
lines.push(`${indent} }`);
|
|
@@ -19542,17 +19944,23 @@ function buildFastifyRouteHandler(op, indent, schemaNames) {
|
|
|
19542
19944
|
}
|
|
19543
19945
|
let bodyVarName = "req.body";
|
|
19544
19946
|
if (op.bodyInfo !== void 0) {
|
|
19545
|
-
|
|
19546
|
-
const useZod = schemaName !== void 0 && schemaNames !== void 0 && schemaNames.has(schemaName);
|
|
19547
|
-
if (useZod) {
|
|
19548
|
-
lines.push(`${indent} // Validate request body: returns 422 with Zod issues on failure`);
|
|
19549
|
-
lines.push(`${indent} const parseResult = ${schemaName}.safeParse(req.body)`);
|
|
19550
|
-
lines.push(`${indent} if (!parseResult.success) {`);
|
|
19947
|
+
if (op.bodyInfo.contentType === "multipart/form-data") {
|
|
19551
19948
|
lines.push(
|
|
19552
|
-
`${indent}
|
|
19949
|
+
`${indent} // multipart/form-data: assumes @fastify/multipart plugin has populated req.body.`
|
|
19553
19950
|
);
|
|
19554
|
-
|
|
19555
|
-
|
|
19951
|
+
} else {
|
|
19952
|
+
const schemaName = op.bodyInfo.typeName !== void 0 ? `${op.bodyInfo.typeName}Schema` : void 0;
|
|
19953
|
+
const useZod = schemaName !== void 0 && schemaNames !== void 0 && schemaNames.has(schemaName);
|
|
19954
|
+
if (useZod) {
|
|
19955
|
+
lines.push(`${indent} // Validate request body: returns 422 with Zod issues on failure`);
|
|
19956
|
+
lines.push(`${indent} const parseResult = ${schemaName}.safeParse(req.body)`);
|
|
19957
|
+
lines.push(`${indent} if (!parseResult.success) {`);
|
|
19958
|
+
lines.push(
|
|
19959
|
+
`${indent} return reply.status(422).send({ error: 'Invalid request body', issues: parseResult.error.issues })`
|
|
19960
|
+
);
|
|
19961
|
+
lines.push(`${indent} }`);
|
|
19962
|
+
bodyVarName = "parseResult.data";
|
|
19963
|
+
}
|
|
19556
19964
|
}
|
|
19557
19965
|
}
|
|
19558
19966
|
const serviceArgs = [];
|
|
@@ -19566,18 +19974,50 @@ function buildFastifyRouteHandler(op, indent, schemaNames) {
|
|
|
19566
19974
|
serviceArgs.push("params");
|
|
19567
19975
|
}
|
|
19568
19976
|
const serviceCall = `service.${op.methodName}(${serviceArgs.join(", ")})`;
|
|
19977
|
+
lines.push(`${indent} try {`);
|
|
19569
19978
|
if (op.responseStatus.isVoid) {
|
|
19570
|
-
lines.push(`${indent}
|
|
19571
|
-
lines.push(`${indent}
|
|
19572
|
-
} else if (op.responseStatus.
|
|
19573
|
-
lines.push(`${indent}
|
|
19574
|
-
lines.push(`${indent}
|
|
19979
|
+
lines.push(`${indent} await ${serviceCall}`);
|
|
19980
|
+
lines.push(`${indent} reply.status(${op.responseStatus.status}).send()`);
|
|
19981
|
+
} else if (op.responseStatus.isMultiStatus === true) {
|
|
19982
|
+
lines.push(`${indent} const _envelope = await ${serviceCall}`);
|
|
19983
|
+
lines.push(`${indent} return reply.status(_envelope.status).send(_envelope.body)`);
|
|
19984
|
+
} else if (op.responseStatus.responseContentType === "text/plain") {
|
|
19985
|
+
if (op.responseStatus.status === 200) {
|
|
19986
|
+
lines.push(`${indent} return reply.type('text/plain').send(await ${serviceCall})`);
|
|
19987
|
+
} else {
|
|
19988
|
+
lines.push(`${indent} return reply.status(${op.responseStatus.status}).type('text/plain').send(await ${serviceCall})`);
|
|
19989
|
+
}
|
|
19990
|
+
} else if (op.responseStatus.responseContentType === "application/octet-stream") {
|
|
19991
|
+
if (op.responseStatus.status === 200) {
|
|
19992
|
+
lines.push(`${indent} return reply.type('application/octet-stream').send(Buffer.from(await ${serviceCall}))`);
|
|
19993
|
+
} else {
|
|
19994
|
+
lines.push(`${indent} return reply.status(${op.responseStatus.status}).type('application/octet-stream').send(Buffer.from(await ${serviceCall}))`);
|
|
19995
|
+
}
|
|
19996
|
+
} else if (op.responseStatus.status === 200) {
|
|
19997
|
+
lines.push(`${indent} return ${serviceCall}`);
|
|
19575
19998
|
} else {
|
|
19576
|
-
lines.push(`${indent}
|
|
19577
|
-
|
|
19999
|
+
lines.push(`${indent} reply.status(${op.responseStatus.status})`);
|
|
20000
|
+
lines.push(`${indent} return ${serviceCall}`);
|
|
20001
|
+
}
|
|
20002
|
+
lines.push(`${indent} } catch (err) {`);
|
|
20003
|
+
lines.push(`${indent} if (err instanceof HttpError) {`);
|
|
20004
|
+
lines.push(`${indent} return reply.status(err.status).send({ error: err.message })`);
|
|
20005
|
+
lines.push(`${indent} }`);
|
|
20006
|
+
lines.push(`${indent} throw err`);
|
|
20007
|
+
lines.push(`${indent} }`);
|
|
19578
20008
|
lines.push(`${indent}})`);
|
|
19579
20009
|
return lines.join("\n");
|
|
19580
20010
|
}
|
|
20011
|
+
function httpErrorClassLines() {
|
|
20012
|
+
return [
|
|
20013
|
+
"export class HttpError extends Error {",
|
|
20014
|
+
" constructor(public readonly status: number, message: string) {",
|
|
20015
|
+
" super(message)",
|
|
20016
|
+
" this.name = 'HttpError'",
|
|
20017
|
+
" }",
|
|
20018
|
+
"}"
|
|
20019
|
+
];
|
|
20020
|
+
}
|
|
19581
20021
|
function operationsNeedZodForParams(operations) {
|
|
19582
20022
|
for (const op of operations) {
|
|
19583
20023
|
if (op.pathParamValidations.length > 0) return true;
|
|
@@ -19610,6 +20050,8 @@ function generateExpressRouter(spec, options) {
|
|
|
19610
20050
|
lines.push(`import { ${sortedUsedSchemas.join(", ")} } from '${options.schemaImportPath}'`);
|
|
19611
20051
|
}
|
|
19612
20052
|
lines.push("");
|
|
20053
|
+
for (const l of httpErrorClassLines()) lines.push(l);
|
|
20054
|
+
lines.push("");
|
|
19613
20055
|
lines.push(`export function createRouter(service: ${serviceName}): Router {`);
|
|
19614
20056
|
lines.push(" const router = Router()");
|
|
19615
20057
|
lines.push("");
|
|
@@ -19645,6 +20087,8 @@ function generateFastifyRouter(spec, options) {
|
|
|
19645
20087
|
lines.push(`import { ${sortedUsedSchemas.join(", ")} } from '${options.schemaImportPath}'`);
|
|
19646
20088
|
}
|
|
19647
20089
|
lines.push("");
|
|
20090
|
+
for (const l of httpErrorClassLines()) lines.push(l);
|
|
20091
|
+
lines.push("");
|
|
19648
20092
|
lines.push(`export function createRouter(app: FastifyInstance, service: ${serviceName}): void {`);
|
|
19649
20093
|
for (const op of operations) {
|
|
19650
20094
|
lines.push("");
|
|
@@ -19677,6 +20121,8 @@ function generateRouter(spec, options) {
|
|
|
19677
20121
|
lines.push(`import { ${sortedUsedSchemas.join(", ")} } from '${options.schemaImportPath}'`);
|
|
19678
20122
|
}
|
|
19679
20123
|
lines.push("");
|
|
20124
|
+
for (const l of httpErrorClassLines()) lines.push(l);
|
|
20125
|
+
lines.push("");
|
|
19680
20126
|
lines.push(`export function createRouter(service: ${serviceName}): Hono {`);
|
|
19681
20127
|
lines.push(" const app = new Hono()");
|
|
19682
20128
|
lines.push("");
|