@cerios/openapi-to-zod 1.2.0 → 1.3.1
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 +87 -30
- package/dist/cli.js +306 -52
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +312 -52
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +300 -51
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +300 -51
- package/dist/index.mjs.map +1 -1
- package/dist/internal.d.mts +93 -2
- package/dist/internal.d.ts +93 -2
- package/dist/internal.js +115 -4
- package/dist/internal.js.map +1 -1
- package/dist/internal.mjs +109 -4
- package/dist/internal.mjs.map +1 -1
- package/dist/{types--r0d47sd.d.mts → types-DZ4Bw-D5.d.mts} +86 -4
- package/dist/{types--r0d47sd.d.ts → types-DZ4Bw-D5.d.ts} +86 -4
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -86,12 +86,12 @@ function toCamelCase(str, options) {
|
|
|
86
86
|
name = words[0].charAt(0).toLowerCase() + words[0].slice(1) + words.slice(1).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
87
87
|
}
|
|
88
88
|
if (options == null ? void 0 : options.prefix) {
|
|
89
|
-
const prefix = options.prefix.toLowerCase();
|
|
89
|
+
const prefix = options.prefix.charAt(0).toLowerCase() + options.prefix.slice(1);
|
|
90
90
|
name = prefix + name.charAt(0).toUpperCase() + name.slice(1);
|
|
91
91
|
}
|
|
92
92
|
if (options == null ? void 0 : options.suffix) {
|
|
93
|
-
const suffix = options.suffix;
|
|
94
|
-
name = name + suffix
|
|
93
|
+
const suffix = options.suffix.charAt(0).toUpperCase() + options.suffix.slice(1);
|
|
94
|
+
name = name + suffix;
|
|
95
95
|
}
|
|
96
96
|
return name;
|
|
97
97
|
}
|
|
@@ -403,12 +403,56 @@ function generateArrayValidation(schema, context) {
|
|
|
403
403
|
}
|
|
404
404
|
|
|
405
405
|
// src/validators/composition-validator.ts
|
|
406
|
+
function isDiscriminatorRequired(schemas, discriminator, context) {
|
|
407
|
+
const invalidSchemas = [];
|
|
408
|
+
for (const schema of schemas) {
|
|
409
|
+
const resolved = resolveSchema(schema, context);
|
|
410
|
+
const required = resolved.required || [];
|
|
411
|
+
if (!required.includes(discriminator)) {
|
|
412
|
+
const schemaName = schema.$ref ? schema.$ref.split("/").pop() || "inline" : "inline";
|
|
413
|
+
invalidSchemas.push(schemaName);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return {
|
|
417
|
+
valid: invalidSchemas.length === 0,
|
|
418
|
+
invalidSchemas
|
|
419
|
+
};
|
|
420
|
+
}
|
|
406
421
|
function generateUnion(schemas, discriminator, isNullable2, context, options, currentSchema) {
|
|
422
|
+
if (schemas.length === 0) {
|
|
423
|
+
console.warn(
|
|
424
|
+
"[openapi-to-zod] Warning: Empty oneOf/anyOf array encountered. This is likely a malformed OpenAPI spec. Generating z.never() as fallback."
|
|
425
|
+
);
|
|
426
|
+
return wrapNullable(
|
|
427
|
+
'z.never().describe("Empty oneOf/anyOf in OpenAPI spec - no valid schema defined")',
|
|
428
|
+
isNullable2
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
if (schemas.length === 1) {
|
|
432
|
+
let singleSchema = context.generatePropertySchema(schemas[0], currentSchema);
|
|
433
|
+
if ((options == null ? void 0 : options.passthrough) && !singleSchema.includes(".catchall(")) {
|
|
434
|
+
singleSchema = `${singleSchema}.catchall(z.unknown())`;
|
|
435
|
+
}
|
|
436
|
+
return wrapNullable(singleSchema, isNullable2);
|
|
437
|
+
}
|
|
407
438
|
if (discriminator) {
|
|
408
439
|
let resolvedSchemas = schemas;
|
|
409
440
|
if ((options == null ? void 0 : options.discriminatorMapping) && context.resolveDiscriminatorMapping) {
|
|
410
441
|
resolvedSchemas = context.resolveDiscriminatorMapping(options.discriminatorMapping, schemas);
|
|
411
442
|
}
|
|
443
|
+
const discriminatorCheck = isDiscriminatorRequired(resolvedSchemas, discriminator, context);
|
|
444
|
+
if (!discriminatorCheck.valid) {
|
|
445
|
+
console.warn(
|
|
446
|
+
`[openapi-to-zod] Warning: Discriminator "${discriminator}" is not required in schemas: ${discriminatorCheck.invalidSchemas.join(", ")}. Falling back to z.union() instead of z.discriminatedUnion().`
|
|
447
|
+
);
|
|
448
|
+
let schemaStrings3 = resolvedSchemas.map((s) => context.generatePropertySchema(s, currentSchema));
|
|
449
|
+
if (options == null ? void 0 : options.passthrough) {
|
|
450
|
+
schemaStrings3 = schemaStrings3.map((s) => s.includes(".catchall(") ? s : `${s}.catchall(z.unknown())`);
|
|
451
|
+
}
|
|
452
|
+
const fallbackDescription = `Discriminator "${discriminator}" is optional in some schemas (${discriminatorCheck.invalidSchemas.join(", ")}), using z.union() instead of z.discriminatedUnion()`;
|
|
453
|
+
const union3 = `z.union([${schemaStrings3.join(", ")}]).describe("${fallbackDescription}")`;
|
|
454
|
+
return wrapNullable(union3, isNullable2);
|
|
455
|
+
}
|
|
412
456
|
let schemaStrings2 = resolvedSchemas.map((s) => context.generatePropertySchema(s, currentSchema));
|
|
413
457
|
if (options == null ? void 0 : options.passthrough) {
|
|
414
458
|
schemaStrings2 = schemaStrings2.map((s) => s.includes(".catchall(") ? s : `${s}.catchall(z.unknown())`);
|
|
@@ -423,25 +467,102 @@ function generateUnion(schemas, discriminator, isNullable2, context, options, cu
|
|
|
423
467
|
const union = `z.union([${schemaStrings.join(", ")}])`;
|
|
424
468
|
return wrapNullable(union, isNullable2);
|
|
425
469
|
}
|
|
426
|
-
function
|
|
470
|
+
function resolveSchema(schema, context) {
|
|
471
|
+
if (schema.$ref && context.resolveSchemaRef) {
|
|
472
|
+
const resolved = context.resolveSchemaRef(schema.$ref);
|
|
473
|
+
if (resolved) {
|
|
474
|
+
return resolved;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
return schema;
|
|
478
|
+
}
|
|
479
|
+
function collectProperties(schema, context) {
|
|
480
|
+
const resolved = resolveSchema(schema, context);
|
|
481
|
+
const props = /* @__PURE__ */ new Map();
|
|
482
|
+
const sourceName = schema.$ref ? schema.$ref.split("/").pop() || "unknown" : "inline";
|
|
483
|
+
if (resolved.properties) {
|
|
484
|
+
for (const [key, value] of Object.entries(resolved.properties)) {
|
|
485
|
+
props.set(key, { schema: value, source: sourceName });
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
if (resolved.allOf) {
|
|
489
|
+
for (const subSchema of resolved.allOf) {
|
|
490
|
+
const subProps = collectProperties(subSchema, context);
|
|
491
|
+
for (const [key, value] of subProps) {
|
|
492
|
+
if (!props.has(key)) {
|
|
493
|
+
props.set(key, value);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
return props;
|
|
499
|
+
}
|
|
500
|
+
function schemasMatch(a, b) {
|
|
501
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
502
|
+
}
|
|
503
|
+
function detectConflictingProperties(schemas, context) {
|
|
504
|
+
const conflicts = [];
|
|
505
|
+
const propertyMap = /* @__PURE__ */ new Map();
|
|
506
|
+
for (const schema of schemas) {
|
|
507
|
+
const schemaProps = collectProperties(schema, context);
|
|
508
|
+
for (const [propName, propInfo] of schemaProps) {
|
|
509
|
+
const existing = propertyMap.get(propName);
|
|
510
|
+
if (existing) {
|
|
511
|
+
if (!schemasMatch(existing.schema, propInfo.schema)) {
|
|
512
|
+
conflicts.push(
|
|
513
|
+
`Property "${propName}" has conflicting definitions in ${existing.source} and ${propInfo.source}`
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
} else {
|
|
517
|
+
propertyMap.set(propName, propInfo);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return conflicts;
|
|
522
|
+
}
|
|
523
|
+
function generateAllOf(schemas, isNullable2, context, currentSchema, explicitNullableFalse = false) {
|
|
427
524
|
if (schemas.length === 1) {
|
|
428
|
-
const singleSchema = context.generatePropertySchema(schemas[0], currentSchema, false);
|
|
525
|
+
const singleSchema = context.generatePropertySchema(schemas[0], currentSchema, false, explicitNullableFalse);
|
|
429
526
|
return wrapNullable(singleSchema, isNullable2);
|
|
430
527
|
}
|
|
528
|
+
const conflicts = detectConflictingProperties(schemas, context);
|
|
529
|
+
let conflictDescription = "";
|
|
530
|
+
if (conflicts.length > 0) {
|
|
531
|
+
for (const conflict of conflicts) {
|
|
532
|
+
console.warn(`[openapi-to-zod] Warning: allOf composition conflict - ${conflict}`);
|
|
533
|
+
}
|
|
534
|
+
conflictDescription = `allOf property conflicts detected: ${conflicts.join("; ")}`;
|
|
535
|
+
}
|
|
431
536
|
const allObjects = schemas.every((s) => s.type === "object" || s.properties || s.$ref || s.allOf);
|
|
432
|
-
|
|
537
|
+
let result;
|
|
433
538
|
if (allObjects) {
|
|
434
|
-
let
|
|
539
|
+
let merged = context.generatePropertySchema(schemas[0], currentSchema, false);
|
|
540
|
+
for (let i = 1; i < schemas.length; i++) {
|
|
541
|
+
const schema = schemas[i];
|
|
542
|
+
if (schema.$ref) {
|
|
543
|
+
const refSchema = context.generatePropertySchema(schema, currentSchema, false);
|
|
544
|
+
merged = `${merged}.extend(${refSchema}.shape)`;
|
|
545
|
+
} else if (context.generateInlineObjectShape && (schema.properties || schema.type === "object")) {
|
|
546
|
+
const inlineShape = context.generateInlineObjectShape(schema, currentSchema);
|
|
547
|
+
merged = `${merged}.extend(${inlineShape})`;
|
|
548
|
+
} else {
|
|
549
|
+
const schemaString = context.generatePropertySchema(schema, currentSchema, false);
|
|
550
|
+
merged = `${merged}.extend(${schemaString}.shape)`;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
result = merged;
|
|
554
|
+
} else {
|
|
555
|
+
const schemaStrings = schemas.map((s) => context.generatePropertySchema(s, currentSchema, false));
|
|
556
|
+
let merged = schemaStrings[0];
|
|
435
557
|
for (let i = 1; i < schemaStrings.length; i++) {
|
|
436
|
-
|
|
558
|
+
merged = `${merged}.and(${schemaStrings[i]})`;
|
|
437
559
|
}
|
|
438
|
-
|
|
560
|
+
result = merged;
|
|
439
561
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
merged = `${merged}.and(${schemaStrings[i]})`;
|
|
562
|
+
if (conflictDescription) {
|
|
563
|
+
result = `${result}.describe("${conflictDescription}")`;
|
|
443
564
|
}
|
|
444
|
-
return wrapNullable(
|
|
565
|
+
return wrapNullable(result, isNullable2);
|
|
445
566
|
}
|
|
446
567
|
|
|
447
568
|
// src/validators/number-validator.ts
|
|
@@ -1117,6 +1238,15 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1117
1238
|
}
|
|
1118
1239
|
return mappedSchemas;
|
|
1119
1240
|
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Resolve a $ref string to the actual schema
|
|
1243
|
+
*/
|
|
1244
|
+
resolveSchemaRef(ref) {
|
|
1245
|
+
var _a, _b;
|
|
1246
|
+
const schemaName = ref.split("/").pop();
|
|
1247
|
+
if (!schemaName) return void 0;
|
|
1248
|
+
return (_b = (_a = this.context.spec.components) == null ? void 0 : _a.schemas) == null ? void 0 : _b[schemaName];
|
|
1249
|
+
}
|
|
1120
1250
|
/**
|
|
1121
1251
|
* Resolve a schema name through any aliases to get the actual schema name
|
|
1122
1252
|
* If the schema is an alias (allOf with single $ref), return the target name
|
|
@@ -1194,7 +1324,7 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1194
1324
|
let schemaWithCatchall = baseSchema;
|
|
1195
1325
|
if (baseSchema.includes(".union([") || baseSchema.includes(".discriminatedUnion(")) {
|
|
1196
1326
|
schemaWithCatchall = baseSchema;
|
|
1197
|
-
} else if (baseSchema.includes(".
|
|
1327
|
+
} else if (baseSchema.includes(".extend(")) {
|
|
1198
1328
|
schemaWithCatchall = `${baseSchema}.catchall(z.unknown())`;
|
|
1199
1329
|
}
|
|
1200
1330
|
if (schema.unevaluatedProperties === false) {
|
|
@@ -1207,12 +1337,21 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1207
1337
|
}
|
|
1208
1338
|
/**
|
|
1209
1339
|
* Generate Zod schema for a property
|
|
1340
|
+
* @param schema - The OpenAPI schema to generate
|
|
1341
|
+
* @param currentSchema - The name of the current schema being processed (for circular ref detection)
|
|
1342
|
+
* @param isTopLevel - Whether this is a top-level schema definition
|
|
1343
|
+
* @param suppressDefaultNullable - When true, don't apply defaultNullable (used when outer schema has explicit nullable: false)
|
|
1210
1344
|
*/
|
|
1211
|
-
generatePropertySchema(schema, currentSchema, isTopLevel = false) {
|
|
1345
|
+
generatePropertySchema(schema, currentSchema, isTopLevel = false, suppressDefaultNullable = false) {
|
|
1212
1346
|
var _a, _b, _c, _d, _e;
|
|
1213
1347
|
const isCacheable = !schema.$ref && !schema.allOf && !schema.oneOf && !schema.anyOf && !currentSchema;
|
|
1214
1348
|
if (isCacheable) {
|
|
1215
|
-
const cacheKey = JSON.stringify({
|
|
1349
|
+
const cacheKey = JSON.stringify({
|
|
1350
|
+
schema,
|
|
1351
|
+
type: this.context.schemaType,
|
|
1352
|
+
mode: this.context.mode,
|
|
1353
|
+
suppressDefaultNullable
|
|
1354
|
+
});
|
|
1216
1355
|
const cached = this.schemaCache.get(cacheKey);
|
|
1217
1356
|
if (cached) {
|
|
1218
1357
|
return cached;
|
|
@@ -1221,7 +1360,10 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1221
1360
|
if ((this.context.schemaType === "request" || this.context.schemaType === "response") && schema.properties) {
|
|
1222
1361
|
schema = this.filterNestedProperties(schema);
|
|
1223
1362
|
}
|
|
1224
|
-
const
|
|
1363
|
+
const isEnum = !!schema.enum;
|
|
1364
|
+
const isConst = schema.const !== void 0;
|
|
1365
|
+
const shouldApplyDefaultNullable = !isTopLevel && !isEnum && !isConst && !suppressDefaultNullable;
|
|
1366
|
+
const effectiveDefaultNullable = shouldApplyDefaultNullable ? this.context.defaultNullable : false;
|
|
1225
1367
|
const nullable = isNullable(schema, effectiveDefaultNullable);
|
|
1226
1368
|
if (hasMultipleTypes(schema)) {
|
|
1227
1369
|
const union = this.generateMultiTypeUnion(schema, currentSchema);
|
|
@@ -1271,11 +1413,17 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1271
1413
|
return wrapNullable(zodUnion, nullable);
|
|
1272
1414
|
}
|
|
1273
1415
|
if (schema.allOf) {
|
|
1416
|
+
const explicitNullableFalse = schema.nullable === false;
|
|
1274
1417
|
let composition = generateAllOf(
|
|
1275
1418
|
schema.allOf,
|
|
1276
1419
|
nullable,
|
|
1277
|
-
{
|
|
1278
|
-
|
|
1420
|
+
{
|
|
1421
|
+
generatePropertySchema: this.generatePropertySchema.bind(this),
|
|
1422
|
+
generateInlineObjectShape: this.generateInlineObjectShape.bind(this),
|
|
1423
|
+
resolveSchemaRef: this.resolveSchemaRef.bind(this)
|
|
1424
|
+
},
|
|
1425
|
+
currentSchema,
|
|
1426
|
+
explicitNullableFalse
|
|
1279
1427
|
);
|
|
1280
1428
|
if (schema.unevaluatedProperties !== void 0) {
|
|
1281
1429
|
composition = this.applyUnevaluatedProperties(composition, schema);
|
|
@@ -1290,7 +1438,8 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1290
1438
|
nullable,
|
|
1291
1439
|
{
|
|
1292
1440
|
generatePropertySchema: this.generatePropertySchema.bind(this),
|
|
1293
|
-
resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this)
|
|
1441
|
+
resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this),
|
|
1442
|
+
resolveSchemaRef: this.resolveSchemaRef.bind(this)
|
|
1294
1443
|
},
|
|
1295
1444
|
{
|
|
1296
1445
|
passthrough: needsPassthrough,
|
|
@@ -1311,7 +1460,8 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1311
1460
|
nullable,
|
|
1312
1461
|
{
|
|
1313
1462
|
generatePropertySchema: this.generatePropertySchema.bind(this),
|
|
1314
|
-
resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this)
|
|
1463
|
+
resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this),
|
|
1464
|
+
resolveSchemaRef: this.resolveSchemaRef.bind(this)
|
|
1315
1465
|
},
|
|
1316
1466
|
{
|
|
1317
1467
|
passthrough: needsPassthrough,
|
|
@@ -1374,7 +1524,17 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1374
1524
|
);
|
|
1375
1525
|
validation = addDescription(validation, schema.description, this.context.useDescribe);
|
|
1376
1526
|
} else {
|
|
1377
|
-
|
|
1527
|
+
switch (this.context.emptyObjectBehavior) {
|
|
1528
|
+
case "strict":
|
|
1529
|
+
validation = "z.strictObject({})";
|
|
1530
|
+
break;
|
|
1531
|
+
case "loose":
|
|
1532
|
+
validation = "z.looseObject({})";
|
|
1533
|
+
break;
|
|
1534
|
+
default:
|
|
1535
|
+
validation = "z.record(z.string(), z.unknown())";
|
|
1536
|
+
break;
|
|
1537
|
+
}
|
|
1378
1538
|
validation = addDescription(validation, schema.description, this.context.useDescribe);
|
|
1379
1539
|
}
|
|
1380
1540
|
break;
|
|
@@ -1389,6 +1549,44 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1389
1549
|
}
|
|
1390
1550
|
return result;
|
|
1391
1551
|
}
|
|
1552
|
+
/**
|
|
1553
|
+
* Generate inline object shape for use with .extend()
|
|
1554
|
+
* Returns just the shape object literal: { prop1: z.string(), prop2: z.number() }
|
|
1555
|
+
*
|
|
1556
|
+
* This method is specifically for allOf compositions where we need to pass
|
|
1557
|
+
* the shape directly to .extend() instead of using z.object({...}).shape.
|
|
1558
|
+
* This avoids the .nullable().shape bug when inline objects have nullable: true.
|
|
1559
|
+
*
|
|
1560
|
+
* According to Zod docs (https://zod.dev/api?id=extend):
|
|
1561
|
+
* - .extend() accepts an object of shape definitions
|
|
1562
|
+
* - e.g., baseSchema.extend({ prop: z.string() })
|
|
1563
|
+
*/
|
|
1564
|
+
generateInlineObjectShape(schema, currentSchema) {
|
|
1565
|
+
const required = new Set(schema.required || []);
|
|
1566
|
+
const properties = [];
|
|
1567
|
+
if (schema.properties) {
|
|
1568
|
+
for (const [propName, propSchema] of Object.entries(schema.properties)) {
|
|
1569
|
+
if (!this.shouldIncludeProperty(propSchema)) {
|
|
1570
|
+
continue;
|
|
1571
|
+
}
|
|
1572
|
+
const isRequired = required.has(propName);
|
|
1573
|
+
const zodSchema = this.generatePropertySchema(propSchema, currentSchema);
|
|
1574
|
+
const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
1575
|
+
const quotedPropName = validIdentifier.test(propName) ? propName : `"${propName}"`;
|
|
1576
|
+
let propertyDef = `${quotedPropName}: ${zodSchema}`;
|
|
1577
|
+
if (!isRequired) {
|
|
1578
|
+
propertyDef += ".optional()";
|
|
1579
|
+
}
|
|
1580
|
+
properties.push(propertyDef);
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
if (properties.length === 0) {
|
|
1584
|
+
return "{}";
|
|
1585
|
+
}
|
|
1586
|
+
return `{
|
|
1587
|
+
${properties.map((p) => ` ${p}`).join(",\n")}
|
|
1588
|
+
}`;
|
|
1589
|
+
}
|
|
1392
1590
|
};
|
|
1393
1591
|
// Performance optimization: Lookup table for faster inclusion checks
|
|
1394
1592
|
_PropertyGenerator.INCLUSION_RULES = {
|
|
@@ -1532,6 +1730,59 @@ function formatFilterStatistics(stats) {
|
|
|
1532
1730
|
return lines.join("\n");
|
|
1533
1731
|
}
|
|
1534
1732
|
|
|
1733
|
+
// src/utils/ref-resolver.ts
|
|
1734
|
+
function resolveRef2(obj, spec, maxDepth = 10) {
|
|
1735
|
+
var _a, _b, _c, _d;
|
|
1736
|
+
if (!obj || typeof obj !== "object" || maxDepth <= 0) return obj;
|
|
1737
|
+
if (!obj.$ref) return obj;
|
|
1738
|
+
const ref = obj.$ref;
|
|
1739
|
+
let resolved = null;
|
|
1740
|
+
const paramMatch = ref.match(/^#\/components\/parameters\/(.+)$/);
|
|
1741
|
+
const requestBodyMatch = ref.match(/^#\/components\/requestBodies\/(.+)$/);
|
|
1742
|
+
const responseMatch = ref.match(/^#\/components\/responses\/(.+)$/);
|
|
1743
|
+
const schemaMatch = ref.match(/^#\/components\/schemas\/(.+)$/);
|
|
1744
|
+
if (paramMatch && ((_a = spec.components) == null ? void 0 : _a.parameters)) {
|
|
1745
|
+
const name = paramMatch[1];
|
|
1746
|
+
resolved = spec.components.parameters[name];
|
|
1747
|
+
} else if (requestBodyMatch && ((_b = spec.components) == null ? void 0 : _b.requestBodies)) {
|
|
1748
|
+
const name = requestBodyMatch[1];
|
|
1749
|
+
resolved = spec.components.requestBodies[name];
|
|
1750
|
+
} else if (responseMatch && ((_c = spec.components) == null ? void 0 : _c.responses)) {
|
|
1751
|
+
const name = responseMatch[1];
|
|
1752
|
+
resolved = spec.components.responses[name];
|
|
1753
|
+
} else if (schemaMatch && ((_d = spec.components) == null ? void 0 : _d.schemas)) {
|
|
1754
|
+
const name = schemaMatch[1];
|
|
1755
|
+
resolved = spec.components.schemas[name];
|
|
1756
|
+
}
|
|
1757
|
+
if (resolved) {
|
|
1758
|
+
if (resolved.$ref) {
|
|
1759
|
+
return resolveRef2(resolved, spec, maxDepth - 1);
|
|
1760
|
+
}
|
|
1761
|
+
return resolved;
|
|
1762
|
+
}
|
|
1763
|
+
return obj;
|
|
1764
|
+
}
|
|
1765
|
+
function resolveParameterRef(param, spec) {
|
|
1766
|
+
return resolveRef2(param, spec);
|
|
1767
|
+
}
|
|
1768
|
+
function mergeParameters(pathParams, operationParams, spec) {
|
|
1769
|
+
const resolvedPathParams = (pathParams || []).map((p) => resolveParameterRef(p, spec));
|
|
1770
|
+
const resolvedOperationParams = (operationParams || []).map((p) => resolveParameterRef(p, spec));
|
|
1771
|
+
const merged = [...resolvedPathParams];
|
|
1772
|
+
for (const opParam of resolvedOperationParams) {
|
|
1773
|
+
if (!opParam || typeof opParam !== "object") continue;
|
|
1774
|
+
const existingIndex = merged.findIndex(
|
|
1775
|
+
(p) => p && typeof p === "object" && p.name === opParam.name && p.in === opParam.in
|
|
1776
|
+
);
|
|
1777
|
+
if (existingIndex >= 0) {
|
|
1778
|
+
merged[existingIndex] = opParam;
|
|
1779
|
+
} else {
|
|
1780
|
+
merged.push(opParam);
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
return merged;
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1535
1786
|
// src/openapi-generator.ts
|
|
1536
1787
|
var OpenApiGenerator = class {
|
|
1537
1788
|
constructor(options) {
|
|
@@ -1541,7 +1792,7 @@ var OpenApiGenerator = class {
|
|
|
1541
1792
|
this.schemaUsageMap = /* @__PURE__ */ new Map();
|
|
1542
1793
|
this.needsZodImport = true;
|
|
1543
1794
|
this.filterStats = createFilterStatistics();
|
|
1544
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
1795
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
1545
1796
|
if (!options.input) {
|
|
1546
1797
|
throw new ConfigurationError("Input path is required", { providedOptions: options });
|
|
1547
1798
|
}
|
|
@@ -1552,18 +1803,19 @@ var OpenApiGenerator = class {
|
|
|
1552
1803
|
includeDescriptions: (_a = options.includeDescriptions) != null ? _a : true,
|
|
1553
1804
|
useDescribe: (_b = options.useDescribe) != null ? _b : false,
|
|
1554
1805
|
defaultNullable: (_c = options.defaultNullable) != null ? _c : false,
|
|
1806
|
+
emptyObjectBehavior: (_d = options.emptyObjectBehavior) != null ? _d : "loose",
|
|
1555
1807
|
schemaType: options.schemaType || "all",
|
|
1556
1808
|
prefix: options.prefix,
|
|
1557
1809
|
suffix: options.suffix,
|
|
1558
1810
|
stripSchemaPrefix: options.stripSchemaPrefix,
|
|
1559
1811
|
stripPathPrefix: options.stripPathPrefix,
|
|
1560
|
-
showStats: (
|
|
1812
|
+
showStats: (_e = options.showStats) != null ? _e : true,
|
|
1561
1813
|
request: options.request,
|
|
1562
1814
|
response: options.response,
|
|
1563
1815
|
operationFilters: options.operationFilters,
|
|
1564
1816
|
ignoreHeaders: options.ignoreHeaders,
|
|
1565
|
-
cacheSize: (
|
|
1566
|
-
batchSize: (
|
|
1817
|
+
cacheSize: (_f = options.cacheSize) != null ? _f : 1e3,
|
|
1818
|
+
batchSize: (_g = options.batchSize) != null ? _g : 10,
|
|
1567
1819
|
customDateTimeFormatRegex: options.customDateTimeFormatRegex
|
|
1568
1820
|
};
|
|
1569
1821
|
if (this.options.cacheSize) {
|
|
@@ -1634,7 +1886,8 @@ var OpenApiGenerator = class {
|
|
|
1634
1886
|
mode: this.requestOptions.mode,
|
|
1635
1887
|
includeDescriptions: this.requestOptions.includeDescriptions,
|
|
1636
1888
|
useDescribe: this.requestOptions.useDescribe,
|
|
1637
|
-
defaultNullable: (
|
|
1889
|
+
defaultNullable: (_h = this.options.defaultNullable) != null ? _h : false,
|
|
1890
|
+
emptyObjectBehavior: (_i = this.options.emptyObjectBehavior) != null ? _i : "loose",
|
|
1638
1891
|
namingOptions: {
|
|
1639
1892
|
prefix: this.options.prefix,
|
|
1640
1893
|
suffix: this.options.suffix
|
|
@@ -1704,12 +1957,6 @@ var OpenApiGenerator = class {
|
|
|
1704
1957
|
* Generate the complete output file
|
|
1705
1958
|
*/
|
|
1706
1959
|
generate() {
|
|
1707
|
-
if (!this.options.output) {
|
|
1708
|
-
throw new ConfigurationError(
|
|
1709
|
-
"Output path is required when calling generate(). Either provide an 'output' option or use generateString() to get the result as a string.",
|
|
1710
|
-
{ hasOutput: false }
|
|
1711
|
-
);
|
|
1712
|
-
}
|
|
1713
1960
|
const output = this.generateString();
|
|
1714
1961
|
const normalizedOutput = normalize(this.options.output);
|
|
1715
1962
|
this.ensureDirectoryExists(normalizedOutput);
|
|
@@ -1988,7 +2235,7 @@ var OpenApiGenerator = class {
|
|
|
1988
2235
|
* Generate schema for a component
|
|
1989
2236
|
*/
|
|
1990
2237
|
generateComponentSchema(name, schema) {
|
|
1991
|
-
var _a, _b, _c;
|
|
2238
|
+
var _a, _b, _c, _d;
|
|
1992
2239
|
if (!this.schemaDependencies.has(name)) {
|
|
1993
2240
|
this.schemaDependencies.set(name, /* @__PURE__ */ new Set());
|
|
1994
2241
|
}
|
|
@@ -2021,6 +2268,7 @@ ${typeCode}`;
|
|
|
2021
2268
|
includeDescriptions: resolvedOptions.includeDescriptions,
|
|
2022
2269
|
useDescribe: resolvedOptions.useDescribe,
|
|
2023
2270
|
defaultNullable: (_b = this.options.defaultNullable) != null ? _b : false,
|
|
2271
|
+
emptyObjectBehavior: (_c = this.options.emptyObjectBehavior) != null ? _c : "loose",
|
|
2024
2272
|
namingOptions: {
|
|
2025
2273
|
prefix: this.options.prefix,
|
|
2026
2274
|
suffix: this.options.suffix
|
|
@@ -2037,7 +2285,7 @@ ${typeCode}`;
|
|
|
2037
2285
|
const depMatch = ref.match(/^([a-z][a-zA-Z0-9]*?)Schema$/);
|
|
2038
2286
|
if (depMatch) {
|
|
2039
2287
|
const depName = depMatch[1].charAt(0).toUpperCase() + depMatch[1].slice(1);
|
|
2040
|
-
(
|
|
2288
|
+
(_d = this.schemaDependencies.get(name)) == null ? void 0 : _d.add(depName);
|
|
2041
2289
|
}
|
|
2042
2290
|
}
|
|
2043
2291
|
}
|
|
@@ -2061,10 +2309,8 @@ ${typeCode}`;
|
|
|
2061
2309
|
if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
|
|
2062
2310
|
continue;
|
|
2063
2311
|
}
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
}
|
|
2067
|
-
const queryParams = operation.parameters.filter(
|
|
2312
|
+
const allParams = mergeParameters(pathItem.parameters, operation.parameters, this.spec);
|
|
2313
|
+
const queryParams = allParams.filter(
|
|
2068
2314
|
(param) => param && typeof param === "object" && param.in === "query"
|
|
2069
2315
|
);
|
|
2070
2316
|
if (queryParams.length === 0) {
|
|
@@ -2200,10 +2446,8 @@ ${propsCode}
|
|
|
2200
2446
|
if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
|
|
2201
2447
|
continue;
|
|
2202
2448
|
}
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
}
|
|
2206
|
-
const headerParams = operation.parameters.filter(
|
|
2449
|
+
const allParams = mergeParameters(pathItem.parameters, operation.parameters, this.spec);
|
|
2450
|
+
const headerParams = allParams.filter(
|
|
2207
2451
|
(param) => param && typeof param === "object" && param.in === "header" && !this.shouldIgnoreHeader(param.name)
|
|
2208
2452
|
);
|
|
2209
2453
|
if (headerParams.length === 0) {
|
|
@@ -2293,13 +2537,23 @@ ${propsCode}
|
|
|
2293
2537
|
}
|
|
2294
2538
|
const type = schema.type;
|
|
2295
2539
|
if (type === "string") {
|
|
2540
|
+
const formatMap = {
|
|
2541
|
+
email: "z.email()",
|
|
2542
|
+
uri: "z.url()",
|
|
2543
|
+
url: "z.url()",
|
|
2544
|
+
uuid: "z.uuid()"
|
|
2545
|
+
};
|
|
2546
|
+
if (schema.format && formatMap[schema.format]) {
|
|
2547
|
+
let zodType2 = formatMap[schema.format];
|
|
2548
|
+
if (schema.minLength !== void 0) zodType2 = `${zodType2}.min(${schema.minLength})`;
|
|
2549
|
+
if (schema.maxLength !== void 0) zodType2 = `${zodType2}.max(${schema.maxLength})`;
|
|
2550
|
+
if (schema.pattern) zodType2 = `${zodType2}.regex(/${schema.pattern}/)`;
|
|
2551
|
+
return zodType2;
|
|
2552
|
+
}
|
|
2296
2553
|
let zodType = "z.string()";
|
|
2297
2554
|
if (schema.minLength !== void 0) zodType = `${zodType}.min(${schema.minLength})`;
|
|
2298
2555
|
if (schema.maxLength !== void 0) zodType = `${zodType}.max(${schema.maxLength})`;
|
|
2299
2556
|
if (schema.pattern) zodType = `${zodType}.regex(/${schema.pattern}/)`;
|
|
2300
|
-
if (schema.format === "email") zodType = `${zodType}.email()`;
|
|
2301
|
-
if (schema.format === "uri" || schema.format === "url") zodType = `${zodType}.url()`;
|
|
2302
|
-
if (schema.format === "uuid") zodType = `${zodType}.uuid()`;
|
|
2303
2557
|
return zodType;
|
|
2304
2558
|
}
|
|
2305
2559
|
if (type === "number" || type === "integer") {
|
|
@@ -2324,11 +2578,6 @@ ${propsCode}
|
|
|
2324
2578
|
}
|
|
2325
2579
|
return "z.unknown()";
|
|
2326
2580
|
}
|
|
2327
|
-
// REMOVED: generateNativeEnum method - no longer needed as we only generate Zod schemas
|
|
2328
|
-
// REMOVED: toEnumKey method - was only used by generateNativeEnum
|
|
2329
|
-
// REMOVED: addConstraintsToJSDoc method - was only used for native TypeScript types
|
|
2330
|
-
// REMOVED: generateNativeTypeDefinition method - was only used for native TypeScript types
|
|
2331
|
-
// REMOVED: generateObjectType method - was only used for native TypeScript types
|
|
2332
2581
|
/**
|
|
2333
2582
|
* Topological sort for schema dependencies
|
|
2334
2583
|
* Returns schemas in the order they should be declared
|