@cerios/openapi-to-zod 1.0.0 → 1.1.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 CHANGED
@@ -187,6 +187,7 @@ Examples:
187
187
  | `schemaType` | `"all"` \| `"request"` \| `"response"` | Schema filtering |
188
188
  | `prefix` | `string` | Prefix for schema names |
189
189
  | `suffix` | `string` | Suffix for schema names |
190
+ | `stripSchemaPrefix` | `string` | Strip prefix from schema names before generating using glob patterns (e.g., `"Company.Models."` or `"*.Models."`) |
190
191
  | `showStats` | `boolean` | Include generation statistics |
191
192
  | `request` | `object` | Request-specific options (mode, includeDescriptions, useDescribe) |
192
193
  | `response` | `object` | Response-specific options (mode, includeDescriptions, useDescribe) |
@@ -570,10 +571,46 @@ OpenAPI's `nullable: true` is converted to `.nullable()`
570
571
 
571
572
  ### Enums
572
573
 
573
- Enums are generated as Zod enums with:
574
- - Proper string value handling
575
- - Zod schema using `z.enum()`
576
- - TypeScript type inference from the Zod schema
574
+ Enums are generated based on their value types:
575
+
576
+ - **String enums**: `z.enum()` for type-safe string unions
577
+ - **Numeric enums**: `z.union([z.literal(n), ...])` for proper number types
578
+ - **Boolean enums**: `z.boolean()` for true/false values
579
+ - **Mixed enums**: `z.union([z.literal(...), ...])` for heterogeneous values
580
+
581
+ **Examples:**
582
+
583
+ ```yaml
584
+ # String enum
585
+ Status:
586
+ type: string
587
+ enum: [active, inactive, pending]
588
+
589
+ # Integer enum
590
+ Priority:
591
+ type: integer
592
+ enum: [0, 1, 2, 3]
593
+
594
+ # Mixed enum
595
+ Value:
596
+ enum: [0, "none", 1, "some"]
597
+ ```
598
+
599
+ **Generated schemas:**
600
+
601
+ ```typescript
602
+ // String enum → z.enum()
603
+ export const statusSchema = z.enum(["active", "inactive", "pending"]);
604
+ export type Status = z.infer<typeof statusSchema>; // "active" | "inactive" | "pending"
605
+
606
+ // Integer enum → z.union with z.literal
607
+ export const prioritySchema = z.union([z.literal(0), z.literal(1), z.literal(2), z.literal(3)]);
608
+ export type Priority = z.infer<typeof prioritySchema>; // 0 | 1 | 2 | 3
609
+
610
+ // Mixed enum → z.union with z.literal
611
+ export const valueSchema = z.union([z.literal(0), z.literal("none"), z.literal(1), z.literal("some")]);
612
+ export type Value = z.infer<typeof valueSchema>; // 0 | "none" | 1 | "some"
613
+ ```
577
614
 
578
615
  ## Schema Naming
579
616
 
@@ -598,6 +635,203 @@ This is useful when:
598
635
  - Following specific naming conventions (DTO, Model, Entity)
599
636
  - Avoiding naming conflicts with existing code
600
637
 
638
+ ### Schema Prefix Stripping
639
+
640
+ The `stripSchemaPrefix` option removes common prefixes from schema names in your OpenAPI spec before generating Zod schemas. This is particularly useful when your OpenAPI spec uses namespaced schema names (like .NET-generated specs with "Company.Models.User").
641
+
642
+ **OpenAPI Spec with Namespaced Schemas:**
643
+ ```yaml
644
+ components:
645
+ schemas:
646
+ Company.Models.User:
647
+ type: object
648
+ properties:
649
+ id:
650
+ type: string
651
+ name:
652
+ type: string
653
+ role:
654
+ $ref: '#/components/schemas/Company.Models.UserRole'
655
+ Company.Models.UserRole:
656
+ type: string
657
+ enum: [admin, user, guest]
658
+ Company.Models.Post:
659
+ type: object
660
+ properties:
661
+ id:
662
+ type: string
663
+ title:
664
+ type: string
665
+ author:
666
+ $ref: '#/components/schemas/Company.Models.User'
667
+ ```
668
+
669
+ **Without `stripSchemaPrefix`:**
670
+ ```typescript
671
+ export const companyModelsUserRoleSchema = z.enum(["admin", "user", "guest"]);
672
+
673
+ export const companyModelsUserSchema = z.object({
674
+ id: z.string(),
675
+ name: z.string(),
676
+ role: companyModelsUserRoleSchema // Long reference name
677
+ });
678
+
679
+ export const companyModelsPostSchema = z.object({
680
+ id: z.string(),
681
+ title: z.string(),
682
+ author: companyModelsUserSchema // Long reference name
683
+ });
684
+
685
+ export type CompanyModelsUserRole = z.infer<typeof companyModelsUserRoleSchema>;
686
+ export type CompanyModelsUser = z.infer<typeof companyModelsUserSchema>;
687
+ export type CompanyModelsPost = z.infer<typeof companyModelsPostSchema>;
688
+ ```
689
+
690
+ **With `stripSchemaPrefix: "Company.Models."`:**
691
+ ```typescript
692
+ export const userRoleSchema = z.enum(["admin", "user", "guest"]);
693
+
694
+ export const userSchema = z.object({
695
+ id: z.string(),
696
+ name: z.string(),
697
+ role: userRoleSchema // Clean reference
698
+ });
699
+
700
+ export const postSchema = z.object({
701
+ id: z.string(),
702
+ title: z.string(),
703
+ author: userSchema // Clean reference
704
+ });
705
+
706
+ export type UserRole = z.infer<typeof userRoleSchema>;
707
+ export type User = z.infer<typeof userSchema>;
708
+ export type Post = z.infer<typeof postSchema>;
709
+ ```
710
+
711
+ #### Usage
712
+
713
+ ```typescript
714
+ export default defineConfig({
715
+ specs: [{
716
+ input: 'openapi.yaml',
717
+ output: 'schemas.ts',
718
+ stripSchemaPrefix: 'Company.Models.' // Strip this exact prefix
719
+ }]
720
+ });
721
+ ```
722
+
723
+ #### Glob Patterns
724
+
725
+ Use glob patterns to strip dynamic prefixes:
726
+
727
+ ```typescript
728
+ export default defineConfig({
729
+ specs: [{
730
+ input: 'openapi.yaml',
731
+ output: 'schemas.ts',
732
+ // Strip any namespace prefix with wildcard
733
+ stripSchemaPrefix: '*.Models.'
734
+ }]
735
+ });
736
+ ```
737
+
738
+ **Glob Pattern Syntax:**
739
+
740
+ Glob patterns support powerful matching using [minimatch](https://github.com/isaacs/minimatch):
741
+ - `*` matches any characters within a single segment (stops at `.`)
742
+ - `**` matches any characters across multiple segments (crosses `.` boundaries)
743
+ - `?` matches a single character
744
+ - `[abc]` matches any character in the set
745
+ - `{a,b}` matches any of the alternatives
746
+ - `!(pattern)` matches anything except the pattern
747
+
748
+ ```typescript
749
+ // Examples of glob patterns:
750
+ stripSchemaPrefix: '*.Models.' // Matches Company.Models., App.Models.
751
+ stripSchemaPrefix: '**.Models.' // Matches any depth: Company.Api.Models., App.V2.Models.
752
+ stripSchemaPrefix: 'Company.{Models,Services}.' // Matches Company.Models. or Company.Services.
753
+ stripSchemaPrefix: 'api_v[0-9]_' // Matches api_v1_, api_v2_, etc.
754
+ stripSchemaPrefix: 'v*.*.' // Matches v1.0., v2.1., etc.
755
+ stripSchemaPrefix: '!(Internal)*.' // Matches any prefix except those starting with Internal
756
+ ```
757
+
758
+ #### Common Patterns
759
+
760
+ **Pattern 1: .NET Namespaces**
761
+ ```typescript
762
+ {
763
+ stripSchemaPrefix: 'Company.Models.'
764
+ }
765
+ // Company.Models.User → User
766
+ // Company.Models.Post → Post
767
+ ```
768
+
769
+ **Pattern 2: Multiple Namespaces with Wildcard**
770
+ ```typescript
771
+ {
772
+ stripSchemaPrefix: '*.Models.'
773
+ }
774
+ // MyApp.Models.User → User
775
+ // OtherApp.Models.User → User
776
+ // Company.Models.Post → Post
777
+ ```
778
+
779
+ **Pattern 3: Multiple Namespace Types**
780
+ ```typescript
781
+ {
782
+ stripSchemaPrefix: '*.{Models,Services}.'
783
+ }
784
+ // App.Models.User → User
785
+ // App.Services.UserService → UserService
786
+ ```
787
+
788
+ **Pattern 4: Version Prefixes with Character Class**
789
+ ```typescript
790
+ {
791
+ stripSchemaPrefix: 'v[0-9].'
792
+ }
793
+ // v1.User → User
794
+ // v2.Product → Product
795
+ ```
796
+
797
+ **Pattern 5: Versioned Prefixes with Wildcards**
798
+ ```typescript
799
+ {
800
+ stripSchemaPrefix: 'api_v*_'
801
+ }
802
+ // api_v1_User → User
803
+ // api_v2_Product → Product
804
+ // api_v10_Comment → Comment
805
+ ```
806
+
807
+ #### Interaction with prefix/suffix Options
808
+
809
+ `stripSchemaPrefix` is applied **before** `prefix` and `suffix` options:
810
+
811
+ ```typescript
812
+ export default defineConfig({
813
+ specs: [{
814
+ input: 'openapi.yaml',
815
+ output: 'schemas.ts',
816
+ stripSchemaPrefix: 'Company.Models.', // Applied first
817
+ prefix: 'api', // Applied second
818
+ suffix: 'dto' // Applied third
819
+ }]
820
+ });
821
+ ```
822
+
823
+ **Result:**
824
+ - `Company.Models.User` → `User` → `apiUserDtoSchema`
825
+ - `Company.Models.Post` → `Post` → `apiPostDtoSchema`
826
+
827
+ #### Benefits
828
+
829
+ 1. **Cleaner Schema Names**: Generates `userSchema` instead of `companyModelsUserSchema`
830
+ 2. **Better Type Names**: Creates `User` type instead of `CompanyModelsUser`
831
+ 3. **Shorter References**: Simpler schema references in composed types
832
+ 4. **Better Code Completion**: Easier to find schemas in IDE autocomplete
833
+ 5. **Flexible Pattern Matching**: Use regex for dynamic prefixes
834
+
601
835
  ## Generation Statistics
602
836
 
603
837
  Statistics are **included by default** in generated files. Use `showStats: false` to disable:
package/dist/cli.js CHANGED
@@ -5129,7 +5129,7 @@ function getBatchExitCode(summary) {
5129
5129
  init_cjs_shims();
5130
5130
  var import_node_fs = require("fs");
5131
5131
  var import_node_path = require("path");
5132
- var import_minimatch2 = require("minimatch");
5132
+ var import_minimatch3 = require("minimatch");
5133
5133
  var import_yaml = require("yaml");
5134
5134
 
5135
5135
  // src/generators/enum-generator.ts
@@ -5137,8 +5137,20 @@ init_cjs_shims();
5137
5137
 
5138
5138
  // src/utils/name-utils.ts
5139
5139
  init_cjs_shims();
5140
+ function sanitizeIdentifier(str) {
5141
+ return str.replace(/[^a-zA-Z0-9._\-\s]+/g, "_");
5142
+ }
5140
5143
  function toCamelCase(str, options) {
5141
- let name = str.charAt(0).toLowerCase() + str.slice(1);
5144
+ const sanitized = sanitizeIdentifier(str);
5145
+ const words = sanitized.split(/[.\-_\s]+/).filter((word) => word.length > 0);
5146
+ let name;
5147
+ if (words.length === 0) {
5148
+ name = str.charAt(0).toLowerCase() + str.slice(1);
5149
+ } else if (words.length === 1) {
5150
+ name = words[0].charAt(0).toLowerCase() + words[0].slice(1);
5151
+ } else {
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
+ }
5142
5154
  if (options == null ? void 0 : options.prefix) {
5143
5155
  const prefix = options.prefix.toLowerCase();
5144
5156
  name = prefix + name.charAt(0).toUpperCase() + name.slice(1);
@@ -5151,12 +5163,23 @@ function toCamelCase(str, options) {
5151
5163
  }
5152
5164
  function toPascalCase(str) {
5153
5165
  const stringValue = String(str);
5154
- let result = stringValue.replace(/[^a-zA-Z0-9_]+/g, "_").split(/[-_]+/).filter((word) => word.length > 0).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
5166
+ const isAlreadyValidCase = /^[a-zA-Z][a-zA-Z0-9]*$/.test(stringValue);
5167
+ if (isAlreadyValidCase) {
5168
+ return stringValue.charAt(0).toUpperCase() + stringValue.slice(1);
5169
+ }
5170
+ const sanitized = sanitizeIdentifier(stringValue);
5171
+ const words = sanitized.split(/[.\-_\s]+/).filter((word) => word.length > 0);
5172
+ let result;
5173
+ if (words.length === 0) {
5174
+ result = "Value";
5175
+ } else {
5176
+ result = words.map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
5177
+ }
5155
5178
  if (/^\d/.test(result)) {
5156
5179
  result = `N${result}`;
5157
5180
  }
5158
5181
  if (!result || /^_+$/.test(result)) {
5159
- result = "Value";
5182
+ return "Value";
5160
5183
  }
5161
5184
  return result;
5162
5185
  }
@@ -5168,9 +5191,28 @@ function resolveRef(ref) {
5168
5191
  // src/generators/enum-generator.ts
5169
5192
  function generateEnum(name, values, options) {
5170
5193
  const schemaName = `${toCamelCase(name, options)}Schema`;
5171
- const enumValues = values.map((v) => `"${v}"`).join(", ");
5172
- const schemaCode = `export const ${schemaName} = z.enum([${enumValues}]);`;
5173
- const typeCode = `export type ${name} = z.infer<typeof ${schemaName}>;`;
5194
+ const typeName = toPascalCase(name);
5195
+ const allBooleans = values.every((v) => typeof v === "boolean");
5196
+ if (allBooleans) {
5197
+ const schemaCode2 = `export const ${schemaName} = z.boolean();`;
5198
+ const typeCode2 = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
5199
+ return { schemaCode: schemaCode2, typeCode: typeCode2 };
5200
+ }
5201
+ const allStrings = values.every((v) => typeof v === "string");
5202
+ if (allStrings) {
5203
+ const enumValues = values.map((v) => `"${v}"`).join(", ");
5204
+ const schemaCode2 = `export const ${schemaName} = z.enum([${enumValues}]);`;
5205
+ const typeCode2 = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
5206
+ return { schemaCode: schemaCode2, typeCode: typeCode2 };
5207
+ }
5208
+ const literalValues = values.map((v) => {
5209
+ if (typeof v === "string") {
5210
+ return `z.literal("${v}")`;
5211
+ }
5212
+ return `z.literal(${v})`;
5213
+ }).join(", ");
5214
+ const schemaCode = `export const ${schemaName} = z.union([${literalValues}]);`;
5215
+ const typeCode = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
5174
5216
  return { schemaCode, typeCode };
5175
5217
  }
5176
5218
 
@@ -5183,7 +5225,7 @@ function escapeDescription(str) {
5183
5225
  return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
5184
5226
  }
5185
5227
  function escapePattern(str) {
5186
- return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
5228
+ return str.replace(/\//g, "\\/");
5187
5229
  }
5188
5230
  function escapeJSDoc(str) {
5189
5231
  return str.replace(/\*\//g, "*\\/");
@@ -5311,6 +5353,65 @@ var LRUCache = class {
5311
5353
  }
5312
5354
  };
5313
5355
 
5356
+ // src/utils/pattern-utils.ts
5357
+ init_cjs_shims();
5358
+ var import_minimatch = require("minimatch");
5359
+ function isValidGlobPattern(pattern) {
5360
+ try {
5361
+ new import_minimatch.minimatch.Minimatch(pattern);
5362
+ return true;
5363
+ } catch {
5364
+ return false;
5365
+ }
5366
+ }
5367
+ function isGlobPattern(pattern) {
5368
+ return /[*?[\]{}!]/.test(pattern);
5369
+ }
5370
+ function stripPrefix(input, pattern, ensureLeadingChar) {
5371
+ if (!pattern) {
5372
+ return input;
5373
+ }
5374
+ if (isGlobPattern(pattern) && !isValidGlobPattern(pattern)) {
5375
+ console.warn(`\u26A0\uFE0F Invalid glob pattern "${pattern}": Pattern is malformed`);
5376
+ return input;
5377
+ }
5378
+ if (isGlobPattern(pattern)) {
5379
+ let longestMatch = -1;
5380
+ for (let i = 1; i <= input.length; i++) {
5381
+ const testPrefix = input.substring(0, i);
5382
+ if ((0, import_minimatch.minimatch)(testPrefix, pattern)) {
5383
+ longestMatch = i;
5384
+ }
5385
+ }
5386
+ if (longestMatch > 0) {
5387
+ const stripped = input.substring(longestMatch);
5388
+ if (ensureLeadingChar) {
5389
+ if (stripped === "") {
5390
+ return ensureLeadingChar;
5391
+ }
5392
+ if (!stripped.startsWith(ensureLeadingChar)) {
5393
+ return `${ensureLeadingChar}${stripped}`;
5394
+ }
5395
+ }
5396
+ return stripped === "" && !ensureLeadingChar ? input : stripped;
5397
+ }
5398
+ return input;
5399
+ }
5400
+ if (input.startsWith(pattern)) {
5401
+ const stripped = input.substring(pattern.length);
5402
+ if (ensureLeadingChar) {
5403
+ if (stripped === "") {
5404
+ return ensureLeadingChar;
5405
+ }
5406
+ if (!stripped.startsWith(ensureLeadingChar)) {
5407
+ return `${ensureLeadingChar}${stripped}`;
5408
+ }
5409
+ }
5410
+ return stripped;
5411
+ }
5412
+ return input;
5413
+ }
5414
+
5314
5415
  // src/validators/array-validator.ts
5315
5416
  init_cjs_shims();
5316
5417
  function generateArrayValidation(schema, context) {
@@ -6175,8 +6276,9 @@ var _PropertyGenerator = class _PropertyGenerator {
6175
6276
  }
6176
6277
  (_a = this.context.schemaDependencies.get(currentSchema)) == null ? void 0 : _a.add(refName);
6177
6278
  }
6178
- const schemaName = `${toCamelCase(resolvedRefName, this.context.namingOptions)}Schema`;
6179
- if (currentSchema && this.isCircularThroughAlias(currentSchema, refName)) {
6279
+ const strippedRefName = stripPrefix(resolvedRefName, this.context.stripSchemaPrefix);
6280
+ const schemaName = `${toCamelCase(strippedRefName, this.context.namingOptions)}Schema`;
6281
+ if (currentSchema && (refName === currentSchema || this.isCircularThroughAlias(currentSchema, refName))) {
6180
6282
  const lazySchema = `z.lazy((): z.ZodTypeAny => ${schemaName})`;
6181
6283
  return wrapNullable(lazySchema, nullable);
6182
6284
  }
@@ -6188,9 +6290,25 @@ var _PropertyGenerator = class _PropertyGenerator {
6188
6290
  return wrapNullable(zodLiteral, nullable);
6189
6291
  }
6190
6292
  if (schema.enum) {
6191
- const enumValues = schema.enum.map((v) => `"${v}"`).join(", ");
6192
- const zodEnum = `z.enum([${enumValues}])`;
6193
- return wrapNullable(zodEnum, nullable);
6293
+ const allBooleans = schema.enum.every((v) => typeof v === "boolean");
6294
+ if (allBooleans) {
6295
+ const zodBoolean = "z.boolean()";
6296
+ return wrapNullable(zodBoolean, nullable);
6297
+ }
6298
+ const allStrings = schema.enum.every((v) => typeof v === "string");
6299
+ if (allStrings) {
6300
+ const enumValues = schema.enum.map((v) => `"${v}"`).join(", ");
6301
+ const zodEnum = `z.enum([${enumValues}])`;
6302
+ return wrapNullable(zodEnum, nullable);
6303
+ }
6304
+ const literalValues = schema.enum.map((v) => {
6305
+ if (typeof v === "string") {
6306
+ return `z.literal("${v}")`;
6307
+ }
6308
+ return `z.literal(${v})`;
6309
+ }).join(", ");
6310
+ const zodUnion = `z.union([${literalValues}])`;
6311
+ return wrapNullable(zodUnion, nullable);
6194
6312
  }
6195
6313
  if (schema.allOf) {
6196
6314
  let composition = generateAllOf(
@@ -6322,7 +6440,7 @@ var PropertyGenerator = _PropertyGenerator;
6322
6440
 
6323
6441
  // src/utils/operation-filters.ts
6324
6442
  init_cjs_shims();
6325
- var import_minimatch = require("minimatch");
6443
+ var import_minimatch2 = require("minimatch");
6326
6444
  function createFilterStatistics() {
6327
6445
  return {
6328
6446
  totalOperations: 0,
@@ -6341,7 +6459,7 @@ function matchesAnyPattern(value, patterns) {
6341
6459
  if (!value) {
6342
6460
  return false;
6343
6461
  }
6344
- return patterns.some((pattern) => (0, import_minimatch.minimatch)(value, pattern));
6462
+ return patterns.some((pattern) => (0, import_minimatch2.minimatch)(value, pattern));
6345
6463
  }
6346
6464
  function containsAny(arr, values) {
6347
6465
  if (!values || values.length === 0) {
@@ -6477,6 +6595,7 @@ var OpenApiGenerator = class {
6477
6595
  schemaType: options.schemaType || "all",
6478
6596
  prefix: options.prefix,
6479
6597
  suffix: options.suffix,
6598
+ stripSchemaPrefix: options.stripSchemaPrefix,
6480
6599
  showStats: (_c = options.showStats) != null ? _c : true,
6481
6600
  request: options.request,
6482
6601
  response: options.response,
@@ -6553,7 +6672,8 @@ var OpenApiGenerator = class {
6553
6672
  namingOptions: {
6554
6673
  prefix: this.options.prefix,
6555
6674
  suffix: this.options.suffix
6556
- }
6675
+ },
6676
+ stripSchemaPrefix: this.options.stripSchemaPrefix
6557
6677
  });
6558
6678
  }
6559
6679
  /**
@@ -6566,6 +6686,9 @@ var OpenApiGenerator = class {
6566
6686
  throw new SpecValidationError("No schemas found in OpenAPI spec", { filePath: this.options.input });
6567
6687
  }
6568
6688
  for (const [name, schema] of Object.entries(this.spec.components.schemas)) {
6689
+ if (this.options.operationFilters && this.schemaUsageMap.size > 0 && !this.schemaUsageMap.has(name)) {
6690
+ continue;
6691
+ }
6569
6692
  this.generateComponentSchema(name, schema);
6570
6693
  }
6571
6694
  this.generateQueryParameterSchemas();
@@ -6587,9 +6710,11 @@ var OpenApiGenerator = class {
6587
6710
  const typeCode = this.types.get(name);
6588
6711
  if (schemaCode) {
6589
6712
  output.push(schemaCode);
6590
- if (!schemaCode.includes(`export type ${name}`)) {
6591
- const schemaName = `${toCamelCase(name, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
6592
- output.push(`export type ${name} = z.infer<typeof ${schemaName}>;`);
6713
+ const strippedName = stripPrefix(name, this.options.stripSchemaPrefix);
6714
+ const typeName = toPascalCase(strippedName);
6715
+ if (!schemaCode.includes(`export type ${typeName}`)) {
6716
+ const schemaName = `${toCamelCase(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
6717
+ output.push(`export type ${typeName} = z.infer<typeof ${schemaName}>;`);
6593
6718
  }
6594
6719
  output.push("");
6595
6720
  } else if (typeCode) {
@@ -6905,7 +7030,8 @@ var OpenApiGenerator = class {
6905
7030
  const resolvedOptions = context === "response" ? this.responseOptions : this.requestOptions;
6906
7031
  if (schema.enum) {
6907
7032
  const jsdoc2 = generateJSDoc(schema, name, { includeDescriptions: resolvedOptions.includeDescriptions });
6908
- const { schemaCode, typeCode } = generateEnum(name, schema.enum, {
7033
+ const strippedName2 = stripPrefix(name, this.options.stripSchemaPrefix);
7034
+ const { schemaCode, typeCode } = generateEnum(strippedName2, schema.enum, {
6909
7035
  prefix: this.options.prefix,
6910
7036
  suffix: this.options.suffix
6911
7037
  });
@@ -6914,7 +7040,8 @@ ${typeCode}`;
6914
7040
  this.schemas.set(name, enumSchemaCode);
6915
7041
  return;
6916
7042
  }
6917
- const schemaName = `${toCamelCase(name, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
7043
+ const strippedName = stripPrefix(name, this.options.stripSchemaPrefix);
7044
+ const schemaName = `${toCamelCase(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
6918
7045
  const jsdoc = generateJSDoc(schema, name, { includeDescriptions: resolvedOptions.includeDescriptions });
6919
7046
  if (schema.allOf && schema.allOf.length === 1 && schema.allOf[0].$ref) {
6920
7047
  const refName = resolveRef(schema.allOf[0].$ref);
@@ -6930,7 +7057,8 @@ ${typeCode}`;
6930
7057
  namingOptions: {
6931
7058
  prefix: this.options.prefix,
6932
7059
  suffix: this.options.suffix
6933
- }
7060
+ },
7061
+ stripSchemaPrefix: this.options.stripSchemaPrefix
6934
7062
  });
6935
7063
  const isAlias = !!(schema.$ref && !schema.properties && !schema.allOf && !schema.oneOf && !schema.anyOf);
6936
7064
  const zodSchema = this.propertyGenerator.generatePropertySchema(schema, name, isAlias);
@@ -7049,7 +7177,7 @@ ${propsCode}
7049
7177
  const headerLower = headerName.toLowerCase();
7050
7178
  return ignorePatterns.some((pattern) => {
7051
7179
  const patternLower = pattern.toLowerCase();
7052
- return (0, import_minimatch2.minimatch)(headerLower, patternLower);
7180
+ return (0, import_minimatch3.minimatch)(headerLower, patternLower);
7053
7181
  });
7054
7182
  }
7055
7183
  /**
@@ -7132,12 +7260,27 @@ ${propsCode}
7132
7260
  generateQueryParamType(schema, param) {
7133
7261
  if (schema.$ref) {
7134
7262
  const refName = resolveRef(schema.$ref);
7135
- const schemaName = toCamelCase(refName, { prefix: this.options.prefix, suffix: this.options.suffix });
7263
+ const strippedRefName = stripPrefix(refName, this.options.stripSchemaPrefix);
7264
+ const schemaName = toCamelCase(strippedRefName, { prefix: this.options.prefix, suffix: this.options.suffix });
7136
7265
  return `${schemaName}Schema`;
7137
7266
  }
7138
7267
  if (schema.enum) {
7139
- const enumValues = schema.enum.map((v) => typeof v === "string" ? `"${v}"` : v).join(", ");
7140
- return `z.enum([${enumValues}])`;
7268
+ const allBooleans = schema.enum.every((v) => typeof v === "boolean");
7269
+ if (allBooleans) {
7270
+ return "z.boolean()";
7271
+ }
7272
+ const allStrings = schema.enum.every((v) => typeof v === "string");
7273
+ if (allStrings) {
7274
+ const enumValues = schema.enum.map((v) => `"${v}"`).join(", ");
7275
+ return `z.enum([${enumValues}])`;
7276
+ }
7277
+ const literalValues = schema.enum.map((v) => {
7278
+ if (typeof v === "string") {
7279
+ return `z.literal("${v}")`;
7280
+ }
7281
+ return `z.literal(${v})`;
7282
+ }).join(", ");
7283
+ return `z.union([${literalValues}])`;
7141
7284
  }
7142
7285
  const type = schema.type;
7143
7286
  if (type === "string") {
@@ -7368,6 +7511,7 @@ var OpenApiGeneratorOptionsSchema = import_zod2.z.strictObject({
7368
7511
  schemaType: import_zod2.z.enum(["all", "request", "response"]).optional(),
7369
7512
  prefix: import_zod2.z.string().optional(),
7370
7513
  suffix: import_zod2.z.string().optional(),
7514
+ stripSchemaPrefix: import_zod2.z.string().optional(),
7371
7515
  showStats: import_zod2.z.boolean().optional(),
7372
7516
  request: RequestResponseOptionsSchema.optional(),
7373
7517
  response: RequestResponseOptionsSchema.optional(),
@@ -7384,6 +7528,7 @@ var ConfigFileSchema = import_zod2.z.strictObject({
7384
7528
  schemaType: import_zod2.z.enum(["all", "request", "response"]).optional(),
7385
7529
  prefix: import_zod2.z.string().optional(),
7386
7530
  suffix: import_zod2.z.string().optional(),
7531
+ stripSchemaPrefix: import_zod2.z.string().optional(),
7387
7532
  showStats: import_zod2.z.boolean().optional(),
7388
7533
  request: RequestResponseOptionsSchema.optional(),
7389
7534
  response: RequestResponseOptionsSchema.optional(),
@@ -7413,7 +7558,7 @@ async function loadConfig(configPath) {
7413
7558
  }
7414
7559
  if (!result || !result.config) {
7415
7560
  throw new Error(
7416
- configPath ? `Config file not found at: ${configPath}` : "No config file found. Searched for: openapi-to-zod.config.ts, openapi-to-zod.config.json, package.json (openapi-to-zod key)"
7561
+ configPath ? `Config file not found at: ${configPath}` : "No config file found. Searched for: openapi-to-zod.config.ts, openapi-to-zod.config.json, package.json (openapi-to-zod key)\nRun 'openapi-to-zod init' to create a new config file."
7417
7562
  );
7418
7563
  }
7419
7564
  try {
@@ -7520,14 +7665,7 @@ function findSpecFiles() {
7520
7665
  }
7521
7666
  async function executeConfigMode(options) {
7522
7667
  var _a, _b;
7523
- let config;
7524
- try {
7525
- config = await loadConfig(options.config);
7526
- } catch {
7527
- throw new CliOptionsError("No config file found. Run 'openapi-to-zod init' to create one.", {
7528
- configPath: options.config
7529
- });
7530
- }
7668
+ const config = await loadConfig(options.config);
7531
7669
  const specs = mergeConfigWithDefaults(config);
7532
7670
  const executionMode = config.executionMode || "parallel";
7533
7671
  const batchSize = (_b = (_a = specs[0]) == null ? void 0 : _a.batchSize) != null ? _b : 10;