@cerios/openapi-to-zod 0.1.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -63,11 +63,9 @@ type TypeMode = "inferred" | "native";
63
63
  */
64
64
  type NativeEnumType = "union" | "enum";
65
65
  /**
66
- * Options that can be overridden per request/response context
67
- * These options override root-level options when specified.
68
- * Resolution order: root options → request/response overrides (nested wins silently)
66
+ * Common options shared by both request and response contexts
69
67
  */
70
- interface RequestResponseOptions {
68
+ interface CommonSchemaOptions {
71
69
  /**
72
70
  * Object validation mode
73
71
  * - 'strict': Uses z.strictObject() - no additional properties allowed
@@ -90,10 +88,16 @@ interface RequestResponseOptions {
90
88
  * Whether to include descriptions as JSDoc comments
91
89
  */
92
90
  includeDescriptions?: boolean;
91
+ }
92
+ /**
93
+ * Request-specific options that can override root-level options
94
+ * Requests support native TypeScript type generation as an alternative to Zod schemas
95
+ */
96
+ interface RequestOptions extends CommonSchemaOptions {
93
97
  /**
94
- * Type generation mode (only for requests)
98
+ * Type generation mode
95
99
  * - 'inferred': Generate Zod schemas with z.infer types (default)
96
- * - 'native': Generate native TypeScript types
100
+ * - 'native': Generate native TypeScript types without Zod validation
97
101
  */
98
102
  typeMode?: TypeMode;
99
103
  /**
@@ -103,6 +107,12 @@ interface RequestResponseOptions {
103
107
  */
104
108
  nativeEnumType?: NativeEnumType;
105
109
  }
110
+ /**
111
+ * Response-specific options that can override root-level options
112
+ * Responses always use Zod schemas for runtime validation
113
+ */
114
+ interface ResponseOptions extends CommonSchemaOptions {
115
+ }
106
116
  interface GeneratorOptions {
107
117
  /**
108
118
  * Object validation mode
@@ -168,13 +178,15 @@ interface GeneratorOptions {
168
178
  /**
169
179
  * Request-specific options that override root-level options
170
180
  * Applied when schemas are used in request contexts
181
+ * Supports native TypeScript type generation
171
182
  */
172
- request?: Partial<RequestResponseOptions>;
183
+ request?: RequestOptions;
173
184
  /**
174
185
  * Response-specific options that override root-level options
175
186
  * Applied when schemas are used in response contexts
187
+ * Always generates Zod schemas for runtime validation
176
188
  */
177
- response?: Partial<RequestResponseOptions>;
189
+ response?: ResponseOptions;
178
190
  }
179
191
  interface OpenAPISchema {
180
192
  type?: string | string[];
@@ -243,16 +255,6 @@ interface OpenAPISpec {
243
255
  * - 'sequential': Process specs one at a time (safer for resource constraints)
244
256
  */
245
257
  type ExecutionMode = "parallel" | "sequential";
246
- /**
247
- * Configuration for a single OpenAPI spec
248
- * Extends GeneratorOptions with all the same properties
249
- */
250
- interface SpecConfig extends GeneratorOptions {
251
- /**
252
- * Optional name/identifier for this spec (for logging purposes)
253
- */
254
- name?: string;
255
- }
256
258
  /**
257
259
  * Root configuration file structure
258
260
  */
@@ -266,7 +268,7 @@ interface ConfigFile {
266
268
  * Array of OpenAPI specifications to process
267
269
  * Each spec must have input and output paths
268
270
  */
269
- specs: SpecConfig[];
271
+ specs: GeneratorOptions[];
270
272
  /**
271
273
  * Execution mode for batch processing
272
274
  * @default "parallel"
@@ -371,6 +373,14 @@ declare class ZodSchemaGenerator {
371
373
  * Generate schema for a component
372
374
  */
373
375
  private generateComponentSchema;
376
+ /**
377
+ * Generate query parameter schemas for each operation
378
+ */
379
+ private generateQueryParameterSchemas;
380
+ /**
381
+ * Generate Zod type for a query parameter schema
382
+ */
383
+ private generateQueryParamType;
374
384
  /**
375
385
  * Generate native TypeScript enum
376
386
  */
@@ -402,4 +412,4 @@ declare class ZodSchemaGenerator {
402
412
  private generateStats;
403
413
  }
404
414
 
405
- export { CircularReferenceError, CliOptionsError, type ConfigFile, ConfigValidationError, type ExecutionMode, FileOperationError, GeneratorError, type GeneratorOptions, type OpenAPISpec, SchemaGenerationError, type SpecConfig, SpecValidationError, ZodSchemaGenerator, defineConfig };
415
+ export { CircularReferenceError, CliOptionsError, type ConfigFile, ConfigValidationError, type ExecutionMode, FileOperationError, GeneratorError, type GeneratorOptions, type OpenAPISpec, SchemaGenerationError, SpecValidationError, ZodSchemaGenerator, defineConfig };
package/dist/index.d.ts CHANGED
@@ -63,11 +63,9 @@ type TypeMode = "inferred" | "native";
63
63
  */
64
64
  type NativeEnumType = "union" | "enum";
65
65
  /**
66
- * Options that can be overridden per request/response context
67
- * These options override root-level options when specified.
68
- * Resolution order: root options → request/response overrides (nested wins silently)
66
+ * Common options shared by both request and response contexts
69
67
  */
70
- interface RequestResponseOptions {
68
+ interface CommonSchemaOptions {
71
69
  /**
72
70
  * Object validation mode
73
71
  * - 'strict': Uses z.strictObject() - no additional properties allowed
@@ -90,10 +88,16 @@ interface RequestResponseOptions {
90
88
  * Whether to include descriptions as JSDoc comments
91
89
  */
92
90
  includeDescriptions?: boolean;
91
+ }
92
+ /**
93
+ * Request-specific options that can override root-level options
94
+ * Requests support native TypeScript type generation as an alternative to Zod schemas
95
+ */
96
+ interface RequestOptions extends CommonSchemaOptions {
93
97
  /**
94
- * Type generation mode (only for requests)
98
+ * Type generation mode
95
99
  * - 'inferred': Generate Zod schemas with z.infer types (default)
96
- * - 'native': Generate native TypeScript types
100
+ * - 'native': Generate native TypeScript types without Zod validation
97
101
  */
98
102
  typeMode?: TypeMode;
99
103
  /**
@@ -103,6 +107,12 @@ interface RequestResponseOptions {
103
107
  */
104
108
  nativeEnumType?: NativeEnumType;
105
109
  }
110
+ /**
111
+ * Response-specific options that can override root-level options
112
+ * Responses always use Zod schemas for runtime validation
113
+ */
114
+ interface ResponseOptions extends CommonSchemaOptions {
115
+ }
106
116
  interface GeneratorOptions {
107
117
  /**
108
118
  * Object validation mode
@@ -168,13 +178,15 @@ interface GeneratorOptions {
168
178
  /**
169
179
  * Request-specific options that override root-level options
170
180
  * Applied when schemas are used in request contexts
181
+ * Supports native TypeScript type generation
171
182
  */
172
- request?: Partial<RequestResponseOptions>;
183
+ request?: RequestOptions;
173
184
  /**
174
185
  * Response-specific options that override root-level options
175
186
  * Applied when schemas are used in response contexts
187
+ * Always generates Zod schemas for runtime validation
176
188
  */
177
- response?: Partial<RequestResponseOptions>;
189
+ response?: ResponseOptions;
178
190
  }
179
191
  interface OpenAPISchema {
180
192
  type?: string | string[];
@@ -243,16 +255,6 @@ interface OpenAPISpec {
243
255
  * - 'sequential': Process specs one at a time (safer for resource constraints)
244
256
  */
245
257
  type ExecutionMode = "parallel" | "sequential";
246
- /**
247
- * Configuration for a single OpenAPI spec
248
- * Extends GeneratorOptions with all the same properties
249
- */
250
- interface SpecConfig extends GeneratorOptions {
251
- /**
252
- * Optional name/identifier for this spec (for logging purposes)
253
- */
254
- name?: string;
255
- }
256
258
  /**
257
259
  * Root configuration file structure
258
260
  */
@@ -266,7 +268,7 @@ interface ConfigFile {
266
268
  * Array of OpenAPI specifications to process
267
269
  * Each spec must have input and output paths
268
270
  */
269
- specs: SpecConfig[];
271
+ specs: GeneratorOptions[];
270
272
  /**
271
273
  * Execution mode for batch processing
272
274
  * @default "parallel"
@@ -371,6 +373,14 @@ declare class ZodSchemaGenerator {
371
373
  * Generate schema for a component
372
374
  */
373
375
  private generateComponentSchema;
376
+ /**
377
+ * Generate query parameter schemas for each operation
378
+ */
379
+ private generateQueryParameterSchemas;
380
+ /**
381
+ * Generate Zod type for a query parameter schema
382
+ */
383
+ private generateQueryParamType;
374
384
  /**
375
385
  * Generate native TypeScript enum
376
386
  */
@@ -402,4 +412,4 @@ declare class ZodSchemaGenerator {
402
412
  private generateStats;
403
413
  }
404
414
 
405
- export { CircularReferenceError, CliOptionsError, type ConfigFile, ConfigValidationError, type ExecutionMode, FileOperationError, GeneratorError, type GeneratorOptions, type OpenAPISpec, SchemaGenerationError, type SpecConfig, SpecValidationError, ZodSchemaGenerator, defineConfig };
415
+ export { CircularReferenceError, CliOptionsError, type ConfigFile, ConfigValidationError, type ExecutionMode, FileOperationError, GeneratorError, type GeneratorOptions, type OpenAPISpec, SchemaGenerationError, SpecValidationError, ZodSchemaGenerator, defineConfig };
package/dist/index.js CHANGED
@@ -147,7 +147,7 @@ function generateEnum(name, values, options) {
147
147
  const enumCode = `export enum ${enumName} {
148
148
  ${enumEntries}
149
149
  }`;
150
- const schemaCode2 = `export const ${schemaName} = z.enum(${enumName});`;
150
+ const schemaCode2 = `export const ${schemaName} = z.nativeEnum(${enumName});`;
151
151
  const typeCode2 = `export type ${name} = z.infer<typeof ${schemaName}>;`;
152
152
  return { enumCode, schemaCode: schemaCode2, typeCode: typeCode2 };
153
153
  }
@@ -330,20 +330,20 @@ function generateArrayValidation(schema, context) {
330
330
  }
331
331
 
332
332
  // src/validators/composition-validator.ts
333
- function generateUnion(schemas, discriminator, isNullable2, context, options) {
333
+ function generateUnion(schemas, discriminator, isNullable2, context, options, currentSchema) {
334
334
  if (discriminator) {
335
335
  let resolvedSchemas = schemas;
336
336
  if ((options == null ? void 0 : options.discriminatorMapping) && context.resolveDiscriminatorMapping) {
337
337
  resolvedSchemas = context.resolveDiscriminatorMapping(options.discriminatorMapping, schemas);
338
338
  }
339
- let schemaStrings2 = resolvedSchemas.map((s) => context.generatePropertySchema(s));
339
+ let schemaStrings2 = resolvedSchemas.map((s) => context.generatePropertySchema(s, currentSchema));
340
340
  if (options == null ? void 0 : options.passthrough) {
341
341
  schemaStrings2 = schemaStrings2.map((s) => s.includes(".catchall(") ? s : `${s}.catchall(z.unknown())`);
342
342
  }
343
343
  const union2 = `z.discriminatedUnion("${discriminator}", [${schemaStrings2.join(", ")}])`;
344
344
  return wrapNullable(union2, isNullable2);
345
345
  }
346
- let schemaStrings = schemas.map((s) => context.generatePropertySchema(s));
346
+ let schemaStrings = schemas.map((s) => context.generatePropertySchema(s, currentSchema));
347
347
  if (options == null ? void 0 : options.passthrough) {
348
348
  schemaStrings = schemaStrings.map((s) => s.includes(".catchall(") ? s : `${s}.catchall(z.unknown())`);
349
349
  }
@@ -1176,7 +1176,8 @@ var _PropertyGenerator = class _PropertyGenerator {
1176
1176
  {
1177
1177
  passthrough: needsPassthrough,
1178
1178
  discriminatorMapping: (_c = schema.discriminator) == null ? void 0 : _c.mapping
1179
- }
1179
+ },
1180
+ currentSchema
1180
1181
  );
1181
1182
  if (schema.unevaluatedProperties !== void 0) {
1182
1183
  composition = this.applyUnevaluatedProperties(composition, schema);
@@ -1196,7 +1197,8 @@ var _PropertyGenerator = class _PropertyGenerator {
1196
1197
  {
1197
1198
  passthrough: needsPassthrough,
1198
1199
  discriminatorMapping: (_e = schema.discriminator) == null ? void 0 : _e.mapping
1199
- }
1200
+ },
1201
+ currentSchema
1200
1202
  );
1201
1203
  if (schema.unevaluatedProperties !== void 0) {
1202
1204
  composition = this.applyUnevaluatedProperties(composition, schema);
@@ -1367,10 +1369,13 @@ var ZodSchemaGenerator = class {
1367
1369
  }
1368
1370
  for (const [name, schema] of Object.entries(this.spec.components.schemas)) {
1369
1371
  if (schema.enum) {
1370
- const typeMode = this.schemaTypeModeMap.get(name) || "inferred";
1371
- if (typeMode === "inferred") {
1372
+ const context = this.schemaUsageMap.get(name);
1373
+ const resolvedOptions = context === "response" ? this.responseOptions : this.requestOptions;
1374
+ if (resolvedOptions.enumType === "typescript") {
1375
+ this.generateNativeEnum(name, schema);
1376
+ } else {
1372
1377
  const { enumCode } = generateEnum(name, schema.enum, {
1373
- enumType: this.options.enumType || "zod",
1378
+ enumType: "zod",
1374
1379
  prefix: this.options.prefix,
1375
1380
  suffix: this.options.suffix
1376
1381
  });
@@ -1378,14 +1383,13 @@ var ZodSchemaGenerator = class {
1378
1383
  this.enums.set(name, enumCode);
1379
1384
  this.needsZodImport = true;
1380
1385
  }
1381
- } else {
1382
- this.generateNativeEnum(name, schema);
1383
1386
  }
1384
1387
  }
1385
1388
  }
1386
1389
  for (const [name, schema] of Object.entries(this.spec.components.schemas)) {
1387
1390
  this.generateComponentSchema(name, schema);
1388
1391
  }
1392
+ this.generateQueryParameterSchemas();
1389
1393
  const orderedSchemaNames = this.topologicalSort();
1390
1394
  const output = ["// Auto-generated by @cerios/openapi-to-zod", "// Do not edit this file manually", ""];
1391
1395
  if (this.options.showStats === true) {
@@ -1396,12 +1400,8 @@ var ZodSchemaGenerator = class {
1396
1400
  output.push('import { z } from "zod";');
1397
1401
  output.push("");
1398
1402
  }
1399
- if (this.enums.size > 0 || this.nativeEnums.size > 0) {
1400
- output.push("// Enums");
1401
- for (const enumCode of this.enums.values()) {
1402
- output.push(enumCode);
1403
- output.push("");
1404
- }
1403
+ if (this.nativeEnums.size > 0) {
1404
+ output.push("// Native Enums");
1405
1405
  for (const enumCode of this.nativeEnums.values()) {
1406
1406
  output.push(enumCode);
1407
1407
  output.push("");
@@ -1409,9 +1409,13 @@ var ZodSchemaGenerator = class {
1409
1409
  }
1410
1410
  output.push("// Schemas and Types");
1411
1411
  for (const name of orderedSchemaNames) {
1412
+ const enumCode = this.enums.get(name);
1412
1413
  const schemaCode = this.schemas.get(name);
1413
1414
  const typeCode = this.types.get(name);
1414
- if (schemaCode) {
1415
+ if (enumCode) {
1416
+ output.push(enumCode);
1417
+ output.push("");
1418
+ } else if (schemaCode) {
1415
1419
  output.push(schemaCode);
1416
1420
  if (!schemaCode.includes(`export type ${name}`)) {
1417
1421
  const schemaName = `${toCamelCase(name, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
@@ -1429,7 +1433,8 @@ var ZodSchemaGenerator = class {
1429
1433
  * Ensure directory exists for a file path
1430
1434
  */
1431
1435
  ensureDirectoryExists(filePath) {
1432
- const dir = (0, import_node_path.dirname)(filePath);
1436
+ const normalizedPath = (0, import_node_path.normalize)(filePath);
1437
+ const dir = (0, import_node_path.dirname)(normalizedPath);
1433
1438
  if (!(0, import_node_fs.existsSync)(dir)) {
1434
1439
  (0, import_node_fs.mkdirSync)(dir, { recursive: true });
1435
1440
  }
@@ -1445,8 +1450,9 @@ var ZodSchemaGenerator = class {
1445
1450
  );
1446
1451
  }
1447
1452
  const output = this.generateString();
1448
- this.ensureDirectoryExists(this.options.output);
1449
- (0, import_node_fs.writeFileSync)(this.options.output, output);
1453
+ const normalizedOutput = (0, import_node_path.normalize)(this.options.output);
1454
+ this.ensureDirectoryExists(normalizedOutput);
1455
+ (0, import_node_fs.writeFileSync)(normalizedOutput, output);
1450
1456
  }
1451
1457
  /**
1452
1458
  * Resolve options for a specific context (request or response)
@@ -1454,17 +1460,18 @@ var ZodSchemaGenerator = class {
1454
1460
  * Response schemas always use 'inferred' mode (Zod schemas)
1455
1461
  */
1456
1462
  resolveOptionsForContext(context) {
1457
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
1463
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
1458
1464
  const contextOptions = context === "request" ? this.options.request : this.options.response;
1465
+ const nativeEnumType = context === "request" ? (_c = (_b = (_a = this.options.request) == null ? void 0 : _a.nativeEnumType) != null ? _b : this.options.nativeEnumType) != null ? _c : "union" : (_d = this.options.nativeEnumType) != null ? _d : "union";
1459
1466
  return {
1460
- mode: (_b = (_a = contextOptions == null ? void 0 : contextOptions.mode) != null ? _a : this.options.mode) != null ? _b : "normal",
1461
- enumType: (_d = (_c = contextOptions == null ? void 0 : contextOptions.enumType) != null ? _c : this.options.enumType) != null ? _d : "zod",
1462
- useDescribe: (_f = (_e = contextOptions == null ? void 0 : contextOptions.useDescribe) != null ? _e : this.options.useDescribe) != null ? _f : false,
1463
- includeDescriptions: (_h = (_g = contextOptions == null ? void 0 : contextOptions.includeDescriptions) != null ? _g : this.options.includeDescriptions) != null ? _h : true,
1467
+ mode: (_f = (_e = contextOptions == null ? void 0 : contextOptions.mode) != null ? _e : this.options.mode) != null ? _f : "normal",
1468
+ enumType: (_h = (_g = contextOptions == null ? void 0 : contextOptions.enumType) != null ? _g : this.options.enumType) != null ? _h : "zod",
1469
+ useDescribe: (_j = (_i = contextOptions == null ? void 0 : contextOptions.useDescribe) != null ? _i : this.options.useDescribe) != null ? _j : false,
1470
+ includeDescriptions: (_l = (_k = contextOptions == null ? void 0 : contextOptions.includeDescriptions) != null ? _k : this.options.includeDescriptions) != null ? _l : true,
1464
1471
  // Response schemas always use 'inferred' mode (Zod schemas are required)
1465
1472
  // Request schemas can optionally use 'native' mode
1466
- typeMode: context === "response" ? "inferred" : (_i = contextOptions == null ? void 0 : contextOptions.typeMode) != null ? _i : "inferred",
1467
- nativeEnumType: (_k = (_j = contextOptions == null ? void 0 : contextOptions.nativeEnumType) != null ? _j : this.options.nativeEnumType) != null ? _k : "union"
1473
+ typeMode: context === "response" ? "inferred" : (_n = (_m = this.options.request) == null ? void 0 : _m.typeMode) != null ? _n : "inferred",
1474
+ nativeEnumType
1468
1475
  };
1469
1476
  }
1470
1477
  /**
@@ -1749,10 +1756,19 @@ var ZodSchemaGenerator = class {
1749
1756
  const context = this.schemaUsageMap.get(name);
1750
1757
  const resolvedOptions = context === "response" ? this.responseOptions : this.requestOptions;
1751
1758
  if (schema.enum) {
1752
- if (typeMode === "inferred") {
1753
- const jsdoc = generateJSDoc(schema, name, { includeDescriptions: resolvedOptions.includeDescriptions });
1759
+ const jsdoc = generateJSDoc(schema, name, { includeDescriptions: resolvedOptions.includeDescriptions });
1760
+ if (resolvedOptions.enumType === "typescript") {
1761
+ const { schemaCode, typeCode } = generateEnum(name, schema.enum, {
1762
+ enumType: "typescript",
1763
+ prefix: this.options.prefix,
1764
+ suffix: this.options.suffix
1765
+ });
1766
+ const enumSchemaCode = `${jsdoc}${schemaCode}
1767
+ ${typeCode}`;
1768
+ this.schemas.set(name, enumSchemaCode);
1769
+ } else {
1754
1770
  const { enumCode, schemaCode, typeCode } = generateEnum(name, schema.enum, {
1755
- enumType: resolvedOptions.enumType,
1771
+ enumType: "zod",
1756
1772
  prefix: this.options.prefix,
1757
1773
  suffix: this.options.suffix
1758
1774
  });
@@ -1811,6 +1827,133 @@ ${typeCode}`;
1811
1827
  this.schemas.set(name, zodSchemaCode);
1812
1828
  }
1813
1829
  }
1830
+ /**
1831
+ * Generate query parameter schemas for each operation
1832
+ */
1833
+ generateQueryParameterSchemas() {
1834
+ var _a;
1835
+ if (!this.spec.paths) {
1836
+ return;
1837
+ }
1838
+ for (const [_path, pathItem] of Object.entries(this.spec.paths)) {
1839
+ if (!pathItem || typeof pathItem !== "object") continue;
1840
+ const methods = ["get", "post", "put", "patch", "delete", "head", "options"];
1841
+ for (const method of methods) {
1842
+ const operation = pathItem[method];
1843
+ if (!operation) continue;
1844
+ if (!operation.operationId || !operation.parameters || !Array.isArray(operation.parameters)) {
1845
+ continue;
1846
+ }
1847
+ const queryParams = operation.parameters.filter(
1848
+ (param) => param && typeof param === "object" && param.in === "query"
1849
+ );
1850
+ if (queryParams.length === 0) {
1851
+ continue;
1852
+ }
1853
+ const pascalOperationId = operation.operationId.includes("-") ? toPascalCase(operation.operationId) : operation.operationId.charAt(0).toUpperCase() + operation.operationId.slice(1);
1854
+ const schemaName = `${pascalOperationId}QueryParams`;
1855
+ if (!this.schemaDependencies.has(schemaName)) {
1856
+ this.schemaDependencies.set(schemaName, /* @__PURE__ */ new Set());
1857
+ }
1858
+ const properties = {};
1859
+ const required = [];
1860
+ for (const param of queryParams) {
1861
+ const paramName = param.name;
1862
+ const isRequired = param.required === true;
1863
+ const paramSchema = param.schema;
1864
+ if (!paramSchema) continue;
1865
+ let zodType = this.generateQueryParamType(paramSchema, param);
1866
+ if (paramSchema.type === "array" && paramSchema.items) {
1867
+ const itemType = this.generateQueryParamType(paramSchema.items, param);
1868
+ zodType = `z.array(${itemType})`;
1869
+ }
1870
+ if (param.description && this.requestOptions.includeDescriptions) {
1871
+ if (this.requestOptions.useDescribe) {
1872
+ zodType = `${zodType}.describe(${JSON.stringify(param.description)})`;
1873
+ }
1874
+ }
1875
+ if (!isRequired) {
1876
+ zodType = `${zodType}.optional()`;
1877
+ }
1878
+ properties[paramName] = zodType;
1879
+ if (isRequired) {
1880
+ required.push(paramName);
1881
+ }
1882
+ if (paramSchema.$ref) {
1883
+ const refName = resolveRef(paramSchema.$ref);
1884
+ (_a = this.schemaDependencies.get(schemaName)) == null ? void 0 : _a.add(refName);
1885
+ }
1886
+ }
1887
+ const objectMode = this.requestOptions.mode;
1888
+ const zodMethod = objectMode === "strict" ? "strictObject" : objectMode === "loose" ? "looseObject" : "object";
1889
+ const propsCode = Object.entries(properties).map(([key, value]) => {
1890
+ const needsQuotes = !/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key);
1891
+ const quotedKey = needsQuotes ? `"${key}"` : key;
1892
+ return ` ${quotedKey}: ${value}`;
1893
+ }).join(",\n");
1894
+ const schemaCode = `z.${zodMethod}({
1895
+ ${propsCode}
1896
+ })`;
1897
+ const operationName = pascalOperationId;
1898
+ const prefixedName = this.options.prefix ? `${toPascalCase(this.options.prefix)}${operationName}` : operationName;
1899
+ const suffixedName = this.options.suffix ? `${prefixedName}${toPascalCase(this.options.suffix)}` : prefixedName;
1900
+ const camelCaseSchemaName = `${suffixedName.charAt(0).toLowerCase() + suffixedName.slice(1)}QueryParamsSchema`;
1901
+ const jsdoc = `/**
1902
+ * Query parameters for ${operation.operationId}
1903
+ */
1904
+ `;
1905
+ const fullSchemaCode = `${jsdoc}export const ${camelCaseSchemaName} = ${schemaCode};`;
1906
+ this.schemas.set(schemaName, fullSchemaCode);
1907
+ this.needsZodImport = true;
1908
+ }
1909
+ }
1910
+ }
1911
+ /**
1912
+ * Generate Zod type for a query parameter schema
1913
+ */
1914
+ generateQueryParamType(schema, param) {
1915
+ if (schema.$ref) {
1916
+ const refName = resolveRef(schema.$ref);
1917
+ const schemaName = toCamelCase(refName, { prefix: this.options.prefix, suffix: this.options.suffix });
1918
+ return `${schemaName}Schema`;
1919
+ }
1920
+ if (schema.enum) {
1921
+ const enumValues = schema.enum.map((v) => typeof v === "string" ? `"${v}"` : v).join(", ");
1922
+ return `z.enum([${enumValues}])`;
1923
+ }
1924
+ const type = schema.type;
1925
+ if (type === "string") {
1926
+ let zodType = "z.string()";
1927
+ if (schema.minLength !== void 0) zodType = `${zodType}.min(${schema.minLength})`;
1928
+ if (schema.maxLength !== void 0) zodType = `${zodType}.max(${schema.maxLength})`;
1929
+ if (schema.pattern) zodType = `${zodType}.regex(/${schema.pattern}/)`;
1930
+ if (schema.format === "email") zodType = `${zodType}.email()`;
1931
+ if (schema.format === "uri" || schema.format === "url") zodType = `${zodType}.url()`;
1932
+ if (schema.format === "uuid") zodType = `${zodType}.uuid()`;
1933
+ return zodType;
1934
+ }
1935
+ if (type === "number" || type === "integer") {
1936
+ let zodType = type === "integer" ? "z.number().int()" : "z.number()";
1937
+ if (schema.minimum !== void 0) {
1938
+ zodType = schema.exclusiveMinimum ? `${zodType}.gt(${schema.minimum})` : `${zodType}.gte(${schema.minimum})`;
1939
+ }
1940
+ if (schema.maximum !== void 0) {
1941
+ zodType = schema.exclusiveMaximum ? `${zodType}.lt(${schema.maximum})` : `${zodType}.lte(${schema.maximum})`;
1942
+ }
1943
+ return zodType;
1944
+ }
1945
+ if (type === "boolean") {
1946
+ return "z.boolean()";
1947
+ }
1948
+ if (type === "array" && schema.items) {
1949
+ const itemType = this.generateQueryParamType(schema.items, param);
1950
+ let arrayType = `z.array(${itemType})`;
1951
+ if (schema.minItems !== void 0) arrayType = `${arrayType}.min(${schema.minItems})`;
1952
+ if (schema.maxItems !== void 0) arrayType = `${arrayType}.max(${schema.maxItems})`;
1953
+ return arrayType;
1954
+ }
1955
+ return "z.unknown()";
1956
+ }
1814
1957
  /**
1815
1958
  * Generate native TypeScript enum
1816
1959
  */
@@ -1821,8 +1964,8 @@ ${typeCode}`;
1821
1964
  const jsdoc = generateJSDoc(schema, name, { includeDescriptions: resolvedOptions.includeDescriptions });
1822
1965
  if (resolvedOptions.nativeEnumType === "enum") {
1823
1966
  const enumName = `${name}Enum`;
1824
- const members = schema.enum.map((value, index) => {
1825
- const key = typeof value === "string" ? this.toEnumKey(value) : `Value${index}`;
1967
+ const members = schema.enum.map((value) => {
1968
+ const key = typeof value === "string" ? this.toEnumKey(value) : `N${value}`;
1826
1969
  const val = typeof value === "string" ? `"${value}"` : value;
1827
1970
  return ` ${key} = ${val}`;
1828
1971
  }).join(",\n");
@@ -1965,7 +2108,11 @@ ${props.join("\n")}
1965
2108
  const visited = /* @__PURE__ */ new Set();
1966
2109
  const visiting = /* @__PURE__ */ new Set();
1967
2110
  const aliases = [];
2111
+ const circularDeps = /* @__PURE__ */ new Set();
1968
2112
  const codeCache = /* @__PURE__ */ new Map();
2113
+ for (const [name, code] of this.enums) {
2114
+ codeCache.set(name, code);
2115
+ }
1969
2116
  for (const [name, code] of this.schemas) {
1970
2117
  codeCache.set(name, code);
1971
2118
  }
@@ -1975,6 +2122,7 @@ ${props.join("\n")}
1975
2122
  const visit = (name) => {
1976
2123
  if (visited.has(name)) return;
1977
2124
  if (visiting.has(name)) {
2125
+ circularDeps.add(name);
1978
2126
  return;
1979
2127
  }
1980
2128
  visiting.add(name);
@@ -1989,19 +2137,27 @@ ${props.join("\n")}
1989
2137
  const deps = this.schemaDependencies.get(name);
1990
2138
  if (deps && deps.size > 0) {
1991
2139
  for (const dep of deps) {
1992
- if (this.schemas.has(dep) || this.types.has(dep)) {
2140
+ if (this.enums.has(dep) || this.schemas.has(dep) || this.types.has(dep)) {
1993
2141
  visit(dep);
1994
2142
  }
1995
2143
  }
1996
2144
  }
1997
2145
  visiting.delete(name);
1998
2146
  visited.add(name);
1999
- sorted.push(name);
2147
+ if (!circularDeps.has(name)) {
2148
+ sorted.push(name);
2149
+ }
2000
2150
  };
2001
- const allNames = /* @__PURE__ */ new Set([...this.schemas.keys(), ...this.types.keys()]);
2151
+ const allNames = /* @__PURE__ */ new Set([...this.enums.keys(), ...this.schemas.keys(), ...this.types.keys()]);
2002
2152
  for (const name of allNames) {
2003
2153
  visit(name);
2004
2154
  }
2155
+ for (const name of circularDeps) {
2156
+ if (!visited.has(name)) {
2157
+ sorted.push(name);
2158
+ visited.add(name);
2159
+ }
2160
+ }
2005
2161
  return [...sorted, ...aliases];
2006
2162
  }
2007
2163
  /**