zenko 0.1.3 → 0.1.4
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 +124 -73
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +124 -73
- package/dist/cli.mjs.map +1 -1
- package/dist/index.cjs +124 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +124 -73
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/cli.cjs
CHANGED
|
@@ -266,8 +266,11 @@ function generate(spec, options = {}) {
|
|
|
266
266
|
const pathParamNames = op.pathParams.map((p) => p.name);
|
|
267
267
|
const hasPathParams = pathParamNames.length > 0;
|
|
268
268
|
const hasQueryParams = op.queryParams.length > 0;
|
|
269
|
+
const camelCaseOperationId = toCamelCase(op.operationId);
|
|
269
270
|
if (!hasPathParams && !hasQueryParams) {
|
|
270
|
-
output.push(
|
|
271
|
+
output.push(
|
|
272
|
+
` ${formatPropertyName(camelCaseOperationId)}: () => "${op.path}",`
|
|
273
|
+
);
|
|
271
274
|
continue;
|
|
272
275
|
}
|
|
273
276
|
const allParamNames = [
|
|
@@ -290,11 +293,13 @@ function generate(spec, options = {}) {
|
|
|
290
293
|
const pathWithParams = op.path.replace(/{([^}]+)}/g, "${$1}");
|
|
291
294
|
if (!hasQueryParams) {
|
|
292
295
|
output.push(
|
|
293
|
-
` ${
|
|
296
|
+
` ${formatPropertyName(camelCaseOperationId)}: (${signature}) => \`${pathWithParams}\`,`
|
|
294
297
|
);
|
|
295
298
|
continue;
|
|
296
299
|
}
|
|
297
|
-
output.push(
|
|
300
|
+
output.push(
|
|
301
|
+
` ${formatPropertyName(camelCaseOperationId)}: (${signature}) => {`
|
|
302
|
+
);
|
|
298
303
|
output.push(" const params = new URLSearchParams()");
|
|
299
304
|
for (const param of op.queryParams) {
|
|
300
305
|
const propertyKey = formatPropertyName(param.name);
|
|
@@ -339,83 +344,57 @@ function generate(spec, options = {}) {
|
|
|
339
344
|
}
|
|
340
345
|
output.push("} as const;");
|
|
341
346
|
output.push("");
|
|
342
|
-
output.push("// Header
|
|
343
|
-
output.push("export const
|
|
347
|
+
output.push("// Header Schemas");
|
|
348
|
+
output.push("export const headerSchemas = {");
|
|
344
349
|
for (const op of operations) {
|
|
350
|
+
const camelCaseOperationId = toCamelCase(op.operationId);
|
|
345
351
|
if (!op.requestHeaders || op.requestHeaders.length === 0) {
|
|
346
|
-
output.push(
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
const typeEntries = op.requestHeaders.map(
|
|
350
|
-
(header) => `${formatPropertyName(header.name)}${header.required ? "" : "?"}: ${mapHeaderType(
|
|
351
|
-
header
|
|
352
|
-
)}`
|
|
353
|
-
).join(", ");
|
|
354
|
-
const requiredHeaders = op.requestHeaders.filter(
|
|
355
|
-
(header) => header.required
|
|
356
|
-
);
|
|
357
|
-
const optionalHeaders = op.requestHeaders.filter(
|
|
358
|
-
(header) => !header.required
|
|
359
|
-
);
|
|
360
|
-
const hasRequired = requiredHeaders.length > 0;
|
|
361
|
-
const signature = hasRequired ? `(params: { ${typeEntries} })` : `(params: { ${typeEntries} } = {})`;
|
|
362
|
-
if (optionalHeaders.length === 0) {
|
|
363
|
-
output.push(` ${op.operationId}: ${signature} => ({`);
|
|
364
|
-
for (const header of requiredHeaders) {
|
|
365
|
-
const propertyKey = formatPropertyName(header.name);
|
|
366
|
-
const accessor = isValidJSIdentifier(header.name) ? `params.${header.name}` : `params[${propertyKey}]`;
|
|
367
|
-
output.push(` ${propertyKey}: ${accessor},`);
|
|
368
|
-
}
|
|
369
|
-
output.push(" }),");
|
|
352
|
+
output.push(
|
|
353
|
+
` ${formatPropertyName(camelCaseOperationId)}: z.object({}),`
|
|
354
|
+
);
|
|
370
355
|
continue;
|
|
371
356
|
}
|
|
372
|
-
|
|
373
|
-
const
|
|
374
|
-
const
|
|
375
|
-
|
|
376
|
-
|
|
357
|
+
const schemaFields = op.requestHeaders.map((header) => {
|
|
358
|
+
const zodType = mapHeaderToZodType(header);
|
|
359
|
+
const optional = header.required ? "" : ".optional()";
|
|
360
|
+
return ` ${formatPropertyName(header.name)}: ${zodType}${optional},`;
|
|
361
|
+
}).join("\n");
|
|
362
|
+
output.push(` ${formatPropertyName(camelCaseOperationId)}: z.object({`);
|
|
363
|
+
output.push(schemaFields);
|
|
364
|
+
output.push(" }),");
|
|
365
|
+
}
|
|
366
|
+
output.push("} as const;");
|
|
367
|
+
output.push("");
|
|
368
|
+
output.push("// Header Functions");
|
|
369
|
+
output.push("export const headers = {");
|
|
370
|
+
for (const op of operations) {
|
|
371
|
+
const camelCaseOperationId = toCamelCase(op.operationId);
|
|
372
|
+
if (!op.requestHeaders || op.requestHeaders.length === 0) {
|
|
377
373
|
output.push(
|
|
378
|
-
`
|
|
374
|
+
` ${formatPropertyName(camelCaseOperationId)}: () => ${isValidJSIdentifier(camelCaseOperationId) ? `headerSchemas.${camelCaseOperationId}` : `headerSchemas[${formatPropertyName(camelCaseOperationId)}]`}.parse({}),`
|
|
379
375
|
);
|
|
380
376
|
continue;
|
|
381
377
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
)
|
|
385
|
-
output.push(
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
for (const header of requiredHeaders) {
|
|
389
|
-
const propertyKey = formatPropertyName(header.name);
|
|
390
|
-
const accessor = isValidJSIdentifier(header.name) ? `params.${header.name}` : `params[${propertyKey}]`;
|
|
391
|
-
output.push(` ${propertyKey}: ${accessor},`);
|
|
392
|
-
}
|
|
393
|
-
output.push(" }");
|
|
394
|
-
} else {
|
|
395
|
-
output.push(` const headers: Record<string, ${valueTypes}> = {}`);
|
|
396
|
-
}
|
|
397
|
-
for (const header of optionalHeaders) {
|
|
398
|
-
const propertyKey = formatPropertyName(header.name);
|
|
399
|
-
const accessor = isValidJSIdentifier(header.name) ? `params.${header.name}` : `params[${propertyKey}]`;
|
|
400
|
-
const assignment = isValidJSIdentifier(header.name) ? `headers.${header.name}` : `headers[${propertyKey}]`;
|
|
401
|
-
output.push(` if (${accessor} !== undefined) {`);
|
|
402
|
-
output.push(` ${assignment} = ${accessor}`);
|
|
403
|
-
output.push(" }");
|
|
404
|
-
}
|
|
405
|
-
output.push(" return headers");
|
|
378
|
+
output.push(
|
|
379
|
+
` ${formatPropertyName(camelCaseOperationId)}: (params: z.input<${isValidJSIdentifier(camelCaseOperationId) ? `typeof headerSchemas.${camelCaseOperationId}` : `(typeof headerSchemas)[${formatPropertyName(camelCaseOperationId)}]`}>) => {`
|
|
380
|
+
);
|
|
381
|
+
output.push(
|
|
382
|
+
` return ${isValidJSIdentifier(camelCaseOperationId) ? `headerSchemas.${camelCaseOperationId}` : `headerSchemas[${formatPropertyName(camelCaseOperationId)}]`}.parse(params)`
|
|
383
|
+
);
|
|
406
384
|
output.push(" },");
|
|
407
385
|
}
|
|
408
386
|
output.push("} as const;");
|
|
409
387
|
output.push("");
|
|
410
388
|
output.push("// Operation Objects");
|
|
411
389
|
for (const op of operations) {
|
|
412
|
-
|
|
390
|
+
const camelCaseOperationId = toCamelCase(op.operationId);
|
|
391
|
+
output.push(`export const ${camelCaseOperationId} = {`);
|
|
413
392
|
output.push(` method: "${op.method}",`);
|
|
414
|
-
output.push(` path: paths.${
|
|
393
|
+
output.push(` path: paths.${camelCaseOperationId},`);
|
|
415
394
|
appendOperationField(output, "request", op.requestType);
|
|
416
395
|
appendOperationField(output, "response", op.responseType);
|
|
417
396
|
if (op.requestHeaders && op.requestHeaders.length > 0) {
|
|
418
|
-
output.push(` headers: headers.${
|
|
397
|
+
output.push(` headers: headers.${camelCaseOperationId},`);
|
|
419
398
|
}
|
|
420
399
|
if (op.errors && hasAnyErrors(op.errors)) {
|
|
421
400
|
output.push(" errors: {");
|
|
@@ -466,6 +445,36 @@ function isRequestMethod(method) {
|
|
|
466
445
|
return false;
|
|
467
446
|
}
|
|
468
447
|
}
|
|
448
|
+
var CONTENT_TYPE_MAP = {
|
|
449
|
+
"application/json": "unknown",
|
|
450
|
+
// Will use schema when available
|
|
451
|
+
"text/csv": "string",
|
|
452
|
+
"text/plain": "string",
|
|
453
|
+
// Binary/ambiguous types default to unknown for cross-platform compatibility
|
|
454
|
+
"application/octet-stream": "unknown",
|
|
455
|
+
"application/pdf": "unknown"
|
|
456
|
+
};
|
|
457
|
+
function findContentType(content) {
|
|
458
|
+
const contentTypes = Object.keys(content);
|
|
459
|
+
if (contentTypes.includes("application/json")) {
|
|
460
|
+
return "application/json";
|
|
461
|
+
}
|
|
462
|
+
for (const contentType of contentTypes) {
|
|
463
|
+
if (contentType in CONTENT_TYPE_MAP) {
|
|
464
|
+
return contentType;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return contentTypes[0] || "";
|
|
468
|
+
}
|
|
469
|
+
function inferResponseType(contentType, statusCode) {
|
|
470
|
+
if (statusCode === "204" || /^3\d\d$/.test(statusCode)) {
|
|
471
|
+
return "undefined";
|
|
472
|
+
}
|
|
473
|
+
if (contentType in CONTENT_TYPE_MAP) {
|
|
474
|
+
return CONTENT_TYPE_MAP[contentType];
|
|
475
|
+
}
|
|
476
|
+
return "unknown";
|
|
477
|
+
}
|
|
469
478
|
function parseOperations(spec) {
|
|
470
479
|
const operations = [];
|
|
471
480
|
for (const [path2, pathItem] of Object.entries(spec.paths)) {
|
|
@@ -552,15 +561,18 @@ function generateOperationTypes(buffer, operations, config) {
|
|
|
552
561
|
if (!config.emit) return;
|
|
553
562
|
buffer.push("// Operation Types");
|
|
554
563
|
for (const op of operations) {
|
|
555
|
-
const
|
|
564
|
+
const camelCaseOperationId = toCamelCase(op.operationId);
|
|
565
|
+
const headerType = op.requestHeaders?.length ? isValidJSIdentifier(camelCaseOperationId) ? `typeof headers.${camelCaseOperationId}` : `(typeof headers)[${formatPropertyName(camelCaseOperationId)}]` : "undefined";
|
|
556
566
|
const requestType = wrapTypeReference(op.requestType);
|
|
557
567
|
const responseType = wrapTypeReference(op.responseType);
|
|
558
568
|
const errorsType = buildOperationErrorsType(op.errors);
|
|
559
569
|
buffer.push(
|
|
560
|
-
`export type ${capitalize(
|
|
570
|
+
`export type ${capitalize(camelCaseOperationId)}Operation = OperationDefinition<`
|
|
561
571
|
);
|
|
562
572
|
buffer.push(` "${op.method}",`);
|
|
563
|
-
buffer.push(
|
|
573
|
+
buffer.push(
|
|
574
|
+
` ${isValidJSIdentifier(camelCaseOperationId) ? `typeof paths.${camelCaseOperationId}` : `(typeof paths)[${formatPropertyName(camelCaseOperationId)}]`},`
|
|
575
|
+
);
|
|
564
576
|
buffer.push(` ${requestType},`);
|
|
565
577
|
buffer.push(` ${responseType},`);
|
|
566
578
|
buffer.push(` ${headerType},`);
|
|
@@ -683,13 +695,34 @@ function getResponseTypes(operation, operationId) {
|
|
|
683
695
|
const successCodes = /* @__PURE__ */ new Map();
|
|
684
696
|
const errorEntries = [];
|
|
685
697
|
for (const [statusCode, response] of Object.entries(responses)) {
|
|
686
|
-
const
|
|
687
|
-
if (!
|
|
698
|
+
const content = response?.content;
|
|
699
|
+
if (!content || Object.keys(content).length === 0) {
|
|
700
|
+
if (statusCode === "204" || /^3\d\d$/.test(statusCode)) {
|
|
701
|
+
successCodes.set(statusCode, "undefined");
|
|
702
|
+
}
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
const contentType = findContentType(content);
|
|
706
|
+
const resolvedSchema = content[contentType]?.schema;
|
|
707
|
+
if (!resolvedSchema) {
|
|
708
|
+
const inferredType = inferResponseType(contentType, statusCode);
|
|
709
|
+
if (inferredType) {
|
|
710
|
+
if (isErrorStatus(statusCode)) {
|
|
711
|
+
errorEntries.push({
|
|
712
|
+
code: statusCode,
|
|
713
|
+
schema: inferredType
|
|
714
|
+
});
|
|
715
|
+
} else if (/^2\d\d$/.test(statusCode)) {
|
|
716
|
+
successCodes.set(statusCode, inferredType);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
continue;
|
|
720
|
+
}
|
|
688
721
|
if (isErrorStatus(statusCode)) {
|
|
689
722
|
errorEntries.push({ code: statusCode, schema: resolvedSchema });
|
|
690
723
|
continue;
|
|
691
724
|
}
|
|
692
|
-
if (/^2\d\d$/.test(statusCode)
|
|
725
|
+
if (/^2\d\d$/.test(statusCode)) {
|
|
693
726
|
successCodes.set(statusCode, resolvedSchema);
|
|
694
727
|
}
|
|
695
728
|
}
|
|
@@ -703,6 +736,9 @@ function selectSuccessResponse(responses, operationId) {
|
|
|
703
736
|
for (const code of preferredOrder) {
|
|
704
737
|
const schema = responses.get(code);
|
|
705
738
|
if (schema) {
|
|
739
|
+
if (typeof schema === "string") {
|
|
740
|
+
return schema;
|
|
741
|
+
}
|
|
706
742
|
return resolveResponseType(
|
|
707
743
|
schema,
|
|
708
744
|
`${capitalize(operationId)}Response${code}`
|
|
@@ -711,6 +747,9 @@ function selectSuccessResponse(responses, operationId) {
|
|
|
711
747
|
}
|
|
712
748
|
const [firstCode, firstSchema] = responses.entries().next().value ?? [];
|
|
713
749
|
if (!firstSchema) return void 0;
|
|
750
|
+
if (typeof firstSchema === "string") {
|
|
751
|
+
return firstSchema;
|
|
752
|
+
}
|
|
714
753
|
return resolveResponseType(
|
|
715
754
|
firstSchema,
|
|
716
755
|
`${capitalize(operationId)}Response${firstCode ?? "Default"}`
|
|
@@ -748,6 +787,9 @@ function buildErrorGroups(errors = [], operationId) {
|
|
|
748
787
|
return group;
|
|
749
788
|
}
|
|
750
789
|
function resolveResponseType(schema, fallbackName) {
|
|
790
|
+
if (typeof schema === "string") {
|
|
791
|
+
return schema;
|
|
792
|
+
}
|
|
751
793
|
if (schema.$ref) {
|
|
752
794
|
return extractRefName(schema.$ref);
|
|
753
795
|
}
|
|
@@ -781,16 +823,22 @@ function getQueryParams(parameters) {
|
|
|
781
823
|
}
|
|
782
824
|
return queryParams;
|
|
783
825
|
}
|
|
784
|
-
function
|
|
785
|
-
const
|
|
826
|
+
function mapHeaderToZodType(header) {
|
|
827
|
+
const schema = header.schema ?? {};
|
|
828
|
+
const schemaType = schema.type;
|
|
786
829
|
switch (schemaType) {
|
|
787
830
|
case "integer":
|
|
788
831
|
case "number":
|
|
789
|
-
return "number";
|
|
832
|
+
return "z.coerce.number()";
|
|
790
833
|
case "boolean":
|
|
791
|
-
return "boolean";
|
|
834
|
+
return "z.coerce.boolean()";
|
|
835
|
+
case "array": {
|
|
836
|
+
const items = schema.items ?? { type: "string" };
|
|
837
|
+
const itemType = items.type === "integer" || items.type === "number" ? "z.coerce.number()" : items.type === "boolean" ? "z.coerce.boolean()" : "z.string()";
|
|
838
|
+
return `z.array(${itemType})`;
|
|
839
|
+
}
|
|
792
840
|
default:
|
|
793
|
-
return "string";
|
|
841
|
+
return "z.string()";
|
|
794
842
|
}
|
|
795
843
|
}
|
|
796
844
|
function mapQueryType(param) {
|
|
@@ -994,6 +1042,9 @@ function applyNumericBounds(schema, builder) {
|
|
|
994
1042
|
}
|
|
995
1043
|
return builder;
|
|
996
1044
|
}
|
|
1045
|
+
function toCamelCase(str) {
|
|
1046
|
+
return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
1047
|
+
}
|
|
997
1048
|
function capitalize(str) {
|
|
998
1049
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
999
1050
|
}
|