@cerios/openapi-to-zod 1.0.0 → 1.1.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.mjs CHANGED
@@ -71,8 +71,20 @@ import { minimatch as minimatch2 } from "minimatch";
71
71
  import { parse } from "yaml";
72
72
 
73
73
  // src/utils/name-utils.ts
74
+ function sanitizeIdentifier(str) {
75
+ return str.replace(/[^a-zA-Z0-9._\-\s]+/g, "_");
76
+ }
74
77
  function toCamelCase(str, options) {
75
- let name = str.charAt(0).toLowerCase() + str.slice(1);
78
+ const sanitized = sanitizeIdentifier(str);
79
+ const words = sanitized.split(/[.\-_\s]+/).filter((word) => word.length > 0);
80
+ let name;
81
+ if (words.length === 0) {
82
+ name = str.charAt(0).toLowerCase() + str.slice(1);
83
+ } else if (words.length === 1) {
84
+ name = words[0].charAt(0).toLowerCase() + words[0].slice(1);
85
+ } else {
86
+ name = words[0].charAt(0).toLowerCase() + words[0].slice(1) + words.slice(1).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
87
+ }
76
88
  if (options == null ? void 0 : options.prefix) {
77
89
  const prefix = options.prefix.toLowerCase();
78
90
  name = prefix + name.charAt(0).toUpperCase() + name.slice(1);
@@ -85,12 +97,23 @@ function toCamelCase(str, options) {
85
97
  }
86
98
  function toPascalCase(str) {
87
99
  const stringValue = String(str);
88
- 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("");
100
+ const isAlreadyValidCase = /^[a-zA-Z][a-zA-Z0-9]*$/.test(stringValue);
101
+ if (isAlreadyValidCase) {
102
+ return stringValue.charAt(0).toUpperCase() + stringValue.slice(1);
103
+ }
104
+ const sanitized = sanitizeIdentifier(stringValue);
105
+ const words = sanitized.split(/[.\-_\s]+/).filter((word) => word.length > 0);
106
+ let result;
107
+ if (words.length === 0) {
108
+ result = "Value";
109
+ } else {
110
+ result = words.map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
111
+ }
89
112
  if (/^\d/.test(result)) {
90
113
  result = `N${result}`;
91
114
  }
92
115
  if (!result || /^_+$/.test(result)) {
93
- result = "Value";
116
+ return "Value";
94
117
  }
95
118
  return result;
96
119
  }
@@ -102,9 +125,10 @@ function resolveRef(ref) {
102
125
  // src/generators/enum-generator.ts
103
126
  function generateEnum(name, values, options) {
104
127
  const schemaName = `${toCamelCase(name, options)}Schema`;
128
+ const typeName = toPascalCase(name);
105
129
  const enumValues = values.map((v) => `"${v}"`).join(", ");
106
130
  const schemaCode = `export const ${schemaName} = z.enum([${enumValues}]);`;
107
- const typeCode = `export type ${name} = z.infer<typeof ${schemaName}>;`;
131
+ const typeCode = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
108
132
  return { schemaCode, typeCode };
109
133
  }
110
134
 
@@ -237,6 +261,76 @@ var LRUCache = class {
237
261
  }
238
262
  };
239
263
 
264
+ // src/utils/pattern-utils.ts
265
+ function isRegexPattern(pattern) {
266
+ if (pattern.startsWith("^") || pattern.endsWith("$")) {
267
+ return true;
268
+ }
269
+ if (/\\[dDwWsS]/.test(pattern)) {
270
+ return true;
271
+ }
272
+ if (/\.\*|\.\+/.test(pattern)) {
273
+ return true;
274
+ }
275
+ if (/[[\]()]/.test(pattern)) {
276
+ return true;
277
+ }
278
+ if (/[^/][+?*]\{/.test(pattern)) {
279
+ return true;
280
+ }
281
+ return false;
282
+ }
283
+ function patternToRegex(pattern) {
284
+ if (pattern instanceof RegExp) {
285
+ return pattern;
286
+ }
287
+ if (isRegexPattern(pattern)) {
288
+ try {
289
+ return new RegExp(pattern);
290
+ } catch (error) {
291
+ console.warn(`\u26A0\uFE0F Invalid regex pattern "${pattern}": ${error instanceof Error ? error.message : String(error)}`);
292
+ return null;
293
+ }
294
+ }
295
+ return null;
296
+ }
297
+ function stripPrefix(input, pattern, ensureLeadingChar) {
298
+ if (!pattern) {
299
+ return input;
300
+ }
301
+ const regex = patternToRegex(pattern);
302
+ if (regex) {
303
+ const match = input.match(regex);
304
+ if (match && match.index === 0) {
305
+ const stripped = input.substring(match[0].length);
306
+ if (ensureLeadingChar) {
307
+ if (stripped === "") {
308
+ return ensureLeadingChar;
309
+ }
310
+ if (!stripped.startsWith(ensureLeadingChar)) {
311
+ return `${ensureLeadingChar}${stripped}`;
312
+ }
313
+ }
314
+ return stripped;
315
+ }
316
+ } else {
317
+ const stringPattern = pattern;
318
+ if (input.startsWith(stringPattern)) {
319
+ const stripped = input.substring(stringPattern.length);
320
+ if (ensureLeadingChar) {
321
+ if (stripped === "") {
322
+ return ensureLeadingChar;
323
+ }
324
+ if (!stripped.startsWith(ensureLeadingChar)) {
325
+ return `${ensureLeadingChar}${stripped}`;
326
+ }
327
+ }
328
+ return stripped;
329
+ }
330
+ }
331
+ return input;
332
+ }
333
+
240
334
  // src/validators/array-validator.ts
241
335
  function generateArrayValidation(schema, context) {
242
336
  var _a;
@@ -1093,8 +1187,9 @@ var _PropertyGenerator = class _PropertyGenerator {
1093
1187
  }
1094
1188
  (_a = this.context.schemaDependencies.get(currentSchema)) == null ? void 0 : _a.add(refName);
1095
1189
  }
1096
- const schemaName = `${toCamelCase(resolvedRefName, this.context.namingOptions)}Schema`;
1097
- if (currentSchema && this.isCircularThroughAlias(currentSchema, refName)) {
1190
+ const strippedRefName = stripPrefix(resolvedRefName, this.context.stripSchemaPrefix);
1191
+ const schemaName = `${toCamelCase(strippedRefName, this.context.namingOptions)}Schema`;
1192
+ if (currentSchema && (refName === currentSchema || this.isCircularThroughAlias(currentSchema, refName))) {
1098
1193
  const lazySchema = `z.lazy((): z.ZodTypeAny => ${schemaName})`;
1099
1194
  return wrapNullable(lazySchema, nullable);
1100
1195
  }
@@ -1394,6 +1489,7 @@ var OpenApiGenerator = class {
1394
1489
  schemaType: options.schemaType || "all",
1395
1490
  prefix: options.prefix,
1396
1491
  suffix: options.suffix,
1492
+ stripSchemaPrefix: options.stripSchemaPrefix,
1397
1493
  showStats: (_c = options.showStats) != null ? _c : true,
1398
1494
  request: options.request,
1399
1495
  response: options.response,
@@ -1470,7 +1566,8 @@ var OpenApiGenerator = class {
1470
1566
  namingOptions: {
1471
1567
  prefix: this.options.prefix,
1472
1568
  suffix: this.options.suffix
1473
- }
1569
+ },
1570
+ stripSchemaPrefix: this.options.stripSchemaPrefix
1474
1571
  });
1475
1572
  }
1476
1573
  /**
@@ -1504,9 +1601,11 @@ var OpenApiGenerator = class {
1504
1601
  const typeCode = this.types.get(name);
1505
1602
  if (schemaCode) {
1506
1603
  output.push(schemaCode);
1507
- if (!schemaCode.includes(`export type ${name}`)) {
1508
- const schemaName = `${toCamelCase(name, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
1509
- output.push(`export type ${name} = z.infer<typeof ${schemaName}>;`);
1604
+ const strippedName = stripPrefix(name, this.options.stripSchemaPrefix);
1605
+ const typeName = toPascalCase(strippedName);
1606
+ if (!schemaCode.includes(`export type ${typeName}`)) {
1607
+ const schemaName = `${toCamelCase(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
1608
+ output.push(`export type ${typeName} = z.infer<typeof ${schemaName}>;`);
1510
1609
  }
1511
1610
  output.push("");
1512
1611
  } else if (typeCode) {
@@ -1822,7 +1921,8 @@ var OpenApiGenerator = class {
1822
1921
  const resolvedOptions = context === "response" ? this.responseOptions : this.requestOptions;
1823
1922
  if (schema.enum) {
1824
1923
  const jsdoc2 = generateJSDoc(schema, name, { includeDescriptions: resolvedOptions.includeDescriptions });
1825
- const { schemaCode, typeCode } = generateEnum(name, schema.enum, {
1924
+ const strippedName2 = stripPrefix(name, this.options.stripSchemaPrefix);
1925
+ const { schemaCode, typeCode } = generateEnum(strippedName2, schema.enum, {
1826
1926
  prefix: this.options.prefix,
1827
1927
  suffix: this.options.suffix
1828
1928
  });
@@ -1831,7 +1931,8 @@ ${typeCode}`;
1831
1931
  this.schemas.set(name, enumSchemaCode);
1832
1932
  return;
1833
1933
  }
1834
- const schemaName = `${toCamelCase(name, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
1934
+ const strippedName = stripPrefix(name, this.options.stripSchemaPrefix);
1935
+ const schemaName = `${toCamelCase(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
1835
1936
  const jsdoc = generateJSDoc(schema, name, { includeDescriptions: resolvedOptions.includeDescriptions });
1836
1937
  if (schema.allOf && schema.allOf.length === 1 && schema.allOf[0].$ref) {
1837
1938
  const refName = resolveRef(schema.allOf[0].$ref);
@@ -1847,7 +1948,8 @@ ${typeCode}`;
1847
1948
  namingOptions: {
1848
1949
  prefix: this.options.prefix,
1849
1950
  suffix: this.options.suffix
1850
- }
1951
+ },
1952
+ stripSchemaPrefix: this.options.stripSchemaPrefix
1851
1953
  });
1852
1954
  const isAlias = !!(schema.$ref && !schema.properties && !schema.allOf && !schema.oneOf && !schema.anyOf);
1853
1955
  const zodSchema = this.propertyGenerator.generatePropertySchema(schema, name, isAlias);
@@ -2049,7 +2151,8 @@ ${propsCode}
2049
2151
  generateQueryParamType(schema, param) {
2050
2152
  if (schema.$ref) {
2051
2153
  const refName = resolveRef(schema.$ref);
2052
- const schemaName = toCamelCase(refName, { prefix: this.options.prefix, suffix: this.options.suffix });
2154
+ const strippedRefName = stripPrefix(refName, this.options.stripSchemaPrefix);
2155
+ const schemaName = toCamelCase(strippedRefName, { prefix: this.options.prefix, suffix: this.options.suffix });
2053
2156
  return `${schemaName}Schema`;
2054
2157
  }
2055
2158
  if (schema.enum) {