@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/README.md +2 -2
- package/dist/cli.js +129 -23
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +134 -28
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +36 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +35 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -834,14 +834,14 @@ All errors include:
|
|
|
834
834
|
|
|
835
835
|
## API Reference
|
|
836
836
|
|
|
837
|
-
### `generateZodSchemas(options:
|
|
837
|
+
### `generateZodSchemas(options: OpenApiGeneratorOptions): void`
|
|
838
838
|
|
|
839
839
|
Main function to generate schemas.
|
|
840
840
|
|
|
841
841
|
#### Options
|
|
842
842
|
|
|
843
843
|
```typescript
|
|
844
|
-
interface
|
|
844
|
+
interface OpenApiGeneratorOptions {
|
|
845
845
|
/**
|
|
846
846
|
* Object validation mode
|
|
847
847
|
* - 'strict': Uses z.strictObject() - no additional properties allowed
|
package/dist/cli.js
CHANGED
|
@@ -4961,6 +4961,7 @@ var require_prompts3 = __commonJS({
|
|
|
4961
4961
|
// src/cli.ts
|
|
4962
4962
|
init_cjs_shims();
|
|
4963
4963
|
var import_node_fs2 = require("fs");
|
|
4964
|
+
var import_node_path2 = require("path");
|
|
4964
4965
|
var import_commander = require("commander");
|
|
4965
4966
|
var import_prompts = __toESM(require_prompts3());
|
|
4966
4967
|
|
|
@@ -5012,7 +5013,7 @@ var ConfigurationError = class extends GeneratorError {
|
|
|
5012
5013
|
}
|
|
5013
5014
|
};
|
|
5014
5015
|
|
|
5015
|
-
// src/generator.ts
|
|
5016
|
+
// src/openapi-generator.ts
|
|
5016
5017
|
init_cjs_shims();
|
|
5017
5018
|
var import_node_fs = require("fs");
|
|
5018
5019
|
var import_node_path = require("path");
|
|
@@ -6221,8 +6222,8 @@ _PropertyGenerator.INCLUSION_RULES = {
|
|
|
6221
6222
|
};
|
|
6222
6223
|
var PropertyGenerator = _PropertyGenerator;
|
|
6223
6224
|
|
|
6224
|
-
// src/generator.ts
|
|
6225
|
-
var
|
|
6225
|
+
// src/openapi-generator.ts
|
|
6226
|
+
var OpenApiGenerator = class {
|
|
6226
6227
|
constructor(options) {
|
|
6227
6228
|
this.schemas = /* @__PURE__ */ new Map();
|
|
6228
6229
|
this.types = /* @__PURE__ */ new Map();
|
|
@@ -6262,19 +6263,41 @@ var ZodSchemaGenerator = class {
|
|
|
6262
6263
|
}
|
|
6263
6264
|
}
|
|
6264
6265
|
try {
|
|
6265
|
-
const
|
|
6266
|
-
|
|
6266
|
+
const content = (0, import_node_fs.readFileSync)(this.options.input, "utf-8");
|
|
6267
|
+
try {
|
|
6268
|
+
this.spec = (0, import_yaml.parse)(content);
|
|
6269
|
+
} catch (yamlError) {
|
|
6270
|
+
try {
|
|
6271
|
+
this.spec = JSON.parse(content);
|
|
6272
|
+
} catch {
|
|
6273
|
+
if (yamlError instanceof Error) {
|
|
6274
|
+
const errorMessage = [
|
|
6275
|
+
`Failed to parse OpenAPI specification from: ${this.options.input}`,
|
|
6276
|
+
"",
|
|
6277
|
+
`Error: ${yamlError.message}`,
|
|
6278
|
+
"",
|
|
6279
|
+
"Please ensure:",
|
|
6280
|
+
" - The file exists and is readable",
|
|
6281
|
+
" - The file contains valid YAML or JSON syntax",
|
|
6282
|
+
" - The file is a valid OpenAPI 3.x specification"
|
|
6283
|
+
].join("\n");
|
|
6284
|
+
throw new SpecValidationError(errorMessage, {
|
|
6285
|
+
filePath: this.options.input,
|
|
6286
|
+
originalError: yamlError.message
|
|
6287
|
+
});
|
|
6288
|
+
}
|
|
6289
|
+
throw yamlError;
|
|
6290
|
+
}
|
|
6291
|
+
}
|
|
6267
6292
|
} catch (error) {
|
|
6293
|
+
if (error instanceof SpecValidationError) {
|
|
6294
|
+
throw error;
|
|
6295
|
+
}
|
|
6268
6296
|
if (error instanceof Error) {
|
|
6269
6297
|
const errorMessage = [
|
|
6270
|
-
`Failed to
|
|
6271
|
-
"",
|
|
6272
|
-
`Error: ${error.message}`,
|
|
6298
|
+
`Failed to read OpenAPI specification from: ${this.options.input}`,
|
|
6273
6299
|
"",
|
|
6274
|
-
|
|
6275
|
-
" - The file exists and is readable",
|
|
6276
|
-
" - The file contains valid YAML syntax",
|
|
6277
|
-
" - The file is a valid OpenAPI 3.x specification"
|
|
6300
|
+
`Error: ${error.message}`
|
|
6278
6301
|
].join("\n");
|
|
6279
6302
|
throw new SpecValidationError(errorMessage, { filePath: this.options.input, originalError: error.message });
|
|
6280
6303
|
}
|
|
@@ -7136,7 +7159,7 @@ ${props.join("\n")}
|
|
|
7136
7159
|
async function processSpec(spec, index, total) {
|
|
7137
7160
|
console.log(`Processing [${index + 1}/${total}] ${spec.input}...`);
|
|
7138
7161
|
try {
|
|
7139
|
-
const generator = new
|
|
7162
|
+
const generator = new OpenApiGenerator(spec);
|
|
7140
7163
|
generator.generate();
|
|
7141
7164
|
console.log(`\u2713 Successfully generated ${spec.output}`);
|
|
7142
7165
|
return {
|
|
@@ -7247,7 +7270,7 @@ var RequestResponseOptionsSchema = import_zod.z.strictObject({
|
|
|
7247
7270
|
typeMode: TypeModeSchema.optional(),
|
|
7248
7271
|
nativeEnumType: NativeEnumTypeSchema.optional()
|
|
7249
7272
|
});
|
|
7250
|
-
var
|
|
7273
|
+
var OpenApiGeneratorOptionsSchema = import_zod.z.strictObject({
|
|
7251
7274
|
mode: import_zod.z.enum(["strict", "normal", "loose"]).optional(),
|
|
7252
7275
|
input: import_zod.z.string(),
|
|
7253
7276
|
output: import_zod.z.string(),
|
|
@@ -7277,7 +7300,7 @@ var ConfigFileSchema = import_zod.z.strictObject({
|
|
|
7277
7300
|
request: RequestResponseOptionsSchema.optional(),
|
|
7278
7301
|
response: RequestResponseOptionsSchema.optional()
|
|
7279
7302
|
}).optional(),
|
|
7280
|
-
specs: import_zod.z.array(
|
|
7303
|
+
specs: import_zod.z.array(OpenApiGeneratorOptionsSchema).min(1, "At least one spec is required"),
|
|
7281
7304
|
executionMode: import_zod.z.enum(["parallel", "sequential"]).optional()
|
|
7282
7305
|
});
|
|
7283
7306
|
var createTypeScriptLoader = () => {
|
|
@@ -7424,6 +7447,36 @@ program.command("init").description("Initialize a new openapi-to-zod configurati
|
|
|
7424
7447
|
}
|
|
7425
7448
|
});
|
|
7426
7449
|
program.parse();
|
|
7450
|
+
function findSpecFiles() {
|
|
7451
|
+
const specFolders = ["spec", "specs"];
|
|
7452
|
+
const validExtensions = [".yaml", ".yml", ".json"];
|
|
7453
|
+
const excludePatterns = ["node_modules", ".git", "dist", "build", "coverage"];
|
|
7454
|
+
const allFiles = [];
|
|
7455
|
+
for (const folder of specFolders) {
|
|
7456
|
+
if (!(0, import_node_fs2.existsSync)(folder)) continue;
|
|
7457
|
+
try {
|
|
7458
|
+
const entries = (0, import_node_fs2.readdirSync)(folder, { recursive: true, encoding: "utf-8" });
|
|
7459
|
+
for (const entry of entries) {
|
|
7460
|
+
const fullPath = (0, import_node_path2.join)(folder, entry);
|
|
7461
|
+
if (excludePatterns.some((pattern) => fullPath.includes(pattern))) continue;
|
|
7462
|
+
try {
|
|
7463
|
+
const stats = (0, import_node_fs2.statSync)(fullPath);
|
|
7464
|
+
if (!stats.isFile()) continue;
|
|
7465
|
+
const hasValidExt = validExtensions.some((ext) => fullPath.endsWith(ext));
|
|
7466
|
+
if (!hasValidExt) continue;
|
|
7467
|
+
const sizeKB = (stats.size / 1024).toFixed(2);
|
|
7468
|
+
allFiles.push({ path: fullPath.replace(/\\/g, "/"), size: `${sizeKB} KB` });
|
|
7469
|
+
} catch {
|
|
7470
|
+
}
|
|
7471
|
+
}
|
|
7472
|
+
} catch {
|
|
7473
|
+
}
|
|
7474
|
+
}
|
|
7475
|
+
allFiles.sort((a, b) => a.path.localeCompare(b.path));
|
|
7476
|
+
const totalCount = allFiles.length;
|
|
7477
|
+
const files = allFiles.slice(0, 20);
|
|
7478
|
+
return { files, totalCount };
|
|
7479
|
+
}
|
|
7427
7480
|
async function executeConfigMode(options) {
|
|
7428
7481
|
let config;
|
|
7429
7482
|
try {
|
|
@@ -7457,14 +7510,66 @@ async function initConfigFile() {
|
|
|
7457
7510
|
return;
|
|
7458
7511
|
}
|
|
7459
7512
|
}
|
|
7460
|
-
const
|
|
7461
|
-
|
|
7513
|
+
const { files, totalCount } = findSpecFiles();
|
|
7514
|
+
if (totalCount > 20) {
|
|
7515
|
+
console.log(`Showing first 20 of ${totalCount} files found. Use manual entry to specify others.
|
|
7516
|
+
`);
|
|
7517
|
+
}
|
|
7518
|
+
let inputPath;
|
|
7519
|
+
if (files.length > 0) {
|
|
7520
|
+
const choices = [
|
|
7521
|
+
...files.map((f) => ({ title: `${f.path} (${f.size})`, value: f.path })),
|
|
7522
|
+
{ title: "\u2192 Enter manually...", value: "__MANUAL__" }
|
|
7523
|
+
];
|
|
7524
|
+
const inputResponse = await (0, import_prompts.default)({
|
|
7525
|
+
type: "select",
|
|
7526
|
+
name: "input",
|
|
7527
|
+
message: "Select OpenAPI spec file (YAML or JSON):",
|
|
7528
|
+
choices
|
|
7529
|
+
});
|
|
7530
|
+
if (!inputResponse.input) {
|
|
7531
|
+
console.log("\nInitialization cancelled.");
|
|
7532
|
+
return;
|
|
7533
|
+
}
|
|
7534
|
+
if (inputResponse.input === "__MANUAL__") {
|
|
7535
|
+
const manualResponse = await (0, import_prompts.default)({
|
|
7536
|
+
type: "text",
|
|
7537
|
+
name: "input",
|
|
7538
|
+
message: "Input OpenAPI file path (YAML or JSON):",
|
|
7539
|
+
initial: "openapi.{yaml,yml,json}",
|
|
7540
|
+
validate: (value) => {
|
|
7541
|
+
if (value.length === 0) return "Input path is required";
|
|
7542
|
+
if (!(0, import_node_fs2.existsSync)(value)) return "\u26A0\uFE0F File does not exist. Continue anyway?";
|
|
7543
|
+
return true;
|
|
7544
|
+
}
|
|
7545
|
+
});
|
|
7546
|
+
if (!manualResponse.input) {
|
|
7547
|
+
console.log("\nInitialization cancelled.");
|
|
7548
|
+
return;
|
|
7549
|
+
}
|
|
7550
|
+
inputPath = manualResponse.input;
|
|
7551
|
+
} else {
|
|
7552
|
+
inputPath = inputResponse.input;
|
|
7553
|
+
}
|
|
7554
|
+
} else {
|
|
7555
|
+
const manualResponse = await (0, import_prompts.default)({
|
|
7462
7556
|
type: "text",
|
|
7463
7557
|
name: "input",
|
|
7464
|
-
message: "Input OpenAPI file path:",
|
|
7465
|
-
initial: "openapi.yaml",
|
|
7466
|
-
validate: (value) =>
|
|
7467
|
-
|
|
7558
|
+
message: "Input OpenAPI file path (YAML or JSON):",
|
|
7559
|
+
initial: "openapi.{yaml,yml,json}",
|
|
7560
|
+
validate: (value) => {
|
|
7561
|
+
if (value.length === 0) return "Input path is required";
|
|
7562
|
+
if (!(0, import_node_fs2.existsSync)(value)) return "\u26A0\uFE0F File does not exist. Continue anyway?";
|
|
7563
|
+
return true;
|
|
7564
|
+
}
|
|
7565
|
+
});
|
|
7566
|
+
if (!manualResponse.input) {
|
|
7567
|
+
console.log("\nInitialization cancelled.");
|
|
7568
|
+
return;
|
|
7569
|
+
}
|
|
7570
|
+
inputPath = manualResponse.input;
|
|
7571
|
+
}
|
|
7572
|
+
const response = await (0, import_prompts.default)([
|
|
7468
7573
|
{
|
|
7469
7574
|
type: "text",
|
|
7470
7575
|
name: "output",
|
|
@@ -7489,11 +7594,12 @@ async function initConfigFile() {
|
|
|
7489
7594
|
initial: true
|
|
7490
7595
|
}
|
|
7491
7596
|
]);
|
|
7492
|
-
if (!response.
|
|
7597
|
+
if (!response.output || !response.format) {
|
|
7493
7598
|
console.log("\nInitialization cancelled.");
|
|
7494
7599
|
return;
|
|
7495
7600
|
}
|
|
7496
|
-
const {
|
|
7601
|
+
const { output, format, includeDefaults } = response;
|
|
7602
|
+
const input = inputPath;
|
|
7497
7603
|
let configContent;
|
|
7498
7604
|
let configFilename;
|
|
7499
7605
|
if (format === "ts") {
|