@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/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { O as OpenApiGeneratorOptions } from './types-BjoP91vk.mjs';
2
- export { C as CommonSchemaOptions, a as ConfigFile, E as ExecutionMode, b as OpenAPISchema, c as OpenAPISpec, d as OperationFilters, R as RequestOptions, e as ResponseOptions, f as defineConfig } from './types-BjoP91vk.mjs';
1
+ import { O as OpenApiGeneratorOptions } from './types-CI48CjiU.mjs';
2
+ export { C as CommonSchemaOptions, a as ConfigFile, E as ExecutionMode, b as OpenAPISchema, c as OpenAPISpec, d as OperationFilters, R as RequestOptions, e as ResponseOptions, f as defineConfig } from './types-CI48CjiU.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-BjoP91vk.js';
2
- export { C as CommonSchemaOptions, a as ConfigFile, E as ExecutionMode, b as OpenAPISchema, c as OpenAPISpec, d as OperationFilters, R as RequestOptions, e as ResponseOptions, f as defineConfig } from './types-BjoP91vk.js';
1
+ import { O as OpenApiGeneratorOptions } from './types-CI48CjiU.js';
2
+ export { C as CommonSchemaOptions, a as ConfigFile, E as ExecutionMode, b as OpenAPISchema, c as OpenAPISpec, d as OperationFilters, R as RequestOptions, e as ResponseOptions, f as defineConfig } from './types-CI48CjiU.js';
3
3
 
4
4
  /**
5
5
  * Custom error classes for better error handling and debugging
package/dist/index.js CHANGED
@@ -94,12 +94,24 @@ var ConfigurationError = class extends GeneratorError {
94
94
  // src/openapi-generator.ts
95
95
  var import_node_fs = require("fs");
96
96
  var import_node_path = require("path");
97
- var import_minimatch2 = require("minimatch");
97
+ var import_minimatch3 = require("minimatch");
98
98
  var import_yaml = require("yaml");
99
99
 
100
100
  // src/utils/name-utils.ts
101
+ function sanitizeIdentifier(str) {
102
+ return str.replace(/[^a-zA-Z0-9._\-\s]+/g, "_");
103
+ }
101
104
  function toCamelCase(str, options) {
102
- let name = str.charAt(0).toLowerCase() + str.slice(1);
105
+ const sanitized = sanitizeIdentifier(str);
106
+ const words = sanitized.split(/[.\-_\s]+/).filter((word) => word.length > 0);
107
+ let name;
108
+ if (words.length === 0) {
109
+ name = str.charAt(0).toLowerCase() + str.slice(1);
110
+ } else if (words.length === 1) {
111
+ name = words[0].charAt(0).toLowerCase() + words[0].slice(1);
112
+ } else {
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
+ }
103
115
  if (options == null ? void 0 : options.prefix) {
104
116
  const prefix = options.prefix.toLowerCase();
105
117
  name = prefix + name.charAt(0).toUpperCase() + name.slice(1);
@@ -112,12 +124,23 @@ function toCamelCase(str, options) {
112
124
  }
113
125
  function toPascalCase(str) {
114
126
  const stringValue = String(str);
115
- 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("");
127
+ const isAlreadyValidCase = /^[a-zA-Z][a-zA-Z0-9]*$/.test(stringValue);
128
+ if (isAlreadyValidCase) {
129
+ return stringValue.charAt(0).toUpperCase() + stringValue.slice(1);
130
+ }
131
+ const sanitized = sanitizeIdentifier(stringValue);
132
+ const words = sanitized.split(/[.\-_\s]+/).filter((word) => word.length > 0);
133
+ let result;
134
+ if (words.length === 0) {
135
+ result = "Value";
136
+ } else {
137
+ result = words.map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
138
+ }
116
139
  if (/^\d/.test(result)) {
117
140
  result = `N${result}`;
118
141
  }
119
142
  if (!result || /^_+$/.test(result)) {
120
- result = "Value";
143
+ return "Value";
121
144
  }
122
145
  return result;
123
146
  }
@@ -129,9 +152,28 @@ function resolveRef(ref) {
129
152
  // src/generators/enum-generator.ts
130
153
  function generateEnum(name, values, options) {
131
154
  const schemaName = `${toCamelCase(name, options)}Schema`;
132
- const enumValues = values.map((v) => `"${v}"`).join(", ");
133
- const schemaCode = `export const ${schemaName} = z.enum([${enumValues}]);`;
134
- const typeCode = `export type ${name} = z.infer<typeof ${schemaName}>;`;
155
+ const typeName = toPascalCase(name);
156
+ const allBooleans = values.every((v) => typeof v === "boolean");
157
+ if (allBooleans) {
158
+ const schemaCode2 = `export const ${schemaName} = z.boolean();`;
159
+ const typeCode2 = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
160
+ return { schemaCode: schemaCode2, typeCode: typeCode2 };
161
+ }
162
+ const allStrings = values.every((v) => typeof v === "string");
163
+ if (allStrings) {
164
+ const enumValues = values.map((v) => `"${v}"`).join(", ");
165
+ const schemaCode2 = `export const ${schemaName} = z.enum([${enumValues}]);`;
166
+ const typeCode2 = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
167
+ return { schemaCode: schemaCode2, typeCode: typeCode2 };
168
+ }
169
+ const literalValues = values.map((v) => {
170
+ if (typeof v === "string") {
171
+ return `z.literal("${v}")`;
172
+ }
173
+ return `z.literal(${v})`;
174
+ }).join(", ");
175
+ const schemaCode = `export const ${schemaName} = z.union([${literalValues}]);`;
176
+ const typeCode = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
135
177
  return { schemaCode, typeCode };
136
178
  }
137
179
 
@@ -140,7 +182,7 @@ function escapeDescription(str) {
140
182
  return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
141
183
  }
142
184
  function escapePattern(str) {
143
- return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
185
+ return str.replace(/\//g, "\\/");
144
186
  }
145
187
  function escapeJSDoc(str) {
146
188
  return str.replace(/\*\//g, "*\\/");
@@ -264,6 +306,64 @@ var LRUCache = class {
264
306
  }
265
307
  };
266
308
 
309
+ // src/utils/pattern-utils.ts
310
+ var import_minimatch = require("minimatch");
311
+ function isValidGlobPattern(pattern) {
312
+ try {
313
+ new import_minimatch.minimatch.Minimatch(pattern);
314
+ return true;
315
+ } catch {
316
+ return false;
317
+ }
318
+ }
319
+ function isGlobPattern(pattern) {
320
+ return /[*?[\]{}!]/.test(pattern);
321
+ }
322
+ function stripPrefix(input, pattern, ensureLeadingChar) {
323
+ if (!pattern) {
324
+ return input;
325
+ }
326
+ if (isGlobPattern(pattern) && !isValidGlobPattern(pattern)) {
327
+ console.warn(`\u26A0\uFE0F Invalid glob pattern "${pattern}": Pattern is malformed`);
328
+ return input;
329
+ }
330
+ if (isGlobPattern(pattern)) {
331
+ let longestMatch = -1;
332
+ for (let i = 1; i <= input.length; i++) {
333
+ const testPrefix = input.substring(0, i);
334
+ if ((0, import_minimatch.minimatch)(testPrefix, pattern)) {
335
+ longestMatch = i;
336
+ }
337
+ }
338
+ if (longestMatch > 0) {
339
+ const stripped = input.substring(longestMatch);
340
+ if (ensureLeadingChar) {
341
+ if (stripped === "") {
342
+ return ensureLeadingChar;
343
+ }
344
+ if (!stripped.startsWith(ensureLeadingChar)) {
345
+ return `${ensureLeadingChar}${stripped}`;
346
+ }
347
+ }
348
+ return stripped === "" && !ensureLeadingChar ? input : stripped;
349
+ }
350
+ return input;
351
+ }
352
+ if (input.startsWith(pattern)) {
353
+ const stripped = input.substring(pattern.length);
354
+ if (ensureLeadingChar) {
355
+ if (stripped === "") {
356
+ return ensureLeadingChar;
357
+ }
358
+ if (!stripped.startsWith(ensureLeadingChar)) {
359
+ return `${ensureLeadingChar}${stripped}`;
360
+ }
361
+ }
362
+ return stripped;
363
+ }
364
+ return input;
365
+ }
366
+
267
367
  // src/validators/array-validator.ts
268
368
  function generateArrayValidation(schema, context) {
269
369
  var _a;
@@ -1120,8 +1220,9 @@ var _PropertyGenerator = class _PropertyGenerator {
1120
1220
  }
1121
1221
  (_a = this.context.schemaDependencies.get(currentSchema)) == null ? void 0 : _a.add(refName);
1122
1222
  }
1123
- const schemaName = `${toCamelCase(resolvedRefName, this.context.namingOptions)}Schema`;
1124
- if (currentSchema && this.isCircularThroughAlias(currentSchema, refName)) {
1223
+ const strippedRefName = stripPrefix(resolvedRefName, this.context.stripSchemaPrefix);
1224
+ const schemaName = `${toCamelCase(strippedRefName, this.context.namingOptions)}Schema`;
1225
+ if (currentSchema && (refName === currentSchema || this.isCircularThroughAlias(currentSchema, refName))) {
1125
1226
  const lazySchema = `z.lazy((): z.ZodTypeAny => ${schemaName})`;
1126
1227
  return wrapNullable(lazySchema, nullable);
1127
1228
  }
@@ -1133,9 +1234,25 @@ var _PropertyGenerator = class _PropertyGenerator {
1133
1234
  return wrapNullable(zodLiteral, nullable);
1134
1235
  }
1135
1236
  if (schema.enum) {
1136
- const enumValues = schema.enum.map((v) => `"${v}"`).join(", ");
1137
- const zodEnum = `z.enum([${enumValues}])`;
1138
- return wrapNullable(zodEnum, nullable);
1237
+ const allBooleans = schema.enum.every((v) => typeof v === "boolean");
1238
+ if (allBooleans) {
1239
+ const zodBoolean = "z.boolean()";
1240
+ return wrapNullable(zodBoolean, nullable);
1241
+ }
1242
+ const allStrings = schema.enum.every((v) => typeof v === "string");
1243
+ if (allStrings) {
1244
+ const enumValues = schema.enum.map((v) => `"${v}"`).join(", ");
1245
+ const zodEnum = `z.enum([${enumValues}])`;
1246
+ return wrapNullable(zodEnum, nullable);
1247
+ }
1248
+ const literalValues = schema.enum.map((v) => {
1249
+ if (typeof v === "string") {
1250
+ return `z.literal("${v}")`;
1251
+ }
1252
+ return `z.literal(${v})`;
1253
+ }).join(", ");
1254
+ const zodUnion = `z.union([${literalValues}])`;
1255
+ return wrapNullable(zodUnion, nullable);
1139
1256
  }
1140
1257
  if (schema.allOf) {
1141
1258
  let composition = generateAllOf(
@@ -1266,7 +1383,7 @@ _PropertyGenerator.INCLUSION_RULES = {
1266
1383
  var PropertyGenerator = _PropertyGenerator;
1267
1384
 
1268
1385
  // src/utils/operation-filters.ts
1269
- var import_minimatch = require("minimatch");
1386
+ var import_minimatch2 = require("minimatch");
1270
1387
  function createFilterStatistics() {
1271
1388
  return {
1272
1389
  totalOperations: 0,
@@ -1285,7 +1402,7 @@ function matchesAnyPattern(value, patterns) {
1285
1402
  if (!value) {
1286
1403
  return false;
1287
1404
  }
1288
- return patterns.some((pattern) => (0, import_minimatch.minimatch)(value, pattern));
1405
+ return patterns.some((pattern) => (0, import_minimatch2.minimatch)(value, pattern));
1289
1406
  }
1290
1407
  function containsAny(arr, values) {
1291
1408
  if (!values || values.length === 0) {
@@ -1421,6 +1538,7 @@ var OpenApiGenerator = class {
1421
1538
  schemaType: options.schemaType || "all",
1422
1539
  prefix: options.prefix,
1423
1540
  suffix: options.suffix,
1541
+ stripSchemaPrefix: options.stripSchemaPrefix,
1424
1542
  showStats: (_c = options.showStats) != null ? _c : true,
1425
1543
  request: options.request,
1426
1544
  response: options.response,
@@ -1497,7 +1615,8 @@ var OpenApiGenerator = class {
1497
1615
  namingOptions: {
1498
1616
  prefix: this.options.prefix,
1499
1617
  suffix: this.options.suffix
1500
- }
1618
+ },
1619
+ stripSchemaPrefix: this.options.stripSchemaPrefix
1501
1620
  });
1502
1621
  }
1503
1622
  /**
@@ -1510,6 +1629,9 @@ var OpenApiGenerator = class {
1510
1629
  throw new SpecValidationError("No schemas found in OpenAPI spec", { filePath: this.options.input });
1511
1630
  }
1512
1631
  for (const [name, schema] of Object.entries(this.spec.components.schemas)) {
1632
+ if (this.options.operationFilters && this.schemaUsageMap.size > 0 && !this.schemaUsageMap.has(name)) {
1633
+ continue;
1634
+ }
1513
1635
  this.generateComponentSchema(name, schema);
1514
1636
  }
1515
1637
  this.generateQueryParameterSchemas();
@@ -1531,9 +1653,11 @@ var OpenApiGenerator = class {
1531
1653
  const typeCode = this.types.get(name);
1532
1654
  if (schemaCode) {
1533
1655
  output.push(schemaCode);
1534
- if (!schemaCode.includes(`export type ${name}`)) {
1535
- const schemaName = `${toCamelCase(name, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
1536
- output.push(`export type ${name} = z.infer<typeof ${schemaName}>;`);
1656
+ const strippedName = stripPrefix(name, this.options.stripSchemaPrefix);
1657
+ const typeName = toPascalCase(strippedName);
1658
+ if (!schemaCode.includes(`export type ${typeName}`)) {
1659
+ const schemaName = `${toCamelCase(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
1660
+ output.push(`export type ${typeName} = z.infer<typeof ${schemaName}>;`);
1537
1661
  }
1538
1662
  output.push("");
1539
1663
  } else if (typeCode) {
@@ -1849,7 +1973,8 @@ var OpenApiGenerator = class {
1849
1973
  const resolvedOptions = context === "response" ? this.responseOptions : this.requestOptions;
1850
1974
  if (schema.enum) {
1851
1975
  const jsdoc2 = generateJSDoc(schema, name, { includeDescriptions: resolvedOptions.includeDescriptions });
1852
- const { schemaCode, typeCode } = generateEnum(name, schema.enum, {
1976
+ const strippedName2 = stripPrefix(name, this.options.stripSchemaPrefix);
1977
+ const { schemaCode, typeCode } = generateEnum(strippedName2, schema.enum, {
1853
1978
  prefix: this.options.prefix,
1854
1979
  suffix: this.options.suffix
1855
1980
  });
@@ -1858,7 +1983,8 @@ ${typeCode}`;
1858
1983
  this.schemas.set(name, enumSchemaCode);
1859
1984
  return;
1860
1985
  }
1861
- const schemaName = `${toCamelCase(name, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
1986
+ const strippedName = stripPrefix(name, this.options.stripSchemaPrefix);
1987
+ const schemaName = `${toCamelCase(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
1862
1988
  const jsdoc = generateJSDoc(schema, name, { includeDescriptions: resolvedOptions.includeDescriptions });
1863
1989
  if (schema.allOf && schema.allOf.length === 1 && schema.allOf[0].$ref) {
1864
1990
  const refName = resolveRef(schema.allOf[0].$ref);
@@ -1874,7 +2000,8 @@ ${typeCode}`;
1874
2000
  namingOptions: {
1875
2001
  prefix: this.options.prefix,
1876
2002
  suffix: this.options.suffix
1877
- }
2003
+ },
2004
+ stripSchemaPrefix: this.options.stripSchemaPrefix
1878
2005
  });
1879
2006
  const isAlias = !!(schema.$ref && !schema.properties && !schema.allOf && !schema.oneOf && !schema.anyOf);
1880
2007
  const zodSchema = this.propertyGenerator.generatePropertySchema(schema, name, isAlias);
@@ -1993,7 +2120,7 @@ ${propsCode}
1993
2120
  const headerLower = headerName.toLowerCase();
1994
2121
  return ignorePatterns.some((pattern) => {
1995
2122
  const patternLower = pattern.toLowerCase();
1996
- return (0, import_minimatch2.minimatch)(headerLower, patternLower);
2123
+ return (0, import_minimatch3.minimatch)(headerLower, patternLower);
1997
2124
  });
1998
2125
  }
1999
2126
  /**
@@ -2076,12 +2203,27 @@ ${propsCode}
2076
2203
  generateQueryParamType(schema, param) {
2077
2204
  if (schema.$ref) {
2078
2205
  const refName = resolveRef(schema.$ref);
2079
- const schemaName = toCamelCase(refName, { prefix: this.options.prefix, suffix: this.options.suffix });
2206
+ const strippedRefName = stripPrefix(refName, this.options.stripSchemaPrefix);
2207
+ const schemaName = toCamelCase(strippedRefName, { prefix: this.options.prefix, suffix: this.options.suffix });
2080
2208
  return `${schemaName}Schema`;
2081
2209
  }
2082
2210
  if (schema.enum) {
2083
- const enumValues = schema.enum.map((v) => typeof v === "string" ? `"${v}"` : v).join(", ");
2084
- return `z.enum([${enumValues}])`;
2211
+ const allBooleans = schema.enum.every((v) => typeof v === "boolean");
2212
+ if (allBooleans) {
2213
+ return "z.boolean()";
2214
+ }
2215
+ const allStrings = schema.enum.every((v) => typeof v === "string");
2216
+ if (allStrings) {
2217
+ const enumValues = schema.enum.map((v) => `"${v}"`).join(", ");
2218
+ return `z.enum([${enumValues}])`;
2219
+ }
2220
+ const literalValues = schema.enum.map((v) => {
2221
+ if (typeof v === "string") {
2222
+ return `z.literal("${v}")`;
2223
+ }
2224
+ return `z.literal(${v})`;
2225
+ }).join(", ");
2226
+ return `z.union([${literalValues}])`;
2085
2227
  }
2086
2228
  const type = schema.type;
2087
2229
  if (type === "string") {