@cerios/openapi-to-zod 0.3.0 → 0.4.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.mjs CHANGED
@@ -6291,13 +6291,13 @@ var init_property_generator = __esm({
6291
6291
  }
6292
6292
  });
6293
6293
 
6294
- // src/generator.ts
6294
+ // src/openapi-generator.ts
6295
6295
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
6296
6296
  import { dirname, normalize } from "path";
6297
6297
  import { parse } from "yaml";
6298
- var ZodSchemaGenerator;
6299
- var init_generator = __esm({
6300
- "src/generator.ts"() {
6298
+ var OpenApiGenerator;
6299
+ var init_openapi_generator = __esm({
6300
+ "src/openapi-generator.ts"() {
6301
6301
  "use strict";
6302
6302
  init_esm_shims();
6303
6303
  init_errors();
@@ -6305,7 +6305,7 @@ var init_generator = __esm({
6305
6305
  init_jsdoc_generator();
6306
6306
  init_property_generator();
6307
6307
  init_name_utils();
6308
- ZodSchemaGenerator = class {
6308
+ OpenApiGenerator = class {
6309
6309
  constructor(options) {
6310
6310
  this.schemas = /* @__PURE__ */ new Map();
6311
6311
  this.types = /* @__PURE__ */ new Map();
@@ -6345,19 +6345,41 @@ var init_generator = __esm({
6345
6345
  }
6346
6346
  }
6347
6347
  try {
6348
- const yamlContent = readFileSync(this.options.input, "utf-8");
6349
- this.spec = parse(yamlContent);
6348
+ const content = readFileSync(this.options.input, "utf-8");
6349
+ try {
6350
+ this.spec = parse(content);
6351
+ } catch (yamlError) {
6352
+ try {
6353
+ this.spec = JSON.parse(content);
6354
+ } catch {
6355
+ if (yamlError instanceof Error) {
6356
+ const errorMessage = [
6357
+ `Failed to parse OpenAPI specification from: ${this.options.input}`,
6358
+ "",
6359
+ `Error: ${yamlError.message}`,
6360
+ "",
6361
+ "Please ensure:",
6362
+ " - The file exists and is readable",
6363
+ " - The file contains valid YAML or JSON syntax",
6364
+ " - The file is a valid OpenAPI 3.x specification"
6365
+ ].join("\n");
6366
+ throw new SpecValidationError(errorMessage, {
6367
+ filePath: this.options.input,
6368
+ originalError: yamlError.message
6369
+ });
6370
+ }
6371
+ throw yamlError;
6372
+ }
6373
+ }
6350
6374
  } catch (error) {
6375
+ if (error instanceof SpecValidationError) {
6376
+ throw error;
6377
+ }
6351
6378
  if (error instanceof Error) {
6352
6379
  const errorMessage = [
6353
- `Failed to parse OpenAPI specification from: ${this.options.input}`,
6354
- "",
6355
- `Error: ${error.message}`,
6380
+ `Failed to read OpenAPI specification from: ${this.options.input}`,
6356
6381
  "",
6357
- "Please ensure:",
6358
- " - The file exists and is readable",
6359
- " - The file contains valid YAML syntax",
6360
- " - The file is a valid OpenAPI 3.x specification"
6382
+ `Error: ${error.message}`
6361
6383
  ].join("\n");
6362
6384
  throw new SpecValidationError(errorMessage, { filePath: this.options.input, originalError: error.message });
6363
6385
  }
@@ -7221,7 +7243,7 @@ ${props.join("\n")}
7221
7243
  async function processSpec(spec, index, total) {
7222
7244
  console.log(`Processing [${index + 1}/${total}] ${spec.input}...`);
7223
7245
  try {
7224
- const generator = new ZodSchemaGenerator(spec);
7246
+ const generator = new OpenApiGenerator(spec);
7225
7247
  generator.generate();
7226
7248
  console.log(`\u2713 Successfully generated ${spec.output}`);
7227
7249
  return {
@@ -7322,7 +7344,7 @@ var init_batch_executor = __esm({
7322
7344
  "use strict";
7323
7345
  init_esm_shims();
7324
7346
  init_errors();
7325
- init_generator();
7347
+ init_openapi_generator();
7326
7348
  }
7327
7349
  });
7328
7350
 
@@ -7397,7 +7419,7 @@ function mergeConfigWithDefaults(config) {
7397
7419
  return merged;
7398
7420
  });
7399
7421
  }
7400
- var TypeModeSchema, NativeEnumTypeSchema, RequestResponseOptionsSchema, GeneratorOptionsSchema, ConfigFileSchema, createTypeScriptLoader;
7422
+ var TypeModeSchema, NativeEnumTypeSchema, RequestResponseOptionsSchema, OpenApiGeneratorOptionsSchema, ConfigFileSchema, createTypeScriptLoader;
7401
7423
  var init_config_loader = __esm({
7402
7424
  "src/utils/config-loader.ts"() {
7403
7425
  "use strict";
@@ -7412,7 +7434,7 @@ var init_config_loader = __esm({
7412
7434
  typeMode: TypeModeSchema.optional(),
7413
7435
  nativeEnumType: NativeEnumTypeSchema.optional()
7414
7436
  });
7415
- GeneratorOptionsSchema = z.strictObject({
7437
+ OpenApiGeneratorOptionsSchema = z.strictObject({
7416
7438
  mode: z.enum(["strict", "normal", "loose"]).optional(),
7417
7439
  input: z.string(),
7418
7440
  output: z.string(),
@@ -7442,7 +7464,7 @@ var init_config_loader = __esm({
7442
7464
  request: RequestResponseOptionsSchema.optional(),
7443
7465
  response: RequestResponseOptionsSchema.optional()
7444
7466
  }).optional(),
7445
- specs: z.array(GeneratorOptionsSchema).min(1, "At least one spec is required"),
7467
+ specs: z.array(OpenApiGeneratorOptionsSchema).min(1, "At least one spec is required"),
7446
7468
  executionMode: z.enum(["parallel", "sequential"]).optional()
7447
7469
  });
7448
7470
  createTypeScriptLoader = () => {
@@ -7481,7 +7503,8 @@ var init_config_loader = __esm({
7481
7503
  });
7482
7504
 
7483
7505
  // src/cli.ts
7484
- import { existsSync as existsSync2, writeFileSync as writeFileSync2 } from "fs";
7506
+ import { existsSync as existsSync2, readdirSync, statSync, writeFileSync as writeFileSync2 } from "fs";
7507
+ import { join } from "path";
7485
7508
  import { Command } from "commander";
7486
7509
  var require_cli = __commonJS({
7487
7510
  "src/cli.ts"() {
@@ -7532,6 +7555,36 @@ Breaking Changes (v2.0):
7532
7555
  }
7533
7556
  });
7534
7557
  program.parse();
7558
+ function findSpecFiles() {
7559
+ const specFolders = ["spec", "specs"];
7560
+ const validExtensions = [".yaml", ".yml", ".json"];
7561
+ const excludePatterns = ["node_modules", ".git", "dist", "build", "coverage"];
7562
+ const allFiles = [];
7563
+ for (const folder of specFolders) {
7564
+ if (!existsSync2(folder)) continue;
7565
+ try {
7566
+ const entries = readdirSync(folder, { recursive: true, encoding: "utf-8" });
7567
+ for (const entry of entries) {
7568
+ const fullPath = join(folder, entry);
7569
+ if (excludePatterns.some((pattern) => fullPath.includes(pattern))) continue;
7570
+ try {
7571
+ const stats = statSync(fullPath);
7572
+ if (!stats.isFile()) continue;
7573
+ const hasValidExt = validExtensions.some((ext) => fullPath.endsWith(ext));
7574
+ if (!hasValidExt) continue;
7575
+ const sizeKB = (stats.size / 1024).toFixed(2);
7576
+ allFiles.push({ path: fullPath.replace(/\\/g, "/"), size: `${sizeKB} KB` });
7577
+ } catch {
7578
+ }
7579
+ }
7580
+ } catch {
7581
+ }
7582
+ }
7583
+ allFiles.sort((a, b) => a.path.localeCompare(b.path));
7584
+ const totalCount = allFiles.length;
7585
+ const files = allFiles.slice(0, 20);
7586
+ return { files, totalCount };
7587
+ }
7535
7588
  async function executeConfigMode(options) {
7536
7589
  let config;
7537
7590
  try {
@@ -7565,14 +7618,66 @@ Breaking Changes (v2.0):
7565
7618
  return;
7566
7619
  }
7567
7620
  }
7568
- const response = await (0, import_prompts.default)([
7569
- {
7621
+ const { files, totalCount } = findSpecFiles();
7622
+ if (totalCount > 20) {
7623
+ console.log(`Showing first 20 of ${totalCount} files found. Use manual entry to specify others.
7624
+ `);
7625
+ }
7626
+ let inputPath;
7627
+ if (files.length > 0) {
7628
+ const choices = [
7629
+ ...files.map((f) => ({ title: `${f.path} (${f.size})`, value: f.path })),
7630
+ { title: "\u2192 Enter manually...", value: "__MANUAL__" }
7631
+ ];
7632
+ const inputResponse = await (0, import_prompts.default)({
7633
+ type: "select",
7634
+ name: "input",
7635
+ message: "Select OpenAPI spec file (YAML or JSON):",
7636
+ choices
7637
+ });
7638
+ if (!inputResponse.input) {
7639
+ console.log("\nInitialization cancelled.");
7640
+ return;
7641
+ }
7642
+ if (inputResponse.input === "__MANUAL__") {
7643
+ const manualResponse = await (0, import_prompts.default)({
7644
+ type: "text",
7645
+ name: "input",
7646
+ message: "Input OpenAPI file path (YAML or JSON):",
7647
+ initial: "openapi.{yaml,yml,json}",
7648
+ validate: (value) => {
7649
+ if (value.length === 0) return "Input path is required";
7650
+ if (!existsSync2(value)) return "\u26A0\uFE0F File does not exist. Continue anyway?";
7651
+ return true;
7652
+ }
7653
+ });
7654
+ if (!manualResponse.input) {
7655
+ console.log("\nInitialization cancelled.");
7656
+ return;
7657
+ }
7658
+ inputPath = manualResponse.input;
7659
+ } else {
7660
+ inputPath = inputResponse.input;
7661
+ }
7662
+ } else {
7663
+ const manualResponse = await (0, import_prompts.default)({
7570
7664
  type: "text",
7571
7665
  name: "input",
7572
- message: "Input OpenAPI file path:",
7573
- initial: "openapi.yaml",
7574
- validate: (value) => value.length > 0 || "Input path is required"
7575
- },
7666
+ message: "Input OpenAPI file path (YAML or JSON):",
7667
+ initial: "openapi.{yaml,yml,json}",
7668
+ validate: (value) => {
7669
+ if (value.length === 0) return "Input path is required";
7670
+ if (!existsSync2(value)) return "\u26A0\uFE0F File does not exist. Continue anyway?";
7671
+ return true;
7672
+ }
7673
+ });
7674
+ if (!manualResponse.input) {
7675
+ console.log("\nInitialization cancelled.");
7676
+ return;
7677
+ }
7678
+ inputPath = manualResponse.input;
7679
+ }
7680
+ const response = await (0, import_prompts.default)([
7576
7681
  {
7577
7682
  type: "text",
7578
7683
  name: "output",
@@ -7597,11 +7702,12 @@ Breaking Changes (v2.0):
7597
7702
  initial: true
7598
7703
  }
7599
7704
  ]);
7600
- if (!response.input || !response.output || !response.format) {
7705
+ if (!response.output || !response.format) {
7601
7706
  console.log("\nInitialization cancelled.");
7602
7707
  return;
7603
7708
  }
7604
- const { input, output, format, includeDefaults } = response;
7709
+ const { output, format, includeDefaults } = response;
7710
+ const input = inputPath;
7605
7711
  let configContent;
7606
7712
  let configFilename;
7607
7713
  if (format === "ts") {