UNPKG

zod-opts

Version:

node.js CLI option parser / validator using Zod

272 lines (271 loc) 8.87 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getDefaultValue = getDefaultValue; exports.toInternalType = toInternalType; exports.toInternalTypeForZodUnion = toInternalTypeForZodUnion; exports.optionToInternal = optionToInternal; exports.positionalArgumentToInternal = positionalArgumentToInternal; const compat_1 = require("./compat"); const type_1 = require("./type"); const util_1 = require("./util"); const TYPE_NAME_MAP = { ZodString: "string", ZodNumber: "number", ZodBoolean: "boolean", ZodArray: "array", ZodObject: "object", ZodUnion: "union", ZodOptional: "optional", ZodDefault: "default", ZodEnum: "enum", ZodEffects: "effects", ZodPipeline: "pipe", ZodNullable: "nullable", ZodBranded: "branded", ZodPromise: "promise", ZodReadonly: "readonly", }; function normalizeTypeName(typeName) { var _a; return (_a = TYPE_NAME_MAP[typeName]) !== null && _a !== void 0 ? _a : typeName; } function getTypeName(def) { const raw = typeof def.typeName === "string" ? def.typeName : def.type; return normalizeTypeName(typeof raw === "string" ? raw : ""); } function getWrappedSchema(def) { if ((0, compat_1.isZodSchema)(def.innerType)) { return def.innerType; } if ((0, compat_1.isZodSchema)(def.schema)) { return def.schema; } if ((0, compat_1.isZodSchema)(def.inner)) { return def.inner; } if ((0, compat_1.isZodSchema)(def.in)) { return def.in; } return undefined; } function getWrappedDef(def) { const wrapped = getWrappedSchema(def); if (wrapped == null) { return undefined; } return (0, compat_1.getDef)(wrapped); } function getDefaultValue(def, allowOptionalDefault = false) { const resolveDefault = (currentDef, optionalSeen) => { if (currentDef == null || typeof currentDef !== "object") { return undefined; } const typedDef = currentDef; const typeName = getTypeName(typedDef); const nextOptionalSeen = optionalSeen || typeName === "optional"; if ("defaultValue" in typedDef) { if (nextOptionalSeen && !allowOptionalDefault) { return undefined; } const value = typedDef.defaultValue; if (typeof value === "function") { return value(); } return value; } const next = getWrappedDef(typedDef); if (next == null) { return undefined; } return resolveDefault(next, nextOptionalSeen); }; const defaultValue = resolveDefault(def, false); const isPrimitive = [...type_1.BASE_TYPES, "undefined"].includes(typeof defaultValue); if (!isPrimitive && !Array.isArray(defaultValue)) { throw new Error(`Unsupported default value: ${JSON.stringify(defaultValue)}`); } if (Array.isArray(defaultValue)) { if (defaultValue.length === 0) { return defaultValue; } const firstType = typeof defaultValue[0]; if (!["string", "number"].includes(firstType)) { throw new Error(`Unsupported default value: ${JSON.stringify(defaultValue)}`); } if ((0, util_1.uniq)(defaultValue.map((value) => typeof value)).length > 1) { throw new Error(`Unsupported default value: ${JSON.stringify(defaultValue)}`); } return defaultValue; } return defaultValue; } function isZodOptional(def) { let current = def; while (current != null) { if (getTypeName(current) === "optional") { return true; } current = getWrappedDef(current); } return false; } function isRequired(def) { if (isZodOptional(def)) { return false; } if (getDefaultValue(def) !== undefined) { return false; } if (getTypeName(def) === "union") { const options = Array.isArray(def.options) ? def.options : []; return !options.some((option) => { if (!(0, compat_1.isZodSchema)(option)) { return false; } return !isRequired((0, compat_1.getDef)(option)); }); } return true; } function resolveInnerType(def) { let current = def; while (true) { const typeName = getTypeName(current); if (["optional", "default"].includes(typeName)) { const next = getWrappedDef(current); if (next == null) { return current; } current = next; continue; } if ([ "effects", "pipe", "branded", "nullable", "promise", "readonly", ].includes(typeName)) { const next = getWrappedDef(current); if (next == null) { return current; } current = next; continue; } return current; } } function toInternalType(def, isPositional = false) { const solvedDef = resolveInnerType(def); const typeName = getTypeName(solvedDef); switch (typeName) { case "number": return "number"; case "string": return "string"; case "boolean": if (isPositional) { throw new Error(`Unsupported zod type (positional argument): ${typeName}`); } return "boolean"; case "enum": return "string"; case "union": return toInternalTypeForZodUnion(solvedDef); case "array": return toInternalTypeForZodArray(solvedDef); default: throw new Error(`Unsupported zod type: ${typeName}`); } } function toInternalTypeForZodUnion(def) { const options = Array.isArray(def.options) ? def.options : []; const types = (0, util_1.uniq)(options.flatMap((option) => { if (!(0, compat_1.isZodSchema)(option)) { return []; } return [toInternalType((0, compat_1.getDef)(option))]; })); if (types.length !== 1) { throw new Error("Union types are not same"); } return types[0]; } function toInternalTypeForZodArray(def) { const elementSchema = (0, compat_1.isZodSchema)(def.element) ? def.element : (0, compat_1.isZodSchema)(def.type) ? def.type : undefined; if (elementSchema == null) { throw new Error("Array element type not found"); } const elementDef = (0, compat_1.getDef)(elementSchema); const typeName = getTypeName(elementDef); switch (typeName) { case "string": return "string"; case "number": return "number"; default: throw new Error(`Unsupported zod type: Array of ${typeName}`); } } function getEnumValues(def) { const solvedDef = resolveInnerType(def); if (getTypeName(solvedDef) !== "enum") { return undefined; } if (Array.isArray(solvedDef.values) && solvedDef.values.every((value) => typeof value === "string")) { return solvedDef.values; } if ((0, compat_1.isRecord)(solvedDef.entries)) { return Object.keys(solvedDef.entries); } return undefined; } function optionToInternal(option, name) { var _a; const zodType = option.type; const def = (0, compat_1.getDef)(zodType); const defaultValue = getDefaultValue(def, (0, compat_1.isZodV4)(zodType)); const internalType = toInternalType(def); const resolvedDef = resolveInnerType(def); const resolvedTypeName = getTypeName(resolvedDef); const description = (_a = option.description) !== null && _a !== void 0 ? _a : (0, compat_1.getDescription)(zodType); const enumValues = getEnumValues(def); return { type: internalType, name, alias: option.alias, argumentName: option.argumentName, description, required: isRequired(def), isArray: resolvedTypeName === "array", defaultValue, enumValues, }; } function positionalArgumentToInternal(option) { var _a; const zodType = option.type; const def = (0, compat_1.getDef)(zodType); const defaultValue = getDefaultValue(def, (0, compat_1.isZodV4)(zodType)); const internalType = toInternalType(def, true); const resolvedDef = resolveInnerType(def); const resolvedTypeName = getTypeName(resolvedDef); const description = (_a = option.description) !== null && _a !== void 0 ? _a : (0, compat_1.getDescription)(zodType); const enumValues = getEnumValues(def); return { type: internalType, name: option.name, description, required: isRequired(def), isArray: resolvedTypeName === "array", defaultValue, enumValues, }; }