@cerios/openapi-to-zod 0.6.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/cli.js CHANGED
@@ -5013,10 +5013,123 @@ var ConfigurationError = class extends GeneratorError {
5013
5013
  }
5014
5014
  };
5015
5015
 
5016
+ // src/batch-executor.ts
5017
+ async function processSpec(spec, index, total, createGenerator) {
5018
+ const specInput = spec.input || "spec";
5019
+ const specOutput = spec.output || "output";
5020
+ console.log(`Processing [${index + 1}/${total}] ${specInput}...`);
5021
+ try {
5022
+ const generator = createGenerator(spec);
5023
+ generator.generate();
5024
+ return {
5025
+ spec,
5026
+ success: true
5027
+ };
5028
+ } catch (error) {
5029
+ const errorMessage = error instanceof Error ? error.message : String(error);
5030
+ console.error(`\u2717 Failed to generate ${specOutput}: ${errorMessage}`);
5031
+ return {
5032
+ spec,
5033
+ success: false,
5034
+ error: errorMessage
5035
+ };
5036
+ }
5037
+ }
5038
+ async function executeParallel(specs, createGenerator, batchSize) {
5039
+ console.log(`
5040
+ Executing ${specs.length} specification(s) in parallel (batch size: ${batchSize})...
5041
+ `);
5042
+ const results = [];
5043
+ for (let i = 0; i < specs.length; i += batchSize) {
5044
+ const batch = specs.slice(i, Math.min(i + batchSize, specs.length));
5045
+ const batchPromises = batch.map(
5046
+ (spec, batchIndex) => processSpec(spec, i + batchIndex, specs.length, createGenerator)
5047
+ );
5048
+ const batchResults = await Promise.allSettled(batchPromises);
5049
+ for (let j = 0; j < batchResults.length; j++) {
5050
+ const result = batchResults[j];
5051
+ if (result.status === "fulfilled") {
5052
+ results.push(result.value);
5053
+ } else {
5054
+ results.push({
5055
+ spec: batch[j],
5056
+ success: false,
5057
+ error: result.reason instanceof Error ? result.reason.message : String(result.reason)
5058
+ });
5059
+ }
5060
+ }
5061
+ }
5062
+ return results;
5063
+ }
5064
+ async function executeSequential(specs, createGenerator) {
5065
+ console.log(`
5066
+ Executing ${specs.length} spec(s) sequentially...
5067
+ `);
5068
+ const results = [];
5069
+ for (let i = 0; i < specs.length; i++) {
5070
+ const result = await processSpec(specs[i], i, specs.length, createGenerator);
5071
+ results.push(result);
5072
+ }
5073
+ return results;
5074
+ }
5075
+ function printSummary(summary) {
5076
+ console.log(`
5077
+ ${"=".repeat(50)}`);
5078
+ console.log("Batch Execution Summary");
5079
+ console.log("=".repeat(50));
5080
+ console.log(`Total specs: ${summary.total}`);
5081
+ console.log(`Successful: ${summary.successful}`);
5082
+ console.log(`Failed: ${summary.failed}`);
5083
+ if (summary.failed > 0) {
5084
+ console.log("\nFailed specs:");
5085
+ for (const result of summary.results) {
5086
+ if (!result.success) {
5087
+ const specInput = result.spec.input || "spec";
5088
+ console.error(` \u2717 ${specInput}`);
5089
+ console.error(` Error: ${result.error}`);
5090
+ }
5091
+ }
5092
+ }
5093
+ console.log(`${"=".repeat(50)}
5094
+ `);
5095
+ }
5096
+ async function executeBatch(specs, executionMode = "parallel", createGenerator, batchSize) {
5097
+ if (specs.length === 0) {
5098
+ throw new ConfigurationError("No specs provided for batch execution", { specsCount: 0, executionMode });
5099
+ }
5100
+ let results = [];
5101
+ try {
5102
+ results = executionMode === "parallel" ? await executeParallel(specs, createGenerator, batchSize) : await executeSequential(specs, createGenerator);
5103
+ const summary = {
5104
+ total: results.length,
5105
+ successful: results.filter((r) => r.success).length,
5106
+ failed: results.filter((r) => !r.success).length,
5107
+ results
5108
+ };
5109
+ printSummary(summary);
5110
+ return summary;
5111
+ } finally {
5112
+ if (results.length > batchSize) {
5113
+ for (const result of results) {
5114
+ if (result.spec) {
5115
+ result.spec = null;
5116
+ }
5117
+ }
5118
+ if (global.gc) {
5119
+ global.gc();
5120
+ }
5121
+ }
5122
+ }
5123
+ }
5124
+ function getBatchExitCode(summary) {
5125
+ return summary.failed > 0 ? 1 : 0;
5126
+ }
5127
+
5016
5128
  // src/openapi-generator.ts
5017
5129
  init_cjs_shims();
5018
5130
  var import_node_fs = require("fs");
5019
5131
  var import_node_path = require("path");
5132
+ var import_minimatch2 = require("minimatch");
5020
5133
  var import_yaml = require("yaml");
5021
5134
 
5022
5135
  // src/generators/enum-generator.ts
@@ -5024,8 +5137,20 @@ init_cjs_shims();
5024
5137
 
5025
5138
  // src/utils/name-utils.ts
5026
5139
  init_cjs_shims();
5140
+ function sanitizeIdentifier(str) {
5141
+ return str.replace(/[^a-zA-Z0-9._\-\s]+/g, "_");
5142
+ }
5027
5143
  function toCamelCase(str, options) {
5028
- 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
+ }
5029
5154
  if (options == null ? void 0 : options.prefix) {
5030
5155
  const prefix = options.prefix.toLowerCase();
5031
5156
  name = prefix + name.charAt(0).toUpperCase() + name.slice(1);
@@ -5038,12 +5163,23 @@ function toCamelCase(str, options) {
5038
5163
  }
5039
5164
  function toPascalCase(str) {
5040
5165
  const stringValue = String(str);
5041
- 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
+ }
5042
5178
  if (/^\d/.test(result)) {
5043
5179
  result = `N${result}`;
5044
5180
  }
5045
5181
  if (!result || /^_+$/.test(result)) {
5046
- result = "Value";
5182
+ return "Value";
5047
5183
  }
5048
5184
  return result;
5049
5185
  }
@@ -5055,9 +5191,10 @@ function resolveRef(ref) {
5055
5191
  // src/generators/enum-generator.ts
5056
5192
  function generateEnum(name, values, options) {
5057
5193
  const schemaName = `${toCamelCase(name, options)}Schema`;
5194
+ const typeName = toPascalCase(name);
5058
5195
  const enumValues = values.map((v) => `"${v}"`).join(", ");
5059
5196
  const schemaCode = `export const ${schemaName} = z.enum([${enumValues}]);`;
5060
- const typeCode = `export type ${name} = z.infer<typeof ${schemaName}>;`;
5197
+ const typeCode = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
5061
5198
  return { schemaCode, typeCode };
5062
5199
  }
5063
5200
 
@@ -5165,6 +5302,9 @@ var LRUCache = class {
5165
5302
  this.cache = /* @__PURE__ */ new Map();
5166
5303
  this.maxSize = maxSize;
5167
5304
  }
5305
+ get capacity() {
5306
+ return this.maxSize;
5307
+ }
5168
5308
  get(key) {
5169
5309
  if (!this.cache.has(key)) return void 0;
5170
5310
  const value = this.cache.get(key);
@@ -5195,6 +5335,77 @@ var LRUCache = class {
5195
5335
  }
5196
5336
  };
5197
5337
 
5338
+ // src/utils/pattern-utils.ts
5339
+ init_cjs_shims();
5340
+ function isRegexPattern(pattern) {
5341
+ if (pattern.startsWith("^") || pattern.endsWith("$")) {
5342
+ return true;
5343
+ }
5344
+ if (/\\[dDwWsS]/.test(pattern)) {
5345
+ return true;
5346
+ }
5347
+ if (/\.\*|\.\+/.test(pattern)) {
5348
+ return true;
5349
+ }
5350
+ if (/[[\]()]/.test(pattern)) {
5351
+ return true;
5352
+ }
5353
+ if (/[^/][+?*]\{/.test(pattern)) {
5354
+ return true;
5355
+ }
5356
+ return false;
5357
+ }
5358
+ function patternToRegex(pattern) {
5359
+ if (pattern instanceof RegExp) {
5360
+ return pattern;
5361
+ }
5362
+ if (isRegexPattern(pattern)) {
5363
+ try {
5364
+ return new RegExp(pattern);
5365
+ } catch (error) {
5366
+ console.warn(`\u26A0\uFE0F Invalid regex pattern "${pattern}": ${error instanceof Error ? error.message : String(error)}`);
5367
+ return null;
5368
+ }
5369
+ }
5370
+ return null;
5371
+ }
5372
+ function stripPrefix(input, pattern, ensureLeadingChar) {
5373
+ if (!pattern) {
5374
+ return input;
5375
+ }
5376
+ const regex = patternToRegex(pattern);
5377
+ if (regex) {
5378
+ const match = input.match(regex);
5379
+ if (match && match.index === 0) {
5380
+ const stripped = input.substring(match[0].length);
5381
+ if (ensureLeadingChar) {
5382
+ if (stripped === "") {
5383
+ return ensureLeadingChar;
5384
+ }
5385
+ if (!stripped.startsWith(ensureLeadingChar)) {
5386
+ return `${ensureLeadingChar}${stripped}`;
5387
+ }
5388
+ }
5389
+ return stripped;
5390
+ }
5391
+ } else {
5392
+ const stringPattern = pattern;
5393
+ if (input.startsWith(stringPattern)) {
5394
+ const stripped = input.substring(stringPattern.length);
5395
+ if (ensureLeadingChar) {
5396
+ if (stripped === "") {
5397
+ return ensureLeadingChar;
5398
+ }
5399
+ if (!stripped.startsWith(ensureLeadingChar)) {
5400
+ return `${ensureLeadingChar}${stripped}`;
5401
+ }
5402
+ }
5403
+ return stripped;
5404
+ }
5405
+ }
5406
+ return input;
5407
+ }
5408
+
5198
5409
  // src/validators/array-validator.ts
5199
5410
  init_cjs_shims();
5200
5411
  function generateArrayValidation(schema, context) {
@@ -5722,6 +5933,11 @@ ${properties.join(",\n")}
5722
5933
  // src/validators/string-validator.ts
5723
5934
  init_cjs_shims();
5724
5935
  var PATTERN_CACHE = new LRUCache(1e3);
5936
+ function configurePatternCache(size) {
5937
+ if (size > 0 && size !== PATTERN_CACHE.capacity) {
5938
+ PATTERN_CACHE = new LRUCache(size);
5939
+ }
5940
+ }
5725
5941
  var FORMAT_MAP = {
5726
5942
  uuid: "z.uuid()",
5727
5943
  email: "z.email()",
@@ -6054,8 +6270,9 @@ var _PropertyGenerator = class _PropertyGenerator {
6054
6270
  }
6055
6271
  (_a = this.context.schemaDependencies.get(currentSchema)) == null ? void 0 : _a.add(refName);
6056
6272
  }
6057
- const schemaName = `${toCamelCase(resolvedRefName, this.context.namingOptions)}Schema`;
6058
- if (currentSchema && this.isCircularThroughAlias(currentSchema, refName)) {
6273
+ const strippedRefName = stripPrefix(resolvedRefName, this.context.stripSchemaPrefix);
6274
+ const schemaName = `${toCamelCase(strippedRefName, this.context.namingOptions)}Schema`;
6275
+ if (currentSchema && (refName === currentSchema || this.isCircularThroughAlias(currentSchema, refName))) {
6059
6276
  const lazySchema = `z.lazy((): z.ZodTypeAny => ${schemaName})`;
6060
6277
  return wrapNullable(lazySchema, nullable);
6061
6278
  }
@@ -6343,7 +6560,7 @@ var OpenApiGenerator = class {
6343
6560
  this.schemaUsageMap = /* @__PURE__ */ new Map();
6344
6561
  this.needsZodImport = true;
6345
6562
  this.filterStats = createFilterStatistics();
6346
- var _a, _b, _c;
6563
+ var _a, _b, _c, _d, _e;
6347
6564
  if (!options.input) {
6348
6565
  throw new ConfigurationError("Input path is required", { providedOptions: options });
6349
6566
  }
@@ -6356,11 +6573,18 @@ var OpenApiGenerator = class {
6356
6573
  schemaType: options.schemaType || "all",
6357
6574
  prefix: options.prefix,
6358
6575
  suffix: options.suffix,
6576
+ stripSchemaPrefix: options.stripSchemaPrefix,
6359
6577
  showStats: (_c = options.showStats) != null ? _c : true,
6360
6578
  request: options.request,
6361
6579
  response: options.response,
6362
- operationFilters: options.operationFilters
6580
+ operationFilters: options.operationFilters,
6581
+ ignoreHeaders: options.ignoreHeaders,
6582
+ cacheSize: (_d = options.cacheSize) != null ? _d : 1e3,
6583
+ batchSize: (_e = options.batchSize) != null ? _e : 10
6363
6584
  };
6585
+ if (this.options.cacheSize) {
6586
+ configurePatternCache(this.options.cacheSize);
6587
+ }
6364
6588
  try {
6365
6589
  const fs = require("fs");
6366
6590
  if (!fs.existsSync(this.options.input)) {
@@ -6426,7 +6650,8 @@ var OpenApiGenerator = class {
6426
6650
  namingOptions: {
6427
6651
  prefix: this.options.prefix,
6428
6652
  suffix: this.options.suffix
6429
- }
6653
+ },
6654
+ stripSchemaPrefix: this.options.stripSchemaPrefix
6430
6655
  });
6431
6656
  }
6432
6657
  /**
@@ -6460,9 +6685,11 @@ var OpenApiGenerator = class {
6460
6685
  const typeCode = this.types.get(name);
6461
6686
  if (schemaCode) {
6462
6687
  output.push(schemaCode);
6463
- if (!schemaCode.includes(`export type ${name}`)) {
6464
- const schemaName = `${toCamelCase(name, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
6465
- output.push(`export type ${name} = z.infer<typeof ${schemaName}>;`);
6688
+ const strippedName = stripPrefix(name, this.options.stripSchemaPrefix);
6689
+ const typeName = toPascalCase(strippedName);
6690
+ if (!schemaCode.includes(`export type ${typeName}`)) {
6691
+ const schemaName = `${toCamelCase(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
6692
+ output.push(`export type ${typeName} = z.infer<typeof ${schemaName}>;`);
6466
6693
  }
6467
6694
  output.push("");
6468
6695
  } else if (typeCode) {
@@ -6496,6 +6723,7 @@ var OpenApiGenerator = class {
6496
6723
  const normalizedOutput = (0, import_node_path.normalize)(this.options.output);
6497
6724
  this.ensureDirectoryExists(normalizedOutput);
6498
6725
  (0, import_node_fs.writeFileSync)(normalizedOutput, output);
6726
+ console.log(` \u2713 Generated ${normalizedOutput}`);
6499
6727
  }
6500
6728
  /**
6501
6729
  * Resolve options for a specific context (request or response)
@@ -6777,7 +7005,8 @@ var OpenApiGenerator = class {
6777
7005
  const resolvedOptions = context === "response" ? this.responseOptions : this.requestOptions;
6778
7006
  if (schema.enum) {
6779
7007
  const jsdoc2 = generateJSDoc(schema, name, { includeDescriptions: resolvedOptions.includeDescriptions });
6780
- const { schemaCode, typeCode } = generateEnum(name, schema.enum, {
7008
+ const strippedName2 = stripPrefix(name, this.options.stripSchemaPrefix);
7009
+ const { schemaCode, typeCode } = generateEnum(strippedName2, schema.enum, {
6781
7010
  prefix: this.options.prefix,
6782
7011
  suffix: this.options.suffix
6783
7012
  });
@@ -6786,7 +7015,8 @@ ${typeCode}`;
6786
7015
  this.schemas.set(name, enumSchemaCode);
6787
7016
  return;
6788
7017
  }
6789
- const schemaName = `${toCamelCase(name, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
7018
+ const strippedName = stripPrefix(name, this.options.stripSchemaPrefix);
7019
+ const schemaName = `${toCamelCase(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
6790
7020
  const jsdoc = generateJSDoc(schema, name, { includeDescriptions: resolvedOptions.includeDescriptions });
6791
7021
  if (schema.allOf && schema.allOf.length === 1 && schema.allOf[0].$ref) {
6792
7022
  const refName = resolveRef(schema.allOf[0].$ref);
@@ -6802,7 +7032,8 @@ ${typeCode}`;
6802
7032
  namingOptions: {
6803
7033
  prefix: this.options.prefix,
6804
7034
  suffix: this.options.suffix
6805
- }
7035
+ },
7036
+ stripSchemaPrefix: this.options.stripSchemaPrefix
6806
7037
  });
6807
7038
  const isAlias = !!(schema.$ref && !schema.properties && !schema.allOf && !schema.oneOf && !schema.anyOf);
6808
7039
  const zodSchema = this.propertyGenerator.generatePropertySchema(schema, name, isAlias);
@@ -6906,6 +7137,24 @@ ${propsCode}
6906
7137
  }
6907
7138
  }
6908
7139
  }
7140
+ /**
7141
+ * Check if a header should be ignored based on filter patterns
7142
+ * @internal
7143
+ */
7144
+ shouldIgnoreHeader(headerName) {
7145
+ const ignorePatterns = this.options.ignoreHeaders;
7146
+ if (!ignorePatterns || ignorePatterns.length === 0) {
7147
+ return false;
7148
+ }
7149
+ if (ignorePatterns.includes("*")) {
7150
+ return true;
7151
+ }
7152
+ const headerLower = headerName.toLowerCase();
7153
+ return ignorePatterns.some((pattern) => {
7154
+ const patternLower = pattern.toLowerCase();
7155
+ return (0, import_minimatch2.minimatch)(headerLower, patternLower);
7156
+ });
7157
+ }
6909
7158
  /**
6910
7159
  * Generate header parameter schemas for each operation
6911
7160
  * Header parameters are always string type (HTTP header semantics)
@@ -6928,7 +7177,7 @@ ${propsCode}
6928
7177
  continue;
6929
7178
  }
6930
7179
  const headerParams = operation.parameters.filter(
6931
- (param) => param && typeof param === "object" && param.in === "header"
7180
+ (param) => param && typeof param === "object" && param.in === "header" && !this.shouldIgnoreHeader(param.name)
6932
7181
  );
6933
7182
  if (headerParams.length === 0) {
6934
7183
  continue;
@@ -6986,7 +7235,8 @@ ${propsCode}
6986
7235
  generateQueryParamType(schema, param) {
6987
7236
  if (schema.$ref) {
6988
7237
  const refName = resolveRef(schema.$ref);
6989
- const schemaName = toCamelCase(refName, { prefix: this.options.prefix, suffix: this.options.suffix });
7238
+ const strippedRefName = stripPrefix(refName, this.options.stripSchemaPrefix);
7239
+ const schemaName = toCamelCase(strippedRefName, { prefix: this.options.prefix, suffix: this.options.suffix });
6990
7240
  return `${schemaName}Schema`;
6991
7241
  }
6992
7242
  if (schema.enum) {
@@ -7125,110 +7375,13 @@ ${propsCode}
7125
7375
  }
7126
7376
  };
7127
7377
 
7128
- // src/batch-executor.ts
7129
- async function processSpec(spec, index, total) {
7130
- console.log(`Processing [${index + 1}/${total}] ${spec.input}...`);
7131
- try {
7132
- const generator = new OpenApiGenerator(spec);
7133
- generator.generate();
7134
- console.log(`\u2713 Successfully generated ${spec.output}`);
7135
- return {
7136
- spec,
7137
- success: true
7138
- };
7139
- } catch (error) {
7140
- const errorMessage = error instanceof Error ? error.message : String(error);
7141
- console.error(`\u2717 Failed to generate ${spec.output}: ${errorMessage}`);
7142
- return {
7143
- spec,
7144
- success: false,
7145
- error: errorMessage
7146
- };
7147
- }
7148
- }
7149
- async function executeParallel(specs) {
7150
- console.log(`
7151
- Executing ${specs.length} spec(s) in parallel...
7152
- `);
7153
- const promises = specs.map((spec, index) => processSpec(spec, index, specs.length));
7154
- const results = await Promise.allSettled(promises);
7155
- return results.map((result, index) => {
7156
- if (result.status === "fulfilled") {
7157
- return result.value;
7158
- }
7159
- return {
7160
- spec: specs[index],
7161
- success: false,
7162
- error: result.reason instanceof Error ? result.reason.message : String(result.reason)
7163
- };
7164
- });
7165
- }
7166
- async function executeSequential(specs) {
7167
- console.log(`
7168
- Executing ${specs.length} spec(s) sequentially...
7169
- `);
7170
- const results = [];
7171
- for (let i = 0; i < specs.length; i++) {
7172
- const result = await processSpec(specs[i], i, specs.length);
7173
- results.push(result);
7174
- }
7175
- return results;
7176
- }
7177
- function printSummary(summary) {
7178
- console.log(`
7179
- ${"=".repeat(50)}`);
7180
- console.log("Batch Execution Summary");
7181
- console.log("=".repeat(50));
7182
- console.log(`Total specs: ${summary.total}`);
7183
- console.log(`Successful: ${summary.successful}`);
7184
- console.log(`Failed: ${summary.failed}`);
7185
- if (summary.failed > 0) {
7186
- console.log("\nFailed specs:");
7187
- for (const result of summary.results) {
7188
- if (!result.success) {
7189
- console.error(` \u2717 ${result.spec.input}`);
7190
- console.error(` Error: ${result.error}`);
7191
- }
7192
- }
7193
- }
7194
- console.log(`${"=".repeat(50)}
7195
- `);
7196
- }
7197
- async function executeBatch(specs, executionMode = "parallel") {
7198
- if (specs.length === 0) {
7199
- throw new ConfigurationError("No specs provided for batch execution", { specsCount: 0, executionMode });
7200
- }
7201
- let results = [];
7202
- try {
7203
- results = executionMode === "parallel" ? await executeParallel(specs) : await executeSequential(specs);
7204
- const summary = {
7205
- total: results.length,
7206
- successful: results.filter((r) => r.success).length,
7207
- failed: results.filter((r) => !r.success).length,
7208
- results
7209
- };
7210
- printSummary(summary);
7211
- return summary;
7212
- } finally {
7213
- if (results.length > 10) {
7214
- for (const result of results) {
7215
- if (result.spec) {
7216
- result.spec = null;
7217
- }
7218
- }
7219
- if (global.gc) {
7220
- global.gc();
7221
- }
7222
- }
7223
- }
7224
- }
7225
- function getBatchExitCode(summary) {
7226
- return summary.failed > 0 ? 1 : 0;
7227
- }
7228
-
7229
7378
  // src/utils/config-loader.ts
7230
7379
  init_cjs_shims();
7231
7380
  var import_cosmiconfig = require("cosmiconfig");
7381
+ var import_zod2 = require("zod");
7382
+
7383
+ // src/utils/config-schemas.ts
7384
+ init_cjs_shims();
7232
7385
  var import_zod = require("zod");
7233
7386
  var RequestResponseOptionsSchema = import_zod.z.strictObject({
7234
7387
  mode: import_zod.z.enum(["strict", "normal", "loose"]).optional(),
@@ -7246,38 +7399,37 @@ var OperationFiltersSchema = import_zod.z.strictObject({
7246
7399
  excludeOperationIds: import_zod.z.array(import_zod.z.string()).optional(),
7247
7400
  excludeDeprecated: import_zod.z.boolean().optional()
7248
7401
  });
7249
- var OpenApiGeneratorOptionsSchema = import_zod.z.strictObject({
7250
- mode: import_zod.z.enum(["strict", "normal", "loose"]).optional(),
7251
- input: import_zod.z.string(),
7252
- output: import_zod.z.string(),
7253
- includeDescriptions: import_zod.z.boolean().optional(),
7254
- useDescribe: import_zod.z.boolean().optional(),
7255
- schemaType: import_zod.z.enum(["all", "request", "response"]).optional(),
7256
- prefix: import_zod.z.string().optional(),
7257
- suffix: import_zod.z.string().optional(),
7258
- showStats: import_zod.z.boolean().optional(),
7259
- request: RequestResponseOptionsSchema.optional(),
7260
- response: RequestResponseOptionsSchema.optional(),
7261
- name: import_zod.z.string().optional(),
7262
- operationFilters: OperationFiltersSchema.optional()
7263
- });
7264
- var ConfigFileSchema = import_zod.z.strictObject({
7265
- defaults: import_zod.z.strictObject({
7266
- mode: import_zod.z.enum(["strict", "normal", "loose"]).optional(),
7267
- includeDescriptions: import_zod.z.boolean().optional(),
7268
- useDescribe: import_zod.z.boolean().optional(),
7269
- schemaType: import_zod.z.enum(["all", "request", "response"]).optional(),
7270
- prefix: import_zod.z.string().optional(),
7271
- suffix: import_zod.z.string().optional(),
7272
- showStats: import_zod.z.boolean().optional(),
7273
- request: RequestResponseOptionsSchema.optional(),
7274
- response: RequestResponseOptionsSchema.optional(),
7275
- operationFilters: OperationFiltersSchema.optional()
7276
- }).optional(),
7277
- specs: import_zod.z.array(OpenApiGeneratorOptionsSchema).min(1, "At least one spec is required"),
7278
- executionMode: import_zod.z.enum(["parallel", "sequential"]).optional()
7279
- });
7280
- var createTypeScriptLoader = () => {
7402
+
7403
+ // src/utils/config-validation.ts
7404
+ init_cjs_shims();
7405
+ function formatConfigValidationError(error, filepath, configPath, additionalNotes) {
7406
+ var _a;
7407
+ const formattedErrors = ((_a = error.issues) == null ? void 0 : _a.map((err) => {
7408
+ const path = err.path.length > 0 ? err.path.join(".") : "root";
7409
+ return ` - ${path}: ${err.message}`;
7410
+ }).join("\n")) || "Unknown validation error";
7411
+ const configSource = filepath || configPath || "config file";
7412
+ const lines = [
7413
+ `Invalid configuration file at: ${configSource}`,
7414
+ "",
7415
+ "Validation errors:",
7416
+ formattedErrors,
7417
+ "",
7418
+ "Please check your configuration file and ensure:",
7419
+ " - All required fields are present (specs array with input/output)",
7420
+ " - Field names are spelled correctly (no typos)",
7421
+ " - Values match the expected types (e.g., mode: 'strict' | 'normal' | 'loose')",
7422
+ " - No unknown/extra properties are included"
7423
+ ];
7424
+ if (additionalNotes && additionalNotes.length > 0) {
7425
+ lines.push(...additionalNotes.map((note) => ` - ${note}`));
7426
+ }
7427
+ return lines.join("\n");
7428
+ }
7429
+
7430
+ // src/utils/typescript-loader.ts
7431
+ init_cjs_shims();
7432
+ function createTypeScriptLoader() {
7281
7433
  return async (filepath) => {
7282
7434
  try {
7283
7435
  const esbuild = await import("esbuild");
@@ -7308,9 +7460,51 @@ var createTypeScriptLoader = () => {
7308
7460
  );
7309
7461
  }
7310
7462
  };
7311
- };
7463
+ }
7464
+
7465
+ // src/utils/config-loader.ts
7466
+ var OpenApiGeneratorOptionsSchema = import_zod2.z.strictObject({
7467
+ mode: import_zod2.z.enum(["strict", "normal", "loose"]).optional(),
7468
+ input: import_zod2.z.string(),
7469
+ output: import_zod2.z.string(),
7470
+ includeDescriptions: import_zod2.z.boolean().optional(),
7471
+ useDescribe: import_zod2.z.boolean().optional(),
7472
+ schemaType: import_zod2.z.enum(["all", "request", "response"]).optional(),
7473
+ prefix: import_zod2.z.string().optional(),
7474
+ suffix: import_zod2.z.string().optional(),
7475
+ stripSchemaPrefix: import_zod2.z.string().optional(),
7476
+ showStats: import_zod2.z.boolean().optional(),
7477
+ request: RequestResponseOptionsSchema.optional(),
7478
+ response: RequestResponseOptionsSchema.optional(),
7479
+ name: import_zod2.z.string().optional(),
7480
+ operationFilters: OperationFiltersSchema.optional(),
7481
+ cacheSize: import_zod2.z.number().positive().optional(),
7482
+ batchSize: import_zod2.z.number().positive().optional()
7483
+ });
7484
+ var ConfigFileSchema = import_zod2.z.strictObject({
7485
+ defaults: import_zod2.z.strictObject({
7486
+ mode: import_zod2.z.enum(["strict", "normal", "loose"]).optional(),
7487
+ includeDescriptions: import_zod2.z.boolean().optional(),
7488
+ useDescribe: import_zod2.z.boolean().optional(),
7489
+ schemaType: import_zod2.z.enum(["all", "request", "response"]).optional(),
7490
+ prefix: import_zod2.z.string().optional(),
7491
+ suffix: import_zod2.z.string().optional(),
7492
+ stripSchemaPrefix: import_zod2.z.string().optional(),
7493
+ showStats: import_zod2.z.boolean().optional(),
7494
+ request: RequestResponseOptionsSchema.optional(),
7495
+ response: RequestResponseOptionsSchema.optional(),
7496
+ operationFilters: OperationFiltersSchema.optional(),
7497
+ cacheSize: import_zod2.z.number().positive().optional(),
7498
+ batchSize: import_zod2.z.number().positive().optional()
7499
+ }).optional(),
7500
+ specs: import_zod2.z.array(OpenApiGeneratorOptionsSchema).min(1, {
7501
+ message: "Configuration must include at least one specification. Each specification should have 'input' and 'output' paths."
7502
+ }).refine((specs) => specs.every((spec) => spec.input && spec.output), {
7503
+ message: "Each specification must have both 'input' and 'output' paths defined"
7504
+ }),
7505
+ executionMode: import_zod2.z.enum(["parallel", "sequential"]).optional()
7506
+ });
7312
7507
  async function loadConfig(configPath) {
7313
- var _a;
7314
7508
  const explorer = (0, import_cosmiconfig.cosmiconfig)("openapi-to-zod", {
7315
7509
  searchPlaces: ["openapi-to-zod.config.ts", "openapi-to-zod.config.json", "package.json"],
7316
7510
  loaders: {
@@ -7325,31 +7519,15 @@ async function loadConfig(configPath) {
7325
7519
  }
7326
7520
  if (!result || !result.config) {
7327
7521
  throw new Error(
7328
- 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)"
7522
+ 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."
7329
7523
  );
7330
7524
  }
7331
7525
  try {
7332
7526
  const validatedConfig = ConfigFileSchema.parse(result.config);
7333
7527
  return validatedConfig;
7334
7528
  } catch (error) {
7335
- if (error instanceof import_zod.z.ZodError) {
7336
- const formattedErrors = ((_a = error.issues) == null ? void 0 : _a.map((err) => {
7337
- const path = err.path.length > 0 ? err.path.join(".") : "root";
7338
- return ` - ${path}: ${err.message}`;
7339
- }).join("\n")) || "Unknown validation error";
7340
- const configSource = result.filepath || configPath || "config file";
7341
- const errorMessage = [
7342
- `Invalid configuration file at: ${configSource}`,
7343
- "",
7344
- "Validation errors:",
7345
- formattedErrors,
7346
- "",
7347
- "Please check your configuration file and ensure:",
7348
- " - All required fields are present (specs array with input/output)",
7349
- " - Field names are spelled correctly (no typos)",
7350
- " - Values match the expected types (e.g., mode: 'strict' | 'normal' | 'loose')",
7351
- " - No unknown/extra properties are included"
7352
- ].join("\n");
7529
+ if (error instanceof import_zod2.z.ZodError) {
7530
+ const errorMessage = formatConfigValidationError(error, result.filepath, configPath);
7353
7531
  throw new Error(errorMessage);
7354
7532
  }
7355
7533
  throw error;
@@ -7384,17 +7562,13 @@ program.name("openapi-to-zod").description("Generate Zod v4 schemas from OpenAPI
7384
7562
  `
7385
7563
  Examples:
7386
7564
  # Create a new config file
7387
- $ openapi-to-zod --init
7565
+ $ openapi-to-zod init
7388
7566
 
7389
7567
  # Generate with auto-discovered config
7390
7568
  $ openapi-to-zod
7391
7569
 
7392
7570
  # Generate with custom config path
7393
7571
  $ openapi-to-zod --config custom.config.ts
7394
-
7395
- Breaking Changes (v2.0):
7396
- CLI options removed. Use configuration file instead.
7397
- Run 'openapi-to-zod --init' to create a config file.
7398
7572
  `
7399
7573
  ).action(async (options) => {
7400
7574
  try {
@@ -7451,17 +7625,12 @@ function findSpecFiles() {
7451
7625
  return { files, totalCount };
7452
7626
  }
7453
7627
  async function executeConfigMode(options) {
7454
- let config;
7455
- try {
7456
- config = await loadConfig(options.config);
7457
- } catch {
7458
- throw new CliOptionsError("No config file found. Run 'openapi-to-zod --init' to create one.", {
7459
- configPath: options.config
7460
- });
7461
- }
7628
+ var _a, _b;
7629
+ const config = await loadConfig(options.config);
7462
7630
  const specs = mergeConfigWithDefaults(config);
7463
7631
  const executionMode = config.executionMode || "parallel";
7464
- const summary = await executeBatch(specs, executionMode);
7632
+ const batchSize = (_b = (_a = specs[0]) == null ? void 0 : _a.batchSize) != null ? _b : 10;
7633
+ const summary = await executeBatch(specs, executionMode, (spec) => new OpenApiGenerator(spec), batchSize);
7465
7634
  const exitCode = getBatchExitCode(summary);
7466
7635
  if (exitCode !== 0) {
7467
7636
  process.exit(exitCode);
@@ -7585,7 +7754,7 @@ export default defineConfig({
7585
7754
  mode: 'strict',
7586
7755
  includeDescriptions: true,
7587
7756
  useDescribe: false,
7588
- showStats: false,
7757
+ showStats: true,
7589
7758
  schemaType: 'all',
7590
7759
  },
7591
7760
  specs: [