@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.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { O as OpenApiGeneratorOptions } from './types
|
|
2
|
-
export { C as CommonSchemaOptions, a as ConfigFile, E as ExecutionMode, b as
|
|
1
|
+
import { O as OpenApiGeneratorOptions } from './types-DZ4Bw-D5.mjs';
|
|
2
|
+
export { C as CommonSchemaOptions, a as ConfigFile, E as ExecutionMode, b as OpenAPIParameter, c as OpenAPIRequestBody, d as OpenAPIResponse, e as OpenAPISchema, f as OpenAPISpec, g as OperationFilters, R as RequestOptions, h as ResponseOptions, i as defineConfig } from './types-DZ4Bw-D5.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Custom error classes for better error handling and debugging
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { O as OpenApiGeneratorOptions } from './types
|
|
2
|
-
export { C as CommonSchemaOptions, a as ConfigFile, E as ExecutionMode, b as
|
|
1
|
+
import { O as OpenApiGeneratorOptions } from './types-DZ4Bw-D5.js';
|
|
2
|
+
export { C as CommonSchemaOptions, a as ConfigFile, E as ExecutionMode, b as OpenAPIParameter, c as OpenAPIRequestBody, d as OpenAPIResponse, e as OpenAPISchema, f as OpenAPISpec, g as OperationFilters, R as RequestOptions, h as ResponseOptions, i as defineConfig } from './types-DZ4Bw-D5.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Custom error classes for better error handling and debugging
|
package/dist/index.js
CHANGED
|
@@ -113,12 +113,12 @@ function toCamelCase(str, options) {
|
|
|
113
113
|
name = words[0].charAt(0).toLowerCase() + words[0].slice(1) + words.slice(1).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
114
114
|
}
|
|
115
115
|
if (options == null ? void 0 : options.prefix) {
|
|
116
|
-
const prefix = options.prefix.toLowerCase();
|
|
116
|
+
const prefix = options.prefix.charAt(0).toLowerCase() + options.prefix.slice(1);
|
|
117
117
|
name = prefix + name.charAt(0).toUpperCase() + name.slice(1);
|
|
118
118
|
}
|
|
119
119
|
if (options == null ? void 0 : options.suffix) {
|
|
120
|
-
const suffix = options.suffix;
|
|
121
|
-
name = name + suffix
|
|
120
|
+
const suffix = options.suffix.charAt(0).toUpperCase() + options.suffix.slice(1);
|
|
121
|
+
name = name + suffix;
|
|
122
122
|
}
|
|
123
123
|
return name;
|
|
124
124
|
}
|
|
@@ -430,12 +430,56 @@ function generateArrayValidation(schema, context) {
|
|
|
430
430
|
}
|
|
431
431
|
|
|
432
432
|
// src/validators/composition-validator.ts
|
|
433
|
+
function isDiscriminatorRequired(schemas, discriminator, context) {
|
|
434
|
+
const invalidSchemas = [];
|
|
435
|
+
for (const schema of schemas) {
|
|
436
|
+
const resolved = resolveSchema(schema, context);
|
|
437
|
+
const required = resolved.required || [];
|
|
438
|
+
if (!required.includes(discriminator)) {
|
|
439
|
+
const schemaName = schema.$ref ? schema.$ref.split("/").pop() || "inline" : "inline";
|
|
440
|
+
invalidSchemas.push(schemaName);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return {
|
|
444
|
+
valid: invalidSchemas.length === 0,
|
|
445
|
+
invalidSchemas
|
|
446
|
+
};
|
|
447
|
+
}
|
|
433
448
|
function generateUnion(schemas, discriminator, isNullable2, context, options, currentSchema) {
|
|
449
|
+
if (schemas.length === 0) {
|
|
450
|
+
console.warn(
|
|
451
|
+
"[openapi-to-zod] Warning: Empty oneOf/anyOf array encountered. This is likely a malformed OpenAPI spec. Generating z.never() as fallback."
|
|
452
|
+
);
|
|
453
|
+
return wrapNullable(
|
|
454
|
+
'z.never().describe("Empty oneOf/anyOf in OpenAPI spec - no valid schema defined")',
|
|
455
|
+
isNullable2
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
if (schemas.length === 1) {
|
|
459
|
+
let singleSchema = context.generatePropertySchema(schemas[0], currentSchema);
|
|
460
|
+
if ((options == null ? void 0 : options.passthrough) && !singleSchema.includes(".catchall(")) {
|
|
461
|
+
singleSchema = `${singleSchema}.catchall(z.unknown())`;
|
|
462
|
+
}
|
|
463
|
+
return wrapNullable(singleSchema, isNullable2);
|
|
464
|
+
}
|
|
434
465
|
if (discriminator) {
|
|
435
466
|
let resolvedSchemas = schemas;
|
|
436
467
|
if ((options == null ? void 0 : options.discriminatorMapping) && context.resolveDiscriminatorMapping) {
|
|
437
468
|
resolvedSchemas = context.resolveDiscriminatorMapping(options.discriminatorMapping, schemas);
|
|
438
469
|
}
|
|
470
|
+
const discriminatorCheck = isDiscriminatorRequired(resolvedSchemas, discriminator, context);
|
|
471
|
+
if (!discriminatorCheck.valid) {
|
|
472
|
+
console.warn(
|
|
473
|
+
`[openapi-to-zod] Warning: Discriminator "${discriminator}" is not required in schemas: ${discriminatorCheck.invalidSchemas.join(", ")}. Falling back to z.union() instead of z.discriminatedUnion().`
|
|
474
|
+
);
|
|
475
|
+
let schemaStrings3 = resolvedSchemas.map((s) => context.generatePropertySchema(s, currentSchema));
|
|
476
|
+
if (options == null ? void 0 : options.passthrough) {
|
|
477
|
+
schemaStrings3 = schemaStrings3.map((s) => s.includes(".catchall(") ? s : `${s}.catchall(z.unknown())`);
|
|
478
|
+
}
|
|
479
|
+
const fallbackDescription = `Discriminator "${discriminator}" is optional in some schemas (${discriminatorCheck.invalidSchemas.join(", ")}), using z.union() instead of z.discriminatedUnion()`;
|
|
480
|
+
const union3 = `z.union([${schemaStrings3.join(", ")}]).describe("${fallbackDescription}")`;
|
|
481
|
+
return wrapNullable(union3, isNullable2);
|
|
482
|
+
}
|
|
439
483
|
let schemaStrings2 = resolvedSchemas.map((s) => context.generatePropertySchema(s, currentSchema));
|
|
440
484
|
if (options == null ? void 0 : options.passthrough) {
|
|
441
485
|
schemaStrings2 = schemaStrings2.map((s) => s.includes(".catchall(") ? s : `${s}.catchall(z.unknown())`);
|
|
@@ -450,25 +494,102 @@ function generateUnion(schemas, discriminator, isNullable2, context, options, cu
|
|
|
450
494
|
const union = `z.union([${schemaStrings.join(", ")}])`;
|
|
451
495
|
return wrapNullable(union, isNullable2);
|
|
452
496
|
}
|
|
453
|
-
function
|
|
497
|
+
function resolveSchema(schema, context) {
|
|
498
|
+
if (schema.$ref && context.resolveSchemaRef) {
|
|
499
|
+
const resolved = context.resolveSchemaRef(schema.$ref);
|
|
500
|
+
if (resolved) {
|
|
501
|
+
return resolved;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
return schema;
|
|
505
|
+
}
|
|
506
|
+
function collectProperties(schema, context) {
|
|
507
|
+
const resolved = resolveSchema(schema, context);
|
|
508
|
+
const props = /* @__PURE__ */ new Map();
|
|
509
|
+
const sourceName = schema.$ref ? schema.$ref.split("/").pop() || "unknown" : "inline";
|
|
510
|
+
if (resolved.properties) {
|
|
511
|
+
for (const [key, value] of Object.entries(resolved.properties)) {
|
|
512
|
+
props.set(key, { schema: value, source: sourceName });
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
if (resolved.allOf) {
|
|
516
|
+
for (const subSchema of resolved.allOf) {
|
|
517
|
+
const subProps = collectProperties(subSchema, context);
|
|
518
|
+
for (const [key, value] of subProps) {
|
|
519
|
+
if (!props.has(key)) {
|
|
520
|
+
props.set(key, value);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return props;
|
|
526
|
+
}
|
|
527
|
+
function schemasMatch(a, b) {
|
|
528
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
529
|
+
}
|
|
530
|
+
function detectConflictingProperties(schemas, context) {
|
|
531
|
+
const conflicts = [];
|
|
532
|
+
const propertyMap = /* @__PURE__ */ new Map();
|
|
533
|
+
for (const schema of schemas) {
|
|
534
|
+
const schemaProps = collectProperties(schema, context);
|
|
535
|
+
for (const [propName, propInfo] of schemaProps) {
|
|
536
|
+
const existing = propertyMap.get(propName);
|
|
537
|
+
if (existing) {
|
|
538
|
+
if (!schemasMatch(existing.schema, propInfo.schema)) {
|
|
539
|
+
conflicts.push(
|
|
540
|
+
`Property "${propName}" has conflicting definitions in ${existing.source} and ${propInfo.source}`
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
} else {
|
|
544
|
+
propertyMap.set(propName, propInfo);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
return conflicts;
|
|
549
|
+
}
|
|
550
|
+
function generateAllOf(schemas, isNullable2, context, currentSchema, explicitNullableFalse = false) {
|
|
454
551
|
if (schemas.length === 1) {
|
|
455
|
-
const singleSchema = context.generatePropertySchema(schemas[0], currentSchema, false);
|
|
552
|
+
const singleSchema = context.generatePropertySchema(schemas[0], currentSchema, false, explicitNullableFalse);
|
|
456
553
|
return wrapNullable(singleSchema, isNullable2);
|
|
457
554
|
}
|
|
555
|
+
const conflicts = detectConflictingProperties(schemas, context);
|
|
556
|
+
let conflictDescription = "";
|
|
557
|
+
if (conflicts.length > 0) {
|
|
558
|
+
for (const conflict of conflicts) {
|
|
559
|
+
console.warn(`[openapi-to-zod] Warning: allOf composition conflict - ${conflict}`);
|
|
560
|
+
}
|
|
561
|
+
conflictDescription = `allOf property conflicts detected: ${conflicts.join("; ")}`;
|
|
562
|
+
}
|
|
458
563
|
const allObjects = schemas.every((s) => s.type === "object" || s.properties || s.$ref || s.allOf);
|
|
459
|
-
|
|
564
|
+
let result;
|
|
460
565
|
if (allObjects) {
|
|
461
|
-
let
|
|
566
|
+
let merged = context.generatePropertySchema(schemas[0], currentSchema, false);
|
|
567
|
+
for (let i = 1; i < schemas.length; i++) {
|
|
568
|
+
const schema = schemas[i];
|
|
569
|
+
if (schema.$ref) {
|
|
570
|
+
const refSchema = context.generatePropertySchema(schema, currentSchema, false);
|
|
571
|
+
merged = `${merged}.extend(${refSchema}.shape)`;
|
|
572
|
+
} else if (context.generateInlineObjectShape && (schema.properties || schema.type === "object")) {
|
|
573
|
+
const inlineShape = context.generateInlineObjectShape(schema, currentSchema);
|
|
574
|
+
merged = `${merged}.extend(${inlineShape})`;
|
|
575
|
+
} else {
|
|
576
|
+
const schemaString = context.generatePropertySchema(schema, currentSchema, false);
|
|
577
|
+
merged = `${merged}.extend(${schemaString}.shape)`;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
result = merged;
|
|
581
|
+
} else {
|
|
582
|
+
const schemaStrings = schemas.map((s) => context.generatePropertySchema(s, currentSchema, false));
|
|
583
|
+
let merged = schemaStrings[0];
|
|
462
584
|
for (let i = 1; i < schemaStrings.length; i++) {
|
|
463
|
-
|
|
585
|
+
merged = `${merged}.and(${schemaStrings[i]})`;
|
|
464
586
|
}
|
|
465
|
-
|
|
587
|
+
result = merged;
|
|
466
588
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
merged = `${merged}.and(${schemaStrings[i]})`;
|
|
589
|
+
if (conflictDescription) {
|
|
590
|
+
result = `${result}.describe("${conflictDescription}")`;
|
|
470
591
|
}
|
|
471
|
-
return wrapNullable(
|
|
592
|
+
return wrapNullable(result, isNullable2);
|
|
472
593
|
}
|
|
473
594
|
|
|
474
595
|
// src/validators/number-validator.ts
|
|
@@ -1144,6 +1265,15 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1144
1265
|
}
|
|
1145
1266
|
return mappedSchemas;
|
|
1146
1267
|
}
|
|
1268
|
+
/**
|
|
1269
|
+
* Resolve a $ref string to the actual schema
|
|
1270
|
+
*/
|
|
1271
|
+
resolveSchemaRef(ref) {
|
|
1272
|
+
var _a, _b;
|
|
1273
|
+
const schemaName = ref.split("/").pop();
|
|
1274
|
+
if (!schemaName) return void 0;
|
|
1275
|
+
return (_b = (_a = this.context.spec.components) == null ? void 0 : _a.schemas) == null ? void 0 : _b[schemaName];
|
|
1276
|
+
}
|
|
1147
1277
|
/**
|
|
1148
1278
|
* Resolve a schema name through any aliases to get the actual schema name
|
|
1149
1279
|
* If the schema is an alias (allOf with single $ref), return the target name
|
|
@@ -1221,7 +1351,7 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1221
1351
|
let schemaWithCatchall = baseSchema;
|
|
1222
1352
|
if (baseSchema.includes(".union([") || baseSchema.includes(".discriminatedUnion(")) {
|
|
1223
1353
|
schemaWithCatchall = baseSchema;
|
|
1224
|
-
} else if (baseSchema.includes(".
|
|
1354
|
+
} else if (baseSchema.includes(".extend(")) {
|
|
1225
1355
|
schemaWithCatchall = `${baseSchema}.catchall(z.unknown())`;
|
|
1226
1356
|
}
|
|
1227
1357
|
if (schema.unevaluatedProperties === false) {
|
|
@@ -1234,12 +1364,21 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1234
1364
|
}
|
|
1235
1365
|
/**
|
|
1236
1366
|
* Generate Zod schema for a property
|
|
1367
|
+
* @param schema - The OpenAPI schema to generate
|
|
1368
|
+
* @param currentSchema - The name of the current schema being processed (for circular ref detection)
|
|
1369
|
+
* @param isTopLevel - Whether this is a top-level schema definition
|
|
1370
|
+
* @param suppressDefaultNullable - When true, don't apply defaultNullable (used when outer schema has explicit nullable: false)
|
|
1237
1371
|
*/
|
|
1238
|
-
generatePropertySchema(schema, currentSchema, isTopLevel = false) {
|
|
1372
|
+
generatePropertySchema(schema, currentSchema, isTopLevel = false, suppressDefaultNullable = false) {
|
|
1239
1373
|
var _a, _b, _c, _d, _e;
|
|
1240
1374
|
const isCacheable = !schema.$ref && !schema.allOf && !schema.oneOf && !schema.anyOf && !currentSchema;
|
|
1241
1375
|
if (isCacheable) {
|
|
1242
|
-
const cacheKey = JSON.stringify({
|
|
1376
|
+
const cacheKey = JSON.stringify({
|
|
1377
|
+
schema,
|
|
1378
|
+
type: this.context.schemaType,
|
|
1379
|
+
mode: this.context.mode,
|
|
1380
|
+
suppressDefaultNullable
|
|
1381
|
+
});
|
|
1243
1382
|
const cached = this.schemaCache.get(cacheKey);
|
|
1244
1383
|
if (cached) {
|
|
1245
1384
|
return cached;
|
|
@@ -1248,7 +1387,10 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1248
1387
|
if ((this.context.schemaType === "request" || this.context.schemaType === "response") && schema.properties) {
|
|
1249
1388
|
schema = this.filterNestedProperties(schema);
|
|
1250
1389
|
}
|
|
1251
|
-
const
|
|
1390
|
+
const isEnum = !!schema.enum;
|
|
1391
|
+
const isConst = schema.const !== void 0;
|
|
1392
|
+
const shouldApplyDefaultNullable = !isTopLevel && !isEnum && !isConst && !suppressDefaultNullable;
|
|
1393
|
+
const effectiveDefaultNullable = shouldApplyDefaultNullable ? this.context.defaultNullable : false;
|
|
1252
1394
|
const nullable = isNullable(schema, effectiveDefaultNullable);
|
|
1253
1395
|
if (hasMultipleTypes(schema)) {
|
|
1254
1396
|
const union = this.generateMultiTypeUnion(schema, currentSchema);
|
|
@@ -1298,11 +1440,17 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1298
1440
|
return wrapNullable(zodUnion, nullable);
|
|
1299
1441
|
}
|
|
1300
1442
|
if (schema.allOf) {
|
|
1443
|
+
const explicitNullableFalse = schema.nullable === false;
|
|
1301
1444
|
let composition = generateAllOf(
|
|
1302
1445
|
schema.allOf,
|
|
1303
1446
|
nullable,
|
|
1304
|
-
{
|
|
1305
|
-
|
|
1447
|
+
{
|
|
1448
|
+
generatePropertySchema: this.generatePropertySchema.bind(this),
|
|
1449
|
+
generateInlineObjectShape: this.generateInlineObjectShape.bind(this),
|
|
1450
|
+
resolveSchemaRef: this.resolveSchemaRef.bind(this)
|
|
1451
|
+
},
|
|
1452
|
+
currentSchema,
|
|
1453
|
+
explicitNullableFalse
|
|
1306
1454
|
);
|
|
1307
1455
|
if (schema.unevaluatedProperties !== void 0) {
|
|
1308
1456
|
composition = this.applyUnevaluatedProperties(composition, schema);
|
|
@@ -1317,7 +1465,8 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1317
1465
|
nullable,
|
|
1318
1466
|
{
|
|
1319
1467
|
generatePropertySchema: this.generatePropertySchema.bind(this),
|
|
1320
|
-
resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this)
|
|
1468
|
+
resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this),
|
|
1469
|
+
resolveSchemaRef: this.resolveSchemaRef.bind(this)
|
|
1321
1470
|
},
|
|
1322
1471
|
{
|
|
1323
1472
|
passthrough: needsPassthrough,
|
|
@@ -1338,7 +1487,8 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1338
1487
|
nullable,
|
|
1339
1488
|
{
|
|
1340
1489
|
generatePropertySchema: this.generatePropertySchema.bind(this),
|
|
1341
|
-
resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this)
|
|
1490
|
+
resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this),
|
|
1491
|
+
resolveSchemaRef: this.resolveSchemaRef.bind(this)
|
|
1342
1492
|
},
|
|
1343
1493
|
{
|
|
1344
1494
|
passthrough: needsPassthrough,
|
|
@@ -1401,7 +1551,17 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1401
1551
|
);
|
|
1402
1552
|
validation = addDescription(validation, schema.description, this.context.useDescribe);
|
|
1403
1553
|
} else {
|
|
1404
|
-
|
|
1554
|
+
switch (this.context.emptyObjectBehavior) {
|
|
1555
|
+
case "strict":
|
|
1556
|
+
validation = "z.strictObject({})";
|
|
1557
|
+
break;
|
|
1558
|
+
case "loose":
|
|
1559
|
+
validation = "z.looseObject({})";
|
|
1560
|
+
break;
|
|
1561
|
+
default:
|
|
1562
|
+
validation = "z.record(z.string(), z.unknown())";
|
|
1563
|
+
break;
|
|
1564
|
+
}
|
|
1405
1565
|
validation = addDescription(validation, schema.description, this.context.useDescribe);
|
|
1406
1566
|
}
|
|
1407
1567
|
break;
|
|
@@ -1416,6 +1576,44 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1416
1576
|
}
|
|
1417
1577
|
return result;
|
|
1418
1578
|
}
|
|
1579
|
+
/**
|
|
1580
|
+
* Generate inline object shape for use with .extend()
|
|
1581
|
+
* Returns just the shape object literal: { prop1: z.string(), prop2: z.number() }
|
|
1582
|
+
*
|
|
1583
|
+
* This method is specifically for allOf compositions where we need to pass
|
|
1584
|
+
* the shape directly to .extend() instead of using z.object({...}).shape.
|
|
1585
|
+
* This avoids the .nullable().shape bug when inline objects have nullable: true.
|
|
1586
|
+
*
|
|
1587
|
+
* According to Zod docs (https://zod.dev/api?id=extend):
|
|
1588
|
+
* - .extend() accepts an object of shape definitions
|
|
1589
|
+
* - e.g., baseSchema.extend({ prop: z.string() })
|
|
1590
|
+
*/
|
|
1591
|
+
generateInlineObjectShape(schema, currentSchema) {
|
|
1592
|
+
const required = new Set(schema.required || []);
|
|
1593
|
+
const properties = [];
|
|
1594
|
+
if (schema.properties) {
|
|
1595
|
+
for (const [propName, propSchema] of Object.entries(schema.properties)) {
|
|
1596
|
+
if (!this.shouldIncludeProperty(propSchema)) {
|
|
1597
|
+
continue;
|
|
1598
|
+
}
|
|
1599
|
+
const isRequired = required.has(propName);
|
|
1600
|
+
const zodSchema = this.generatePropertySchema(propSchema, currentSchema);
|
|
1601
|
+
const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
1602
|
+
const quotedPropName = validIdentifier.test(propName) ? propName : `"${propName}"`;
|
|
1603
|
+
let propertyDef = `${quotedPropName}: ${zodSchema}`;
|
|
1604
|
+
if (!isRequired) {
|
|
1605
|
+
propertyDef += ".optional()";
|
|
1606
|
+
}
|
|
1607
|
+
properties.push(propertyDef);
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
if (properties.length === 0) {
|
|
1611
|
+
return "{}";
|
|
1612
|
+
}
|
|
1613
|
+
return `{
|
|
1614
|
+
${properties.map((p) => ` ${p}`).join(",\n")}
|
|
1615
|
+
}`;
|
|
1616
|
+
}
|
|
1419
1617
|
};
|
|
1420
1618
|
// Performance optimization: Lookup table for faster inclusion checks
|
|
1421
1619
|
_PropertyGenerator.INCLUSION_RULES = {
|
|
@@ -1559,6 +1757,59 @@ function formatFilterStatistics(stats) {
|
|
|
1559
1757
|
return lines.join("\n");
|
|
1560
1758
|
}
|
|
1561
1759
|
|
|
1760
|
+
// src/utils/ref-resolver.ts
|
|
1761
|
+
function resolveRef2(obj, spec, maxDepth = 10) {
|
|
1762
|
+
var _a, _b, _c, _d;
|
|
1763
|
+
if (!obj || typeof obj !== "object" || maxDepth <= 0) return obj;
|
|
1764
|
+
if (!obj.$ref) return obj;
|
|
1765
|
+
const ref = obj.$ref;
|
|
1766
|
+
let resolved = null;
|
|
1767
|
+
const paramMatch = ref.match(/^#\/components\/parameters\/(.+)$/);
|
|
1768
|
+
const requestBodyMatch = ref.match(/^#\/components\/requestBodies\/(.+)$/);
|
|
1769
|
+
const responseMatch = ref.match(/^#\/components\/responses\/(.+)$/);
|
|
1770
|
+
const schemaMatch = ref.match(/^#\/components\/schemas\/(.+)$/);
|
|
1771
|
+
if (paramMatch && ((_a = spec.components) == null ? void 0 : _a.parameters)) {
|
|
1772
|
+
const name = paramMatch[1];
|
|
1773
|
+
resolved = spec.components.parameters[name];
|
|
1774
|
+
} else if (requestBodyMatch && ((_b = spec.components) == null ? void 0 : _b.requestBodies)) {
|
|
1775
|
+
const name = requestBodyMatch[1];
|
|
1776
|
+
resolved = spec.components.requestBodies[name];
|
|
1777
|
+
} else if (responseMatch && ((_c = spec.components) == null ? void 0 : _c.responses)) {
|
|
1778
|
+
const name = responseMatch[1];
|
|
1779
|
+
resolved = spec.components.responses[name];
|
|
1780
|
+
} else if (schemaMatch && ((_d = spec.components) == null ? void 0 : _d.schemas)) {
|
|
1781
|
+
const name = schemaMatch[1];
|
|
1782
|
+
resolved = spec.components.schemas[name];
|
|
1783
|
+
}
|
|
1784
|
+
if (resolved) {
|
|
1785
|
+
if (resolved.$ref) {
|
|
1786
|
+
return resolveRef2(resolved, spec, maxDepth - 1);
|
|
1787
|
+
}
|
|
1788
|
+
return resolved;
|
|
1789
|
+
}
|
|
1790
|
+
return obj;
|
|
1791
|
+
}
|
|
1792
|
+
function resolveParameterRef(param, spec) {
|
|
1793
|
+
return resolveRef2(param, spec);
|
|
1794
|
+
}
|
|
1795
|
+
function mergeParameters(pathParams, operationParams, spec) {
|
|
1796
|
+
const resolvedPathParams = (pathParams || []).map((p) => resolveParameterRef(p, spec));
|
|
1797
|
+
const resolvedOperationParams = (operationParams || []).map((p) => resolveParameterRef(p, spec));
|
|
1798
|
+
const merged = [...resolvedPathParams];
|
|
1799
|
+
for (const opParam of resolvedOperationParams) {
|
|
1800
|
+
if (!opParam || typeof opParam !== "object") continue;
|
|
1801
|
+
const existingIndex = merged.findIndex(
|
|
1802
|
+
(p) => p && typeof p === "object" && p.name === opParam.name && p.in === opParam.in
|
|
1803
|
+
);
|
|
1804
|
+
if (existingIndex >= 0) {
|
|
1805
|
+
merged[existingIndex] = opParam;
|
|
1806
|
+
} else {
|
|
1807
|
+
merged.push(opParam);
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
return merged;
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1562
1813
|
// src/openapi-generator.ts
|
|
1563
1814
|
var OpenApiGenerator = class {
|
|
1564
1815
|
constructor(options) {
|
|
@@ -1568,7 +1819,7 @@ var OpenApiGenerator = class {
|
|
|
1568
1819
|
this.schemaUsageMap = /* @__PURE__ */ new Map();
|
|
1569
1820
|
this.needsZodImport = true;
|
|
1570
1821
|
this.filterStats = createFilterStatistics();
|
|
1571
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
1822
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
1572
1823
|
if (!options.input) {
|
|
1573
1824
|
throw new ConfigurationError("Input path is required", { providedOptions: options });
|
|
1574
1825
|
}
|
|
@@ -1579,18 +1830,19 @@ var OpenApiGenerator = class {
|
|
|
1579
1830
|
includeDescriptions: (_a = options.includeDescriptions) != null ? _a : true,
|
|
1580
1831
|
useDescribe: (_b = options.useDescribe) != null ? _b : false,
|
|
1581
1832
|
defaultNullable: (_c = options.defaultNullable) != null ? _c : false,
|
|
1833
|
+
emptyObjectBehavior: (_d = options.emptyObjectBehavior) != null ? _d : "loose",
|
|
1582
1834
|
schemaType: options.schemaType || "all",
|
|
1583
1835
|
prefix: options.prefix,
|
|
1584
1836
|
suffix: options.suffix,
|
|
1585
1837
|
stripSchemaPrefix: options.stripSchemaPrefix,
|
|
1586
1838
|
stripPathPrefix: options.stripPathPrefix,
|
|
1587
|
-
showStats: (
|
|
1839
|
+
showStats: (_e = options.showStats) != null ? _e : true,
|
|
1588
1840
|
request: options.request,
|
|
1589
1841
|
response: options.response,
|
|
1590
1842
|
operationFilters: options.operationFilters,
|
|
1591
1843
|
ignoreHeaders: options.ignoreHeaders,
|
|
1592
|
-
cacheSize: (
|
|
1593
|
-
batchSize: (
|
|
1844
|
+
cacheSize: (_f = options.cacheSize) != null ? _f : 1e3,
|
|
1845
|
+
batchSize: (_g = options.batchSize) != null ? _g : 10,
|
|
1594
1846
|
customDateTimeFormatRegex: options.customDateTimeFormatRegex
|
|
1595
1847
|
};
|
|
1596
1848
|
if (this.options.cacheSize) {
|
|
@@ -1661,7 +1913,8 @@ var OpenApiGenerator = class {
|
|
|
1661
1913
|
mode: this.requestOptions.mode,
|
|
1662
1914
|
includeDescriptions: this.requestOptions.includeDescriptions,
|
|
1663
1915
|
useDescribe: this.requestOptions.useDescribe,
|
|
1664
|
-
defaultNullable: (
|
|
1916
|
+
defaultNullable: (_h = this.options.defaultNullable) != null ? _h : false,
|
|
1917
|
+
emptyObjectBehavior: (_i = this.options.emptyObjectBehavior) != null ? _i : "loose",
|
|
1665
1918
|
namingOptions: {
|
|
1666
1919
|
prefix: this.options.prefix,
|
|
1667
1920
|
suffix: this.options.suffix
|
|
@@ -1731,12 +1984,6 @@ var OpenApiGenerator = class {
|
|
|
1731
1984
|
* Generate the complete output file
|
|
1732
1985
|
*/
|
|
1733
1986
|
generate() {
|
|
1734
|
-
if (!this.options.output) {
|
|
1735
|
-
throw new ConfigurationError(
|
|
1736
|
-
"Output path is required when calling generate(). Either provide an 'output' option or use generateString() to get the result as a string.",
|
|
1737
|
-
{ hasOutput: false }
|
|
1738
|
-
);
|
|
1739
|
-
}
|
|
1740
1987
|
const output = this.generateString();
|
|
1741
1988
|
const normalizedOutput = (0, import_node_path.normalize)(this.options.output);
|
|
1742
1989
|
this.ensureDirectoryExists(normalizedOutput);
|
|
@@ -2015,7 +2262,7 @@ var OpenApiGenerator = class {
|
|
|
2015
2262
|
* Generate schema for a component
|
|
2016
2263
|
*/
|
|
2017
2264
|
generateComponentSchema(name, schema) {
|
|
2018
|
-
var _a, _b, _c;
|
|
2265
|
+
var _a, _b, _c, _d;
|
|
2019
2266
|
if (!this.schemaDependencies.has(name)) {
|
|
2020
2267
|
this.schemaDependencies.set(name, /* @__PURE__ */ new Set());
|
|
2021
2268
|
}
|
|
@@ -2048,6 +2295,7 @@ ${typeCode}`;
|
|
|
2048
2295
|
includeDescriptions: resolvedOptions.includeDescriptions,
|
|
2049
2296
|
useDescribe: resolvedOptions.useDescribe,
|
|
2050
2297
|
defaultNullable: (_b = this.options.defaultNullable) != null ? _b : false,
|
|
2298
|
+
emptyObjectBehavior: (_c = this.options.emptyObjectBehavior) != null ? _c : "loose",
|
|
2051
2299
|
namingOptions: {
|
|
2052
2300
|
prefix: this.options.prefix,
|
|
2053
2301
|
suffix: this.options.suffix
|
|
@@ -2064,7 +2312,7 @@ ${typeCode}`;
|
|
|
2064
2312
|
const depMatch = ref.match(/^([a-z][a-zA-Z0-9]*?)Schema$/);
|
|
2065
2313
|
if (depMatch) {
|
|
2066
2314
|
const depName = depMatch[1].charAt(0).toUpperCase() + depMatch[1].slice(1);
|
|
2067
|
-
(
|
|
2315
|
+
(_d = this.schemaDependencies.get(name)) == null ? void 0 : _d.add(depName);
|
|
2068
2316
|
}
|
|
2069
2317
|
}
|
|
2070
2318
|
}
|
|
@@ -2088,10 +2336,8 @@ ${typeCode}`;
|
|
|
2088
2336
|
if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
|
|
2089
2337
|
continue;
|
|
2090
2338
|
}
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
}
|
|
2094
|
-
const queryParams = operation.parameters.filter(
|
|
2339
|
+
const allParams = mergeParameters(pathItem.parameters, operation.parameters, this.spec);
|
|
2340
|
+
const queryParams = allParams.filter(
|
|
2095
2341
|
(param) => param && typeof param === "object" && param.in === "query"
|
|
2096
2342
|
);
|
|
2097
2343
|
if (queryParams.length === 0) {
|
|
@@ -2227,10 +2473,8 @@ ${propsCode}
|
|
|
2227
2473
|
if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
|
|
2228
2474
|
continue;
|
|
2229
2475
|
}
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
}
|
|
2233
|
-
const headerParams = operation.parameters.filter(
|
|
2476
|
+
const allParams = mergeParameters(pathItem.parameters, operation.parameters, this.spec);
|
|
2477
|
+
const headerParams = allParams.filter(
|
|
2234
2478
|
(param) => param && typeof param === "object" && param.in === "header" && !this.shouldIgnoreHeader(param.name)
|
|
2235
2479
|
);
|
|
2236
2480
|
if (headerParams.length === 0) {
|
|
@@ -2320,13 +2564,23 @@ ${propsCode}
|
|
|
2320
2564
|
}
|
|
2321
2565
|
const type = schema.type;
|
|
2322
2566
|
if (type === "string") {
|
|
2567
|
+
const formatMap = {
|
|
2568
|
+
email: "z.email()",
|
|
2569
|
+
uri: "z.url()",
|
|
2570
|
+
url: "z.url()",
|
|
2571
|
+
uuid: "z.uuid()"
|
|
2572
|
+
};
|
|
2573
|
+
if (schema.format && formatMap[schema.format]) {
|
|
2574
|
+
let zodType2 = formatMap[schema.format];
|
|
2575
|
+
if (schema.minLength !== void 0) zodType2 = `${zodType2}.min(${schema.minLength})`;
|
|
2576
|
+
if (schema.maxLength !== void 0) zodType2 = `${zodType2}.max(${schema.maxLength})`;
|
|
2577
|
+
if (schema.pattern) zodType2 = `${zodType2}.regex(/${schema.pattern}/)`;
|
|
2578
|
+
return zodType2;
|
|
2579
|
+
}
|
|
2323
2580
|
let zodType = "z.string()";
|
|
2324
2581
|
if (schema.minLength !== void 0) zodType = `${zodType}.min(${schema.minLength})`;
|
|
2325
2582
|
if (schema.maxLength !== void 0) zodType = `${zodType}.max(${schema.maxLength})`;
|
|
2326
2583
|
if (schema.pattern) zodType = `${zodType}.regex(/${schema.pattern}/)`;
|
|
2327
|
-
if (schema.format === "email") zodType = `${zodType}.email()`;
|
|
2328
|
-
if (schema.format === "uri" || schema.format === "url") zodType = `${zodType}.url()`;
|
|
2329
|
-
if (schema.format === "uuid") zodType = `${zodType}.uuid()`;
|
|
2330
2584
|
return zodType;
|
|
2331
2585
|
}
|
|
2332
2586
|
if (type === "number" || type === "integer") {
|
|
@@ -2351,11 +2605,6 @@ ${propsCode}
|
|
|
2351
2605
|
}
|
|
2352
2606
|
return "z.unknown()";
|
|
2353
2607
|
}
|
|
2354
|
-
// REMOVED: generateNativeEnum method - no longer needed as we only generate Zod schemas
|
|
2355
|
-
// REMOVED: toEnumKey method - was only used by generateNativeEnum
|
|
2356
|
-
// REMOVED: addConstraintsToJSDoc method - was only used for native TypeScript types
|
|
2357
|
-
// REMOVED: generateNativeTypeDefinition method - was only used for native TypeScript types
|
|
2358
|
-
// REMOVED: generateObjectType method - was only used for native TypeScript types
|
|
2359
2608
|
/**
|
|
2360
2609
|
* Topological sort for schema dependencies
|
|
2361
2610
|
* Returns schemas in the order they should be declared
|