@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/cli.js
CHANGED
|
@@ -5152,12 +5152,12 @@ function toCamelCase(str, options) {
|
|
|
5152
5152
|
name = words[0].charAt(0).toLowerCase() + words[0].slice(1) + words.slice(1).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
5153
5153
|
}
|
|
5154
5154
|
if (options == null ? void 0 : options.prefix) {
|
|
5155
|
-
const prefix = options.prefix.toLowerCase();
|
|
5155
|
+
const prefix = options.prefix.charAt(0).toLowerCase() + options.prefix.slice(1);
|
|
5156
5156
|
name = prefix + name.charAt(0).toUpperCase() + name.slice(1);
|
|
5157
5157
|
}
|
|
5158
5158
|
if (options == null ? void 0 : options.suffix) {
|
|
5159
|
-
const suffix = options.suffix;
|
|
5160
|
-
name = name + suffix
|
|
5159
|
+
const suffix = options.suffix.charAt(0).toUpperCase() + options.suffix.slice(1);
|
|
5160
|
+
name = name + suffix;
|
|
5161
5161
|
}
|
|
5162
5162
|
return name;
|
|
5163
5163
|
}
|
|
@@ -5480,12 +5480,56 @@ function generateArrayValidation(schema, context) {
|
|
|
5480
5480
|
|
|
5481
5481
|
// src/validators/composition-validator.ts
|
|
5482
5482
|
init_cjs_shims();
|
|
5483
|
+
function isDiscriminatorRequired(schemas, discriminator, context) {
|
|
5484
|
+
const invalidSchemas = [];
|
|
5485
|
+
for (const schema of schemas) {
|
|
5486
|
+
const resolved = resolveSchema(schema, context);
|
|
5487
|
+
const required = resolved.required || [];
|
|
5488
|
+
if (!required.includes(discriminator)) {
|
|
5489
|
+
const schemaName = schema.$ref ? schema.$ref.split("/").pop() || "inline" : "inline";
|
|
5490
|
+
invalidSchemas.push(schemaName);
|
|
5491
|
+
}
|
|
5492
|
+
}
|
|
5493
|
+
return {
|
|
5494
|
+
valid: invalidSchemas.length === 0,
|
|
5495
|
+
invalidSchemas
|
|
5496
|
+
};
|
|
5497
|
+
}
|
|
5483
5498
|
function generateUnion(schemas, discriminator, isNullable2, context, options, currentSchema) {
|
|
5499
|
+
if (schemas.length === 0) {
|
|
5500
|
+
console.warn(
|
|
5501
|
+
"[openapi-to-zod] Warning: Empty oneOf/anyOf array encountered. This is likely a malformed OpenAPI spec. Generating z.never() as fallback."
|
|
5502
|
+
);
|
|
5503
|
+
return wrapNullable(
|
|
5504
|
+
'z.never().describe("Empty oneOf/anyOf in OpenAPI spec - no valid schema defined")',
|
|
5505
|
+
isNullable2
|
|
5506
|
+
);
|
|
5507
|
+
}
|
|
5508
|
+
if (schemas.length === 1) {
|
|
5509
|
+
let singleSchema = context.generatePropertySchema(schemas[0], currentSchema);
|
|
5510
|
+
if ((options == null ? void 0 : options.passthrough) && !singleSchema.includes(".catchall(")) {
|
|
5511
|
+
singleSchema = `${singleSchema}.catchall(z.unknown())`;
|
|
5512
|
+
}
|
|
5513
|
+
return wrapNullable(singleSchema, isNullable2);
|
|
5514
|
+
}
|
|
5484
5515
|
if (discriminator) {
|
|
5485
5516
|
let resolvedSchemas = schemas;
|
|
5486
5517
|
if ((options == null ? void 0 : options.discriminatorMapping) && context.resolveDiscriminatorMapping) {
|
|
5487
5518
|
resolvedSchemas = context.resolveDiscriminatorMapping(options.discriminatorMapping, schemas);
|
|
5488
5519
|
}
|
|
5520
|
+
const discriminatorCheck = isDiscriminatorRequired(resolvedSchemas, discriminator, context);
|
|
5521
|
+
if (!discriminatorCheck.valid) {
|
|
5522
|
+
console.warn(
|
|
5523
|
+
`[openapi-to-zod] Warning: Discriminator "${discriminator}" is not required in schemas: ${discriminatorCheck.invalidSchemas.join(", ")}. Falling back to z.union() instead of z.discriminatedUnion().`
|
|
5524
|
+
);
|
|
5525
|
+
let schemaStrings3 = resolvedSchemas.map((s) => context.generatePropertySchema(s, currentSchema));
|
|
5526
|
+
if (options == null ? void 0 : options.passthrough) {
|
|
5527
|
+
schemaStrings3 = schemaStrings3.map((s) => s.includes(".catchall(") ? s : `${s}.catchall(z.unknown())`);
|
|
5528
|
+
}
|
|
5529
|
+
const fallbackDescription = `Discriminator "${discriminator}" is optional in some schemas (${discriminatorCheck.invalidSchemas.join(", ")}), using z.union() instead of z.discriminatedUnion()`;
|
|
5530
|
+
const union3 = `z.union([${schemaStrings3.join(", ")}]).describe("${fallbackDescription}")`;
|
|
5531
|
+
return wrapNullable(union3, isNullable2);
|
|
5532
|
+
}
|
|
5489
5533
|
let schemaStrings2 = resolvedSchemas.map((s) => context.generatePropertySchema(s, currentSchema));
|
|
5490
5534
|
if (options == null ? void 0 : options.passthrough) {
|
|
5491
5535
|
schemaStrings2 = schemaStrings2.map((s) => s.includes(".catchall(") ? s : `${s}.catchall(z.unknown())`);
|
|
@@ -5500,25 +5544,102 @@ function generateUnion(schemas, discriminator, isNullable2, context, options, cu
|
|
|
5500
5544
|
const union = `z.union([${schemaStrings.join(", ")}])`;
|
|
5501
5545
|
return wrapNullable(union, isNullable2);
|
|
5502
5546
|
}
|
|
5503
|
-
function
|
|
5547
|
+
function resolveSchema(schema, context) {
|
|
5548
|
+
if (schema.$ref && context.resolveSchemaRef) {
|
|
5549
|
+
const resolved = context.resolveSchemaRef(schema.$ref);
|
|
5550
|
+
if (resolved) {
|
|
5551
|
+
return resolved;
|
|
5552
|
+
}
|
|
5553
|
+
}
|
|
5554
|
+
return schema;
|
|
5555
|
+
}
|
|
5556
|
+
function collectProperties(schema, context) {
|
|
5557
|
+
const resolved = resolveSchema(schema, context);
|
|
5558
|
+
const props = /* @__PURE__ */ new Map();
|
|
5559
|
+
const sourceName = schema.$ref ? schema.$ref.split("/").pop() || "unknown" : "inline";
|
|
5560
|
+
if (resolved.properties) {
|
|
5561
|
+
for (const [key, value] of Object.entries(resolved.properties)) {
|
|
5562
|
+
props.set(key, { schema: value, source: sourceName });
|
|
5563
|
+
}
|
|
5564
|
+
}
|
|
5565
|
+
if (resolved.allOf) {
|
|
5566
|
+
for (const subSchema of resolved.allOf) {
|
|
5567
|
+
const subProps = collectProperties(subSchema, context);
|
|
5568
|
+
for (const [key, value] of subProps) {
|
|
5569
|
+
if (!props.has(key)) {
|
|
5570
|
+
props.set(key, value);
|
|
5571
|
+
}
|
|
5572
|
+
}
|
|
5573
|
+
}
|
|
5574
|
+
}
|
|
5575
|
+
return props;
|
|
5576
|
+
}
|
|
5577
|
+
function schemasMatch(a, b) {
|
|
5578
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
5579
|
+
}
|
|
5580
|
+
function detectConflictingProperties(schemas, context) {
|
|
5581
|
+
const conflicts = [];
|
|
5582
|
+
const propertyMap = /* @__PURE__ */ new Map();
|
|
5583
|
+
for (const schema of schemas) {
|
|
5584
|
+
const schemaProps = collectProperties(schema, context);
|
|
5585
|
+
for (const [propName, propInfo] of schemaProps) {
|
|
5586
|
+
const existing = propertyMap.get(propName);
|
|
5587
|
+
if (existing) {
|
|
5588
|
+
if (!schemasMatch(existing.schema, propInfo.schema)) {
|
|
5589
|
+
conflicts.push(
|
|
5590
|
+
`Property "${propName}" has conflicting definitions in ${existing.source} and ${propInfo.source}`
|
|
5591
|
+
);
|
|
5592
|
+
}
|
|
5593
|
+
} else {
|
|
5594
|
+
propertyMap.set(propName, propInfo);
|
|
5595
|
+
}
|
|
5596
|
+
}
|
|
5597
|
+
}
|
|
5598
|
+
return conflicts;
|
|
5599
|
+
}
|
|
5600
|
+
function generateAllOf(schemas, isNullable2, context, currentSchema, explicitNullableFalse = false) {
|
|
5504
5601
|
if (schemas.length === 1) {
|
|
5505
|
-
const singleSchema = context.generatePropertySchema(schemas[0], currentSchema, false);
|
|
5602
|
+
const singleSchema = context.generatePropertySchema(schemas[0], currentSchema, false, explicitNullableFalse);
|
|
5506
5603
|
return wrapNullable(singleSchema, isNullable2);
|
|
5507
5604
|
}
|
|
5605
|
+
const conflicts = detectConflictingProperties(schemas, context);
|
|
5606
|
+
let conflictDescription = "";
|
|
5607
|
+
if (conflicts.length > 0) {
|
|
5608
|
+
for (const conflict of conflicts) {
|
|
5609
|
+
console.warn(`[openapi-to-zod] Warning: allOf composition conflict - ${conflict}`);
|
|
5610
|
+
}
|
|
5611
|
+
conflictDescription = `allOf property conflicts detected: ${conflicts.join("; ")}`;
|
|
5612
|
+
}
|
|
5508
5613
|
const allObjects = schemas.every((s) => s.type === "object" || s.properties || s.$ref || s.allOf);
|
|
5509
|
-
|
|
5614
|
+
let result;
|
|
5510
5615
|
if (allObjects) {
|
|
5511
|
-
let
|
|
5616
|
+
let merged = context.generatePropertySchema(schemas[0], currentSchema, false);
|
|
5617
|
+
for (let i = 1; i < schemas.length; i++) {
|
|
5618
|
+
const schema = schemas[i];
|
|
5619
|
+
if (schema.$ref) {
|
|
5620
|
+
const refSchema = context.generatePropertySchema(schema, currentSchema, false);
|
|
5621
|
+
merged = `${merged}.extend(${refSchema}.shape)`;
|
|
5622
|
+
} else if (context.generateInlineObjectShape && (schema.properties || schema.type === "object")) {
|
|
5623
|
+
const inlineShape = context.generateInlineObjectShape(schema, currentSchema);
|
|
5624
|
+
merged = `${merged}.extend(${inlineShape})`;
|
|
5625
|
+
} else {
|
|
5626
|
+
const schemaString = context.generatePropertySchema(schema, currentSchema, false);
|
|
5627
|
+
merged = `${merged}.extend(${schemaString}.shape)`;
|
|
5628
|
+
}
|
|
5629
|
+
}
|
|
5630
|
+
result = merged;
|
|
5631
|
+
} else {
|
|
5632
|
+
const schemaStrings = schemas.map((s) => context.generatePropertySchema(s, currentSchema, false));
|
|
5633
|
+
let merged = schemaStrings[0];
|
|
5512
5634
|
for (let i = 1; i < schemaStrings.length; i++) {
|
|
5513
|
-
|
|
5635
|
+
merged = `${merged}.and(${schemaStrings[i]})`;
|
|
5514
5636
|
}
|
|
5515
|
-
|
|
5637
|
+
result = merged;
|
|
5516
5638
|
}
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
merged = `${merged}.and(${schemaStrings[i]})`;
|
|
5639
|
+
if (conflictDescription) {
|
|
5640
|
+
result = `${result}.describe("${conflictDescription}")`;
|
|
5520
5641
|
}
|
|
5521
|
-
return wrapNullable(
|
|
5642
|
+
return wrapNullable(result, isNullable2);
|
|
5522
5643
|
}
|
|
5523
5644
|
|
|
5524
5645
|
// src/validators/number-validator.ts
|
|
@@ -6200,6 +6321,15 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
6200
6321
|
}
|
|
6201
6322
|
return mappedSchemas;
|
|
6202
6323
|
}
|
|
6324
|
+
/**
|
|
6325
|
+
* Resolve a $ref string to the actual schema
|
|
6326
|
+
*/
|
|
6327
|
+
resolveSchemaRef(ref) {
|
|
6328
|
+
var _a, _b;
|
|
6329
|
+
const schemaName = ref.split("/").pop();
|
|
6330
|
+
if (!schemaName) return void 0;
|
|
6331
|
+
return (_b = (_a = this.context.spec.components) == null ? void 0 : _a.schemas) == null ? void 0 : _b[schemaName];
|
|
6332
|
+
}
|
|
6203
6333
|
/**
|
|
6204
6334
|
* Resolve a schema name through any aliases to get the actual schema name
|
|
6205
6335
|
* If the schema is an alias (allOf with single $ref), return the target name
|
|
@@ -6277,7 +6407,7 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
6277
6407
|
let schemaWithCatchall = baseSchema;
|
|
6278
6408
|
if (baseSchema.includes(".union([") || baseSchema.includes(".discriminatedUnion(")) {
|
|
6279
6409
|
schemaWithCatchall = baseSchema;
|
|
6280
|
-
} else if (baseSchema.includes(".
|
|
6410
|
+
} else if (baseSchema.includes(".extend(")) {
|
|
6281
6411
|
schemaWithCatchall = `${baseSchema}.catchall(z.unknown())`;
|
|
6282
6412
|
}
|
|
6283
6413
|
if (schema.unevaluatedProperties === false) {
|
|
@@ -6290,12 +6420,21 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
6290
6420
|
}
|
|
6291
6421
|
/**
|
|
6292
6422
|
* Generate Zod schema for a property
|
|
6423
|
+
* @param schema - The OpenAPI schema to generate
|
|
6424
|
+
* @param currentSchema - The name of the current schema being processed (for circular ref detection)
|
|
6425
|
+
* @param isTopLevel - Whether this is a top-level schema definition
|
|
6426
|
+
* @param suppressDefaultNullable - When true, don't apply defaultNullable (used when outer schema has explicit nullable: false)
|
|
6293
6427
|
*/
|
|
6294
|
-
generatePropertySchema(schema, currentSchema, isTopLevel = false) {
|
|
6428
|
+
generatePropertySchema(schema, currentSchema, isTopLevel = false, suppressDefaultNullable = false) {
|
|
6295
6429
|
var _a, _b, _c, _d, _e;
|
|
6296
6430
|
const isCacheable = !schema.$ref && !schema.allOf && !schema.oneOf && !schema.anyOf && !currentSchema;
|
|
6297
6431
|
if (isCacheable) {
|
|
6298
|
-
const cacheKey = JSON.stringify({
|
|
6432
|
+
const cacheKey = JSON.stringify({
|
|
6433
|
+
schema,
|
|
6434
|
+
type: this.context.schemaType,
|
|
6435
|
+
mode: this.context.mode,
|
|
6436
|
+
suppressDefaultNullable
|
|
6437
|
+
});
|
|
6299
6438
|
const cached = this.schemaCache.get(cacheKey);
|
|
6300
6439
|
if (cached) {
|
|
6301
6440
|
return cached;
|
|
@@ -6304,7 +6443,10 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
6304
6443
|
if ((this.context.schemaType === "request" || this.context.schemaType === "response") && schema.properties) {
|
|
6305
6444
|
schema = this.filterNestedProperties(schema);
|
|
6306
6445
|
}
|
|
6307
|
-
const
|
|
6446
|
+
const isEnum = !!schema.enum;
|
|
6447
|
+
const isConst = schema.const !== void 0;
|
|
6448
|
+
const shouldApplyDefaultNullable = !isTopLevel && !isEnum && !isConst && !suppressDefaultNullable;
|
|
6449
|
+
const effectiveDefaultNullable = shouldApplyDefaultNullable ? this.context.defaultNullable : false;
|
|
6308
6450
|
const nullable = isNullable(schema, effectiveDefaultNullable);
|
|
6309
6451
|
if (hasMultipleTypes(schema)) {
|
|
6310
6452
|
const union = this.generateMultiTypeUnion(schema, currentSchema);
|
|
@@ -6354,11 +6496,17 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
6354
6496
|
return wrapNullable(zodUnion, nullable);
|
|
6355
6497
|
}
|
|
6356
6498
|
if (schema.allOf) {
|
|
6499
|
+
const explicitNullableFalse = schema.nullable === false;
|
|
6357
6500
|
let composition = generateAllOf(
|
|
6358
6501
|
schema.allOf,
|
|
6359
6502
|
nullable,
|
|
6360
|
-
{
|
|
6361
|
-
|
|
6503
|
+
{
|
|
6504
|
+
generatePropertySchema: this.generatePropertySchema.bind(this),
|
|
6505
|
+
generateInlineObjectShape: this.generateInlineObjectShape.bind(this),
|
|
6506
|
+
resolveSchemaRef: this.resolveSchemaRef.bind(this)
|
|
6507
|
+
},
|
|
6508
|
+
currentSchema,
|
|
6509
|
+
explicitNullableFalse
|
|
6362
6510
|
);
|
|
6363
6511
|
if (schema.unevaluatedProperties !== void 0) {
|
|
6364
6512
|
composition = this.applyUnevaluatedProperties(composition, schema);
|
|
@@ -6373,7 +6521,8 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
6373
6521
|
nullable,
|
|
6374
6522
|
{
|
|
6375
6523
|
generatePropertySchema: this.generatePropertySchema.bind(this),
|
|
6376
|
-
resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this)
|
|
6524
|
+
resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this),
|
|
6525
|
+
resolveSchemaRef: this.resolveSchemaRef.bind(this)
|
|
6377
6526
|
},
|
|
6378
6527
|
{
|
|
6379
6528
|
passthrough: needsPassthrough,
|
|
@@ -6394,7 +6543,8 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
6394
6543
|
nullable,
|
|
6395
6544
|
{
|
|
6396
6545
|
generatePropertySchema: this.generatePropertySchema.bind(this),
|
|
6397
|
-
resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this)
|
|
6546
|
+
resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this),
|
|
6547
|
+
resolveSchemaRef: this.resolveSchemaRef.bind(this)
|
|
6398
6548
|
},
|
|
6399
6549
|
{
|
|
6400
6550
|
passthrough: needsPassthrough,
|
|
@@ -6457,7 +6607,17 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
6457
6607
|
);
|
|
6458
6608
|
validation = addDescription(validation, schema.description, this.context.useDescribe);
|
|
6459
6609
|
} else {
|
|
6460
|
-
|
|
6610
|
+
switch (this.context.emptyObjectBehavior) {
|
|
6611
|
+
case "strict":
|
|
6612
|
+
validation = "z.strictObject({})";
|
|
6613
|
+
break;
|
|
6614
|
+
case "loose":
|
|
6615
|
+
validation = "z.looseObject({})";
|
|
6616
|
+
break;
|
|
6617
|
+
default:
|
|
6618
|
+
validation = "z.record(z.string(), z.unknown())";
|
|
6619
|
+
break;
|
|
6620
|
+
}
|
|
6461
6621
|
validation = addDescription(validation, schema.description, this.context.useDescribe);
|
|
6462
6622
|
}
|
|
6463
6623
|
break;
|
|
@@ -6472,6 +6632,44 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
6472
6632
|
}
|
|
6473
6633
|
return result;
|
|
6474
6634
|
}
|
|
6635
|
+
/**
|
|
6636
|
+
* Generate inline object shape for use with .extend()
|
|
6637
|
+
* Returns just the shape object literal: { prop1: z.string(), prop2: z.number() }
|
|
6638
|
+
*
|
|
6639
|
+
* This method is specifically for allOf compositions where we need to pass
|
|
6640
|
+
* the shape directly to .extend() instead of using z.object({...}).shape.
|
|
6641
|
+
* This avoids the .nullable().shape bug when inline objects have nullable: true.
|
|
6642
|
+
*
|
|
6643
|
+
* According to Zod docs (https://zod.dev/api?id=extend):
|
|
6644
|
+
* - .extend() accepts an object of shape definitions
|
|
6645
|
+
* - e.g., baseSchema.extend({ prop: z.string() })
|
|
6646
|
+
*/
|
|
6647
|
+
generateInlineObjectShape(schema, currentSchema) {
|
|
6648
|
+
const required = new Set(schema.required || []);
|
|
6649
|
+
const properties = [];
|
|
6650
|
+
if (schema.properties) {
|
|
6651
|
+
for (const [propName, propSchema] of Object.entries(schema.properties)) {
|
|
6652
|
+
if (!this.shouldIncludeProperty(propSchema)) {
|
|
6653
|
+
continue;
|
|
6654
|
+
}
|
|
6655
|
+
const isRequired = required.has(propName);
|
|
6656
|
+
const zodSchema = this.generatePropertySchema(propSchema, currentSchema);
|
|
6657
|
+
const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
6658
|
+
const quotedPropName = validIdentifier.test(propName) ? propName : `"${propName}"`;
|
|
6659
|
+
let propertyDef = `${quotedPropName}: ${zodSchema}`;
|
|
6660
|
+
if (!isRequired) {
|
|
6661
|
+
propertyDef += ".optional()";
|
|
6662
|
+
}
|
|
6663
|
+
properties.push(propertyDef);
|
|
6664
|
+
}
|
|
6665
|
+
}
|
|
6666
|
+
if (properties.length === 0) {
|
|
6667
|
+
return "{}";
|
|
6668
|
+
}
|
|
6669
|
+
return `{
|
|
6670
|
+
${properties.map((p) => ` ${p}`).join(",\n")}
|
|
6671
|
+
}`;
|
|
6672
|
+
}
|
|
6475
6673
|
};
|
|
6476
6674
|
// Performance optimization: Lookup table for faster inclusion checks
|
|
6477
6675
|
_PropertyGenerator.INCLUSION_RULES = {
|
|
@@ -6616,6 +6814,60 @@ function formatFilterStatistics(stats) {
|
|
|
6616
6814
|
return lines.join("\n");
|
|
6617
6815
|
}
|
|
6618
6816
|
|
|
6817
|
+
// src/utils/ref-resolver.ts
|
|
6818
|
+
init_cjs_shims();
|
|
6819
|
+
function resolveRef2(obj, spec, maxDepth = 10) {
|
|
6820
|
+
var _a, _b, _c, _d;
|
|
6821
|
+
if (!obj || typeof obj !== "object" || maxDepth <= 0) return obj;
|
|
6822
|
+
if (!obj.$ref) return obj;
|
|
6823
|
+
const ref = obj.$ref;
|
|
6824
|
+
let resolved = null;
|
|
6825
|
+
const paramMatch = ref.match(/^#\/components\/parameters\/(.+)$/);
|
|
6826
|
+
const requestBodyMatch = ref.match(/^#\/components\/requestBodies\/(.+)$/);
|
|
6827
|
+
const responseMatch = ref.match(/^#\/components\/responses\/(.+)$/);
|
|
6828
|
+
const schemaMatch = ref.match(/^#\/components\/schemas\/(.+)$/);
|
|
6829
|
+
if (paramMatch && ((_a = spec.components) == null ? void 0 : _a.parameters)) {
|
|
6830
|
+
const name = paramMatch[1];
|
|
6831
|
+
resolved = spec.components.parameters[name];
|
|
6832
|
+
} else if (requestBodyMatch && ((_b = spec.components) == null ? void 0 : _b.requestBodies)) {
|
|
6833
|
+
const name = requestBodyMatch[1];
|
|
6834
|
+
resolved = spec.components.requestBodies[name];
|
|
6835
|
+
} else if (responseMatch && ((_c = spec.components) == null ? void 0 : _c.responses)) {
|
|
6836
|
+
const name = responseMatch[1];
|
|
6837
|
+
resolved = spec.components.responses[name];
|
|
6838
|
+
} else if (schemaMatch && ((_d = spec.components) == null ? void 0 : _d.schemas)) {
|
|
6839
|
+
const name = schemaMatch[1];
|
|
6840
|
+
resolved = spec.components.schemas[name];
|
|
6841
|
+
}
|
|
6842
|
+
if (resolved) {
|
|
6843
|
+
if (resolved.$ref) {
|
|
6844
|
+
return resolveRef2(resolved, spec, maxDepth - 1);
|
|
6845
|
+
}
|
|
6846
|
+
return resolved;
|
|
6847
|
+
}
|
|
6848
|
+
return obj;
|
|
6849
|
+
}
|
|
6850
|
+
function resolveParameterRef(param, spec) {
|
|
6851
|
+
return resolveRef2(param, spec);
|
|
6852
|
+
}
|
|
6853
|
+
function mergeParameters(pathParams, operationParams, spec) {
|
|
6854
|
+
const resolvedPathParams = (pathParams || []).map((p) => resolveParameterRef(p, spec));
|
|
6855
|
+
const resolvedOperationParams = (operationParams || []).map((p) => resolveParameterRef(p, spec));
|
|
6856
|
+
const merged = [...resolvedPathParams];
|
|
6857
|
+
for (const opParam of resolvedOperationParams) {
|
|
6858
|
+
if (!opParam || typeof opParam !== "object") continue;
|
|
6859
|
+
const existingIndex = merged.findIndex(
|
|
6860
|
+
(p) => p && typeof p === "object" && p.name === opParam.name && p.in === opParam.in
|
|
6861
|
+
);
|
|
6862
|
+
if (existingIndex >= 0) {
|
|
6863
|
+
merged[existingIndex] = opParam;
|
|
6864
|
+
} else {
|
|
6865
|
+
merged.push(opParam);
|
|
6866
|
+
}
|
|
6867
|
+
}
|
|
6868
|
+
return merged;
|
|
6869
|
+
}
|
|
6870
|
+
|
|
6619
6871
|
// src/openapi-generator.ts
|
|
6620
6872
|
var OpenApiGenerator = class {
|
|
6621
6873
|
constructor(options) {
|
|
@@ -6625,7 +6877,7 @@ var OpenApiGenerator = class {
|
|
|
6625
6877
|
this.schemaUsageMap = /* @__PURE__ */ new Map();
|
|
6626
6878
|
this.needsZodImport = true;
|
|
6627
6879
|
this.filterStats = createFilterStatistics();
|
|
6628
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
6880
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
6629
6881
|
if (!options.input) {
|
|
6630
6882
|
throw new ConfigurationError("Input path is required", { providedOptions: options });
|
|
6631
6883
|
}
|
|
@@ -6636,18 +6888,19 @@ var OpenApiGenerator = class {
|
|
|
6636
6888
|
includeDescriptions: (_a = options.includeDescriptions) != null ? _a : true,
|
|
6637
6889
|
useDescribe: (_b = options.useDescribe) != null ? _b : false,
|
|
6638
6890
|
defaultNullable: (_c = options.defaultNullable) != null ? _c : false,
|
|
6891
|
+
emptyObjectBehavior: (_d = options.emptyObjectBehavior) != null ? _d : "loose",
|
|
6639
6892
|
schemaType: options.schemaType || "all",
|
|
6640
6893
|
prefix: options.prefix,
|
|
6641
6894
|
suffix: options.suffix,
|
|
6642
6895
|
stripSchemaPrefix: options.stripSchemaPrefix,
|
|
6643
6896
|
stripPathPrefix: options.stripPathPrefix,
|
|
6644
|
-
showStats: (
|
|
6897
|
+
showStats: (_e = options.showStats) != null ? _e : true,
|
|
6645
6898
|
request: options.request,
|
|
6646
6899
|
response: options.response,
|
|
6647
6900
|
operationFilters: options.operationFilters,
|
|
6648
6901
|
ignoreHeaders: options.ignoreHeaders,
|
|
6649
|
-
cacheSize: (
|
|
6650
|
-
batchSize: (
|
|
6902
|
+
cacheSize: (_f = options.cacheSize) != null ? _f : 1e3,
|
|
6903
|
+
batchSize: (_g = options.batchSize) != null ? _g : 10,
|
|
6651
6904
|
customDateTimeFormatRegex: options.customDateTimeFormatRegex
|
|
6652
6905
|
};
|
|
6653
6906
|
if (this.options.cacheSize) {
|
|
@@ -6718,7 +6971,8 @@ var OpenApiGenerator = class {
|
|
|
6718
6971
|
mode: this.requestOptions.mode,
|
|
6719
6972
|
includeDescriptions: this.requestOptions.includeDescriptions,
|
|
6720
6973
|
useDescribe: this.requestOptions.useDescribe,
|
|
6721
|
-
defaultNullable: (
|
|
6974
|
+
defaultNullable: (_h = this.options.defaultNullable) != null ? _h : false,
|
|
6975
|
+
emptyObjectBehavior: (_i = this.options.emptyObjectBehavior) != null ? _i : "loose",
|
|
6722
6976
|
namingOptions: {
|
|
6723
6977
|
prefix: this.options.prefix,
|
|
6724
6978
|
suffix: this.options.suffix
|
|
@@ -6788,12 +7042,6 @@ var OpenApiGenerator = class {
|
|
|
6788
7042
|
* Generate the complete output file
|
|
6789
7043
|
*/
|
|
6790
7044
|
generate() {
|
|
6791
|
-
if (!this.options.output) {
|
|
6792
|
-
throw new ConfigurationError(
|
|
6793
|
-
"Output path is required when calling generate(). Either provide an 'output' option or use generateString() to get the result as a string.",
|
|
6794
|
-
{ hasOutput: false }
|
|
6795
|
-
);
|
|
6796
|
-
}
|
|
6797
7045
|
const output = this.generateString();
|
|
6798
7046
|
const normalizedOutput = (0, import_node_path.normalize)(this.options.output);
|
|
6799
7047
|
this.ensureDirectoryExists(normalizedOutput);
|
|
@@ -7072,7 +7320,7 @@ var OpenApiGenerator = class {
|
|
|
7072
7320
|
* Generate schema for a component
|
|
7073
7321
|
*/
|
|
7074
7322
|
generateComponentSchema(name, schema) {
|
|
7075
|
-
var _a, _b, _c;
|
|
7323
|
+
var _a, _b, _c, _d;
|
|
7076
7324
|
if (!this.schemaDependencies.has(name)) {
|
|
7077
7325
|
this.schemaDependencies.set(name, /* @__PURE__ */ new Set());
|
|
7078
7326
|
}
|
|
@@ -7105,6 +7353,7 @@ ${typeCode}`;
|
|
|
7105
7353
|
includeDescriptions: resolvedOptions.includeDescriptions,
|
|
7106
7354
|
useDescribe: resolvedOptions.useDescribe,
|
|
7107
7355
|
defaultNullable: (_b = this.options.defaultNullable) != null ? _b : false,
|
|
7356
|
+
emptyObjectBehavior: (_c = this.options.emptyObjectBehavior) != null ? _c : "loose",
|
|
7108
7357
|
namingOptions: {
|
|
7109
7358
|
prefix: this.options.prefix,
|
|
7110
7359
|
suffix: this.options.suffix
|
|
@@ -7121,7 +7370,7 @@ ${typeCode}`;
|
|
|
7121
7370
|
const depMatch = ref.match(/^([a-z][a-zA-Z0-9]*?)Schema$/);
|
|
7122
7371
|
if (depMatch) {
|
|
7123
7372
|
const depName = depMatch[1].charAt(0).toUpperCase() + depMatch[1].slice(1);
|
|
7124
|
-
(
|
|
7373
|
+
(_d = this.schemaDependencies.get(name)) == null ? void 0 : _d.add(depName);
|
|
7125
7374
|
}
|
|
7126
7375
|
}
|
|
7127
7376
|
}
|
|
@@ -7145,10 +7394,8 @@ ${typeCode}`;
|
|
|
7145
7394
|
if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
|
|
7146
7395
|
continue;
|
|
7147
7396
|
}
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
}
|
|
7151
|
-
const queryParams = operation.parameters.filter(
|
|
7397
|
+
const allParams = mergeParameters(pathItem.parameters, operation.parameters, this.spec);
|
|
7398
|
+
const queryParams = allParams.filter(
|
|
7152
7399
|
(param) => param && typeof param === "object" && param.in === "query"
|
|
7153
7400
|
);
|
|
7154
7401
|
if (queryParams.length === 0) {
|
|
@@ -7284,10 +7531,8 @@ ${propsCode}
|
|
|
7284
7531
|
if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
|
|
7285
7532
|
continue;
|
|
7286
7533
|
}
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
}
|
|
7290
|
-
const headerParams = operation.parameters.filter(
|
|
7534
|
+
const allParams = mergeParameters(pathItem.parameters, operation.parameters, this.spec);
|
|
7535
|
+
const headerParams = allParams.filter(
|
|
7291
7536
|
(param) => param && typeof param === "object" && param.in === "header" && !this.shouldIgnoreHeader(param.name)
|
|
7292
7537
|
);
|
|
7293
7538
|
if (headerParams.length === 0) {
|
|
@@ -7377,13 +7622,23 @@ ${propsCode}
|
|
|
7377
7622
|
}
|
|
7378
7623
|
const type = schema.type;
|
|
7379
7624
|
if (type === "string") {
|
|
7625
|
+
const formatMap = {
|
|
7626
|
+
email: "z.email()",
|
|
7627
|
+
uri: "z.url()",
|
|
7628
|
+
url: "z.url()",
|
|
7629
|
+
uuid: "z.uuid()"
|
|
7630
|
+
};
|
|
7631
|
+
if (schema.format && formatMap[schema.format]) {
|
|
7632
|
+
let zodType2 = formatMap[schema.format];
|
|
7633
|
+
if (schema.minLength !== void 0) zodType2 = `${zodType2}.min(${schema.minLength})`;
|
|
7634
|
+
if (schema.maxLength !== void 0) zodType2 = `${zodType2}.max(${schema.maxLength})`;
|
|
7635
|
+
if (schema.pattern) zodType2 = `${zodType2}.regex(/${schema.pattern}/)`;
|
|
7636
|
+
return zodType2;
|
|
7637
|
+
}
|
|
7380
7638
|
let zodType = "z.string()";
|
|
7381
7639
|
if (schema.minLength !== void 0) zodType = `${zodType}.min(${schema.minLength})`;
|
|
7382
7640
|
if (schema.maxLength !== void 0) zodType = `${zodType}.max(${schema.maxLength})`;
|
|
7383
7641
|
if (schema.pattern) zodType = `${zodType}.regex(/${schema.pattern}/)`;
|
|
7384
|
-
if (schema.format === "email") zodType = `${zodType}.email()`;
|
|
7385
|
-
if (schema.format === "uri" || schema.format === "url") zodType = `${zodType}.url()`;
|
|
7386
|
-
if (schema.format === "uuid") zodType = `${zodType}.uuid()`;
|
|
7387
7642
|
return zodType;
|
|
7388
7643
|
}
|
|
7389
7644
|
if (type === "number" || type === "integer") {
|
|
@@ -7408,11 +7663,6 @@ ${propsCode}
|
|
|
7408
7663
|
}
|
|
7409
7664
|
return "z.unknown()";
|
|
7410
7665
|
}
|
|
7411
|
-
// REMOVED: generateNativeEnum method - no longer needed as we only generate Zod schemas
|
|
7412
|
-
// REMOVED: toEnumKey method - was only used by generateNativeEnum
|
|
7413
|
-
// REMOVED: addConstraintsToJSDoc method - was only used for native TypeScript types
|
|
7414
|
-
// REMOVED: generateNativeTypeDefinition method - was only used for native TypeScript types
|
|
7415
|
-
// REMOVED: generateObjectType method - was only used for native TypeScript types
|
|
7416
7666
|
/**
|
|
7417
7667
|
* Topological sort for schema dependencies
|
|
7418
7668
|
* Returns schemas in the order they should be declared
|
|
@@ -7519,7 +7769,8 @@ var RequestResponseOptionsSchema = import_zod.z.strictObject({
|
|
|
7519
7769
|
mode: import_zod.z.enum(["strict", "normal", "loose"]).optional(),
|
|
7520
7770
|
useDescribe: import_zod.z.boolean().optional(),
|
|
7521
7771
|
includeDescriptions: import_zod.z.boolean().optional(),
|
|
7522
|
-
defaultNullable: import_zod.z.boolean().optional()
|
|
7772
|
+
defaultNullable: import_zod.z.boolean().optional(),
|
|
7773
|
+
emptyObjectBehavior: import_zod.z.enum(["strict", "loose", "record"]).optional()
|
|
7523
7774
|
});
|
|
7524
7775
|
var OperationFiltersSchema = import_zod.z.strictObject({
|
|
7525
7776
|
includeTags: import_zod.z.array(import_zod.z.string()).optional(),
|
|
@@ -7603,6 +7854,7 @@ var OpenApiGeneratorOptionsSchema = import_zod2.z.strictObject({
|
|
|
7603
7854
|
includeDescriptions: import_zod2.z.boolean().optional(),
|
|
7604
7855
|
useDescribe: import_zod2.z.boolean().optional(),
|
|
7605
7856
|
defaultNullable: import_zod2.z.boolean().optional(),
|
|
7857
|
+
emptyObjectBehavior: import_zod2.z.enum(["strict", "loose", "record"]).optional(),
|
|
7606
7858
|
schemaType: import_zod2.z.enum(["all", "request", "response"]).optional(),
|
|
7607
7859
|
prefix: import_zod2.z.string().optional(),
|
|
7608
7860
|
suffix: import_zod2.z.string().optional(),
|
|
@@ -7635,6 +7887,7 @@ var ConfigFileSchema = import_zod2.z.strictObject({
|
|
|
7635
7887
|
includeDescriptions: import_zod2.z.boolean().optional(),
|
|
7636
7888
|
useDescribe: import_zod2.z.boolean().optional(),
|
|
7637
7889
|
defaultNullable: import_zod2.z.boolean().optional(),
|
|
7890
|
+
emptyObjectBehavior: import_zod2.z.enum(["strict", "loose", "record"]).optional(),
|
|
7638
7891
|
schemaType: import_zod2.z.enum(["all", "request", "response"]).optional(),
|
|
7639
7892
|
prefix: import_zod2.z.string().optional(),
|
|
7640
7893
|
suffix: import_zod2.z.string().optional(),
|
|
@@ -7708,6 +7961,7 @@ function mergeConfigWithDefaults(config) {
|
|
|
7708
7961
|
includeDescriptions: defaults.includeDescriptions,
|
|
7709
7962
|
useDescribe: defaults.useDescribe,
|
|
7710
7963
|
defaultNullable: defaults.defaultNullable,
|
|
7964
|
+
emptyObjectBehavior: defaults.emptyObjectBehavior,
|
|
7711
7965
|
schemaType: defaults.schemaType,
|
|
7712
7966
|
prefix: defaults.prefix,
|
|
7713
7967
|
suffix: defaults.suffix,
|