json-schema-to-zod
Advanced tools
Comparing version 2.0.4 to 2.0.5
@@ -8,56 +8,52 @@ "use strict"; | ||
if (help) { | ||
const defaults = { | ||
name: "help", | ||
short: "h", | ||
description: "Display this message :)", | ||
}; | ||
const param = help === true | ||
? defaults | ||
: { | ||
...defaults, | ||
...help, | ||
}; | ||
let index = args.indexOf("--" + param.name); | ||
let index = args.indexOf("--help"); | ||
if (index === -1) { | ||
index = args.indexOf("-" + param.short); | ||
index = args.indexOf("-h"); | ||
} | ||
if (index !== -1) { | ||
printParams([...params, param]); | ||
printParams({ | ||
...params, | ||
help: { | ||
shorthand: "h", | ||
description: typeof help === "string" ? help : "Display this message :)", | ||
}, | ||
}); | ||
process.exit(0); | ||
} | ||
} | ||
for (const param of params) { | ||
let index = args.indexOf("--" + param.name); | ||
if (index === -1) { | ||
index = args.indexOf("-" + param.short); | ||
for (const name in params) { | ||
const { shorthand, required, value } = params[name]; | ||
let index = args.indexOf("--" + name); | ||
if (index === -1 && shorthand) { | ||
index = args.indexOf("-" + shorthand); | ||
} | ||
if (index === -1) { | ||
if (param.required) { | ||
throw new Error(typeof param.required === "string" | ||
? param.required | ||
: `Missing required argument ${param.name}`); | ||
if (required !== false) { | ||
throw new Error(typeof required === "string" && required !== "" | ||
? required | ||
: `Missing required argument ${name}`); | ||
} | ||
result[param.name] = false; | ||
result[name] = false; | ||
continue; | ||
} | ||
if (param.value) { | ||
if (value) { | ||
const value = args[index + 1]; | ||
if (value === undefined) { | ||
throw new Error(`Expected a value for argument ${param.name}`); | ||
throw new Error(`Expected a value for argument ${name}`); | ||
} | ||
if (param.value === "number") { | ||
if (value === "number") { | ||
const asNumber = Number(value); | ||
if (isNaN(asNumber)) { | ||
throw new Error(`Value of argument ${param.name} must be a valid number`); | ||
throw new Error(`Value of argument ${name} must be a valid number`); | ||
} | ||
result[param.name] = asNumber; | ||
result[name] = asNumber; | ||
continue; | ||
} | ||
if (Array.isArray(param.value) && !param.value.includes(value)) { | ||
throw new Error(`Value of argument ${param.name} must be one of ${param.value}`); | ||
if (Array.isArray(value) && !value.includes(value)) { | ||
throw new Error(`Value of argument ${name} must be one of ${value}`); | ||
} | ||
result[param.name] = value; | ||
result[name] = value; | ||
} | ||
else { | ||
result[param.name] = true; | ||
result[name] = true; | ||
} | ||
@@ -93,15 +89,16 @@ } | ||
function printParams(params) { | ||
const longest = params.reduce((n, p) => (p.name.length > n ? p.name.length : n), 5); | ||
const longest = Object.keys(params).reduce((l, c) => (c.length > l ? c.length : l), 5); | ||
const header = "Name " + " ".repeat(longest - 2) + "Short Description"; | ||
console.log(header); | ||
for (const param of params) { | ||
for (const name in params) { | ||
const { shorthand, description } = params[name]; | ||
console.log("--" + | ||
param.name + | ||
" ".repeat(longest - param.name.length) + | ||
name + | ||
" ".repeat(longest - name.length) + | ||
" -" + | ||
param.short + | ||
shorthand + | ||
" " + | ||
param.description ?? ""); | ||
description ?? ""); | ||
} | ||
} | ||
exports.printParams = printParams; |
@@ -8,45 +8,37 @@ #!/usr/bin/env node | ||
const args_js_1 = require("./args.js"); | ||
const params = [ | ||
{ | ||
name: "input", | ||
short: "i", | ||
const pick_js_1 = require("./utils/pick.js"); | ||
const params = { | ||
input: { | ||
shorthand: "i", | ||
value: "string", | ||
required: process.stdin.isTTY && | ||
"input is required when no JSON or file path is piped", | ||
description: "JSON or a source file path", | ||
description: "JSON or a source file path. Required if no data is piped.", | ||
}, | ||
{ | ||
name: "output", | ||
short: "o", | ||
output: { | ||
shorthand: "o", | ||
value: "string", | ||
description: "A file path to write to. If not supplied output will be stdout", | ||
description: "A file path to write to. If not supplied stdout will be used.", | ||
}, | ||
{ | ||
name: "name", | ||
short: "n", | ||
name: { | ||
shorthand: "n", | ||
value: "string", | ||
description: "The name of the schema in the output", | ||
description: "The name of the schema in the output.", | ||
}, | ||
{ | ||
name: "depth", | ||
short: "d", | ||
depth: { | ||
shorthand: "d", | ||
value: "number", | ||
description: "Maximum depth of recursion before falling back to z.any() - defaults to 0", | ||
description: "Maximum depth of recursion before falling back to z.any(). Defaults to 0.", | ||
}, | ||
{ | ||
name: "module", | ||
short: "m", | ||
value: ["esm", "cjs"], | ||
description: "Force module syntax ('esm' or 'cjs')", | ||
module: { | ||
shorthand: "m", | ||
value: ["esm", "cjs", "none"], | ||
description: "Module syntax; 'esm', 'cjs' or 'none'. Defaults to 'esm'.", | ||
}, | ||
]; | ||
}; | ||
async function main() { | ||
const args = (0, args_js_1.parseArgs)(params, process.argv, {}); | ||
const args = (0, args_js_1.parseArgs)(params, process.argv, true); | ||
const input = args.input || (await (0, args_js_1.readPipe)()); | ||
const jsonSchema = (0, args_js_1.parseOrReadJSON)(input); | ||
const zodSchema = (0, jsonSchemaToZod_js_1.jsonSchemaToZod)(jsonSchema, { | ||
module: args.module, | ||
name: args.name, | ||
recursionDepth: args["recursion-depth"], | ||
}); | ||
const zodSchema = (0, jsonSchemaToZod_js_1.jsonSchemaToZod)(jsonSchema, (0, pick_js_1.pick)(args, "name", "depth", "module")); | ||
if (args.output) { | ||
@@ -53,0 +45,0 @@ (0, fs_1.mkdirSync)((0, path_1.dirname)(args.output), { recursive: true }); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.parseSchema = exports.jsonSchemaToZod = void 0; | ||
const jsonSchemaToZod_js_1 = require("./jsonSchemaToZod.js"); | ||
Object.defineProperty(exports, "jsonSchemaToZod", { enumerable: true, get: function () { return jsonSchemaToZod_js_1.jsonSchemaToZod; } }); | ||
const parseSchema_js_1 = require("./parsers/parseSchema.js"); | ||
Object.defineProperty(exports, "parseSchema", { enumerable: true, get: function () { return parseSchema_js_1.parseSchema; } }); | ||
exports.default = jsonSchemaToZod_js_1.jsonSchemaToZod; |
@@ -5,3 +5,3 @@ "use strict"; | ||
const parseSchema_js_1 = require("./parsers/parseSchema.js"); | ||
const jsonSchemaToZod = (schema, { module = true, name, ...rest } = {}) => { | ||
const jsonSchemaToZod = (schema, { module, name, ...rest } = {}) => { | ||
let result = (0, parseSchema_js_1.parseSchema)(schema, { | ||
@@ -14,18 +14,16 @@ module, | ||
}); | ||
if (module) { | ||
if (module === "cjs") { | ||
result = `const { z } = require("zod") | ||
if (module === "cjs") { | ||
result = `const { z } = require("zod") | ||
module.exports = ${name ? `{ ${JSON.stringify(name)}: ${result} }` : result} | ||
`; | ||
} | ||
else { | ||
result = `import { z } from "zod" | ||
} | ||
else if (module === "esm") { | ||
result = `import { z } from "zod" | ||
export ${name ? `const ${name} =` : `default`} ${result} | ||
`; | ||
} | ||
} | ||
else { | ||
result = `const ${name || "schema"} = ${result}`; | ||
else if (name) { | ||
result = `const ${name} = ${result}`; | ||
} | ||
@@ -32,0 +30,0 @@ return result; |
@@ -23,4 +23,4 @@ "use strict"; | ||
return schema ? "z.any()" : "z.never()"; | ||
if (refs.overrideParser) { | ||
const custom = refs.overrideParser(schema, refs); | ||
if (refs.parserOverride) { | ||
const custom = refs.parserOverride(schema, refs); | ||
if (typeof custom === "string") { | ||
@@ -35,3 +35,3 @@ return custom; | ||
} | ||
if (refs.recursionDepth === undefined || seen.n >= refs.recursionDepth) { | ||
if (refs.depth === undefined || seen.n >= refs.depth) { | ||
return "z.any()"; | ||
@@ -38,0 +38,0 @@ } |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.omit = void 0; | ||
const omit = (obj, ...keys) => Object.fromEntries(Object.entries(obj).filter(([key]) => !keys.includes(key))); | ||
const omit = (obj, ...keys) => Object.keys(obj).reduce((acc, key) => { | ||
if (!keys.includes(key)) { | ||
acc[key] = obj[key]; | ||
} | ||
return acc; | ||
}, {}); | ||
exports.omit = omit; |
@@ -5,56 +5,52 @@ import { statSync, readFileSync } from "fs"; | ||
if (help) { | ||
const defaults = { | ||
name: "help", | ||
short: "h", | ||
description: "Display this message :)", | ||
}; | ||
const param = help === true | ||
? defaults | ||
: { | ||
...defaults, | ||
...help, | ||
}; | ||
let index = args.indexOf("--" + param.name); | ||
let index = args.indexOf("--help"); | ||
if (index === -1) { | ||
index = args.indexOf("-" + param.short); | ||
index = args.indexOf("-h"); | ||
} | ||
if (index !== -1) { | ||
printParams([...params, param]); | ||
printParams({ | ||
...params, | ||
help: { | ||
shorthand: "h", | ||
description: typeof help === "string" ? help : "Display this message :)", | ||
}, | ||
}); | ||
process.exit(0); | ||
} | ||
} | ||
for (const param of params) { | ||
let index = args.indexOf("--" + param.name); | ||
if (index === -1) { | ||
index = args.indexOf("-" + param.short); | ||
for (const name in params) { | ||
const { shorthand, required, value } = params[name]; | ||
let index = args.indexOf("--" + name); | ||
if (index === -1 && shorthand) { | ||
index = args.indexOf("-" + shorthand); | ||
} | ||
if (index === -1) { | ||
if (param.required) { | ||
throw new Error(typeof param.required === "string" | ||
? param.required | ||
: `Missing required argument ${param.name}`); | ||
if (required !== false) { | ||
throw new Error(typeof required === "string" && required !== "" | ||
? required | ||
: `Missing required argument ${name}`); | ||
} | ||
result[param.name] = false; | ||
result[name] = false; | ||
continue; | ||
} | ||
if (param.value) { | ||
if (value) { | ||
const value = args[index + 1]; | ||
if (value === undefined) { | ||
throw new Error(`Expected a value for argument ${param.name}`); | ||
throw new Error(`Expected a value for argument ${name}`); | ||
} | ||
if (param.value === "number") { | ||
if (value === "number") { | ||
const asNumber = Number(value); | ||
if (isNaN(asNumber)) { | ||
throw new Error(`Value of argument ${param.name} must be a valid number`); | ||
throw new Error(`Value of argument ${name} must be a valid number`); | ||
} | ||
result[param.name] = asNumber; | ||
result[name] = asNumber; | ||
continue; | ||
} | ||
if (Array.isArray(param.value) && !param.value.includes(value)) { | ||
throw new Error(`Value of argument ${param.name} must be one of ${param.value}`); | ||
if (Array.isArray(value) && !value.includes(value)) { | ||
throw new Error(`Value of argument ${name} must be one of ${value}`); | ||
} | ||
result[param.name] = value; | ||
result[name] = value; | ||
} | ||
else { | ||
result[param.name] = true; | ||
result[name] = true; | ||
} | ||
@@ -87,14 +83,15 @@ } | ||
export function printParams(params) { | ||
const longest = params.reduce((n, p) => (p.name.length > n ? p.name.length : n), 5); | ||
const longest = Object.keys(params).reduce((l, c) => (c.length > l ? c.length : l), 5); | ||
const header = "Name " + " ".repeat(longest - 2) + "Short Description"; | ||
console.log(header); | ||
for (const param of params) { | ||
for (const name in params) { | ||
const { shorthand, description } = params[name]; | ||
console.log("--" + | ||
param.name + | ||
" ".repeat(longest - param.name.length) + | ||
name + | ||
" ".repeat(longest - name.length) + | ||
" -" + | ||
param.short + | ||
shorthand + | ||
" " + | ||
param.description ?? ""); | ||
description ?? ""); | ||
} | ||
} |
@@ -6,45 +6,37 @@ #!/usr/bin/env node | ||
import { parseArgs, parseOrReadJSON, readPipe } from "./args.js"; | ||
const params = [ | ||
{ | ||
name: "input", | ||
short: "i", | ||
import { pick } from "./utils/pick.js"; | ||
const params = { | ||
input: { | ||
shorthand: "i", | ||
value: "string", | ||
required: process.stdin.isTTY && | ||
"input is required when no JSON or file path is piped", | ||
description: "JSON or a source file path", | ||
description: "JSON or a source file path. Required if no data is piped.", | ||
}, | ||
{ | ||
name: "output", | ||
short: "o", | ||
output: { | ||
shorthand: "o", | ||
value: "string", | ||
description: "A file path to write to. If not supplied output will be stdout", | ||
description: "A file path to write to. If not supplied stdout will be used.", | ||
}, | ||
{ | ||
name: "name", | ||
short: "n", | ||
name: { | ||
shorthand: "n", | ||
value: "string", | ||
description: "The name of the schema in the output", | ||
description: "The name of the schema in the output.", | ||
}, | ||
{ | ||
name: "depth", | ||
short: "d", | ||
depth: { | ||
shorthand: "d", | ||
value: "number", | ||
description: "Maximum depth of recursion before falling back to z.any() - defaults to 0", | ||
description: "Maximum depth of recursion before falling back to z.any(). Defaults to 0.", | ||
}, | ||
{ | ||
name: "module", | ||
short: "m", | ||
value: ["esm", "cjs"], | ||
description: "Force module syntax ('esm' or 'cjs')", | ||
module: { | ||
shorthand: "m", | ||
value: ["esm", "cjs", "none"], | ||
description: "Module syntax; 'esm', 'cjs' or 'none'. Defaults to 'esm'.", | ||
}, | ||
]; | ||
}; | ||
async function main() { | ||
const args = parseArgs(params, process.argv, {}); | ||
const args = parseArgs(params, process.argv, true); | ||
const input = args.input || (await readPipe()); | ||
const jsonSchema = parseOrReadJSON(input); | ||
const zodSchema = jsonSchemaToZod(jsonSchema, { | ||
module: args.module, | ||
name: args.name, | ||
recursionDepth: args["recursion-depth"], | ||
}); | ||
const zodSchema = jsonSchemaToZod(jsonSchema, pick(args, "name", "depth", "module")); | ||
if (args.output) { | ||
@@ -51,0 +43,0 @@ mkdirSync(dirname(args.output), { recursive: true }); |
import { jsonSchemaToZod } from "./jsonSchemaToZod.js"; | ||
export { jsonSchemaToZod }; | ||
import { parseSchema } from "./parsers/parseSchema.js"; | ||
export { parseSchema }; | ||
export default jsonSchemaToZod; |
import { parseSchema } from "./parsers/parseSchema.js"; | ||
export const jsonSchemaToZod = (schema, { module = true, name, ...rest } = {}) => { | ||
export const jsonSchemaToZod = (schema, { module, name, ...rest } = {}) => { | ||
let result = parseSchema(schema, { | ||
@@ -10,20 +10,18 @@ module, | ||
}); | ||
if (module) { | ||
if (module === "cjs") { | ||
result = `const { z } = require("zod") | ||
if (module === "cjs") { | ||
result = `const { z } = require("zod") | ||
module.exports = ${name ? `{ ${JSON.stringify(name)}: ${result} }` : result} | ||
`; | ||
} | ||
else { | ||
result = `import { z } from "zod" | ||
} | ||
else if (module === "esm") { | ||
result = `import { z } from "zod" | ||
export ${name ? `const ${name} =` : `default`} ${result} | ||
`; | ||
} | ||
} | ||
else { | ||
result = `const ${name || "schema"} = ${result}`; | ||
else if (name) { | ||
result = `const ${name} = ${result}`; | ||
} | ||
return result; | ||
}; |
@@ -20,4 +20,4 @@ import { parseAnyOf } from "./parseAnyOf.js"; | ||
return schema ? "z.any()" : "z.never()"; | ||
if (refs.overrideParser) { | ||
const custom = refs.overrideParser(schema, refs); | ||
if (refs.parserOverride) { | ||
const custom = refs.parserOverride(schema, refs); | ||
if (typeof custom === "string") { | ||
@@ -32,3 +32,3 @@ return custom; | ||
} | ||
if (refs.recursionDepth === undefined || seen.n >= refs.recursionDepth) { | ||
if (refs.depth === undefined || seen.n >= refs.depth) { | ||
return "z.any()"; | ||
@@ -35,0 +35,0 @@ } |
@@ -1,1 +0,6 @@ | ||
export const omit = (obj, ...keys) => Object.fromEntries(Object.entries(obj).filter(([key]) => !keys.includes(key))); | ||
export const omit = (obj, ...keys) => Object.keys(obj).reduce((acc, key) => { | ||
if (!keys.includes(key)) { | ||
acc[key] = obj[key]; | ||
} | ||
return acc; | ||
}, {}); |
export type Param = { | ||
name: string; | ||
short: string; | ||
shorthand?: string; | ||
description?: string; | ||
value?: "string" | "number" | string[]; | ||
required?: boolean | string; | ||
required?: boolean | string | undefined; | ||
} & ({ | ||
value?: "boolean"; | ||
} | { | ||
value: "number"; | ||
} | { | ||
value: "string"; | ||
} | { | ||
value: { | ||
[key: number]: string; | ||
}; | ||
}); | ||
export type Params = { | ||
[name: string]: Param; | ||
}; | ||
type Help = Partial<Pick<Param, "name" | "short" | "description">>; | ||
export declare function parseArgs(params: Param[], args: string[], help?: boolean | Help): Record<string, string | number | boolean | undefined>; | ||
type InferReturnType<T extends Params> = { | ||
[name in keyof T]: (T[name]["value"] extends "number" ? number : T[name]["value"] extends "string" ? string : T[name]["value"] extends { | ||
[key: number]: string; | ||
} ? T[name]["value"][number] : boolean) | (T[name]["required"] extends string | true ? never : undefined); | ||
}; | ||
export declare function parseArgs<T extends Params>(params: T, args: string[], help?: boolean | string): InferReturnType<T>; | ||
export declare function parseOrReadJSON(jsonOrPath: string): unknown; | ||
export declare function readPipe(): Promise<string>; | ||
export declare function printParams(params: Param[]): void; | ||
export declare function printParams(params: Record<string, Param>): void; | ||
export {}; |
import { jsonSchemaToZod } from "./jsonSchemaToZod.js"; | ||
export { jsonSchemaToZod }; | ||
import { parseSchema } from "./parsers/parseSchema.js"; | ||
export { parseSchema }; | ||
export default jsonSchemaToZod; |
@@ -51,6 +51,6 @@ export type Serializable = { | ||
name?: string; | ||
module?: boolean | "cjs" | "esm"; | ||
module?: "cjs" | "esm" | "none"; | ||
withoutDefaults?: boolean; | ||
overrideParser?: ParserOverride; | ||
recursionDepth?: number; | ||
parserOverride?: ParserOverride; | ||
depth?: number; | ||
}; | ||
@@ -57,0 +57,0 @@ export type Refs = Options & { |
{ | ||
"name": "json-schema-to-zod", | ||
"version": "2.0.4", | ||
"version": "2.0.5", | ||
"description": "Converts JSON schema objects or files into Zod schemas", | ||
@@ -47,2 +47,3 @@ "types": "dist/types/index.d.ts", | ||
"@types/node": "^20.9.0", | ||
"fast-diff": "^1.3.0", | ||
"rimraf": "^5.0.5", | ||
@@ -49,0 +50,0 @@ "tsx": "^4.1.1", |
@@ -38,9 +38,9 @@ # Json-Schema-to-Zod | ||
| Flag | Shorthand | Function | | ||
| ---------- | --------- | --------------------------------------------------------------------------------------- | | ||
| `--input` | `-i` | JSON or a source file path (required if no data is piped) | | ||
| `--output` | `-t` | Target file name | | ||
| `--name` | `-n` | The name of the schema in the output | | ||
| `--depth` | `-d` | Maximum depth of recursion in schema before falling back to `z.any()`. Defaults to 0. ` | | ||
| `--module` | `-m` | Force module syntax (`"esm"` or `"cjs"`) | | ||
| Flag | Shorthand | Function | | ||
| ---------- | --------- | -------------------------------------------------------------------------------------------- | | ||
| `--input` | `-i` | JSON or a source file path. Required if no data is piped. | | ||
| `--output` | `-t` | A file path to write to. If not supplied stdout will be used. | | ||
| `--name` | `-n` | The name of the schema in the output | | ||
| `--depth` | `-d` | Maximum depth of recursion in schema before falling back to `z.any()`. Defaults to 0. | | ||
| `--module` | `-m` | Module syntax; `esm`, `cjs` or none. Defaults to `esm` in the CLI and `none` programmaticly. | | ||
@@ -52,3 +52,3 @@ ### Programmatic | ||
```typescript | ||
import { jsonSchemaToZod, parseSchema } from "json-schema-to-zod"; | ||
import { jsonSchemaToZod } from "json-schema-to-zod"; | ||
@@ -62,7 +62,9 @@ const myObject = { | ||
}, | ||
} as const; | ||
}; | ||
const module = jsonSchemaToZod(myObject); | ||
const module = jsonSchemaToZod(myObject, { module: "esm" }); | ||
const schema = parseSchema(myObject); | ||
const cjs = jsonSchemaToZod(myObject, { module: "cjs", name: "mySchema" }); | ||
const schema = jsonSchemaToZod(myObject); | ||
``` | ||
@@ -78,2 +80,10 @@ | ||
#### `cjs` | ||
```typescript | ||
const { z } = require("zod"); | ||
module.exports = { mySchema: z.object({ hello: z.string().optional() }) }; | ||
``` | ||
#### `schema` | ||
@@ -87,3 +97,3 @@ | ||
You can pass a `ParserOverride` to the `overrideParser` option, which is a function that receives the current schema node and the reference object, and should return a string when it wants to replace a default output. If the default output should be used for the node, just return nothing. | ||
You can pass a function to the `overrideParser` option, which represents a function that receives the current schema node and the reference object, and should return a string when it wants to replace a default output. If the default output should be used for the node just return void. | ||
@@ -90,0 +100,0 @@ ### Use at Runtime |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
95014
86
2413
106
7