UNPKG

@conform-to/zod

Version:

Conform helpers for integrating with Zod

174 lines (168 loc) 6.68 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _rollupPluginBabelHelpers = require('../_virtual/_rollupPluginBabelHelpers.js'); var dom = require('@conform-to/dom'); var future = require('@conform-to/dom/future'); var keys = ['required', 'minLength', 'maxLength', 'min', 'max', 'step', 'multiple', 'pattern', 'accept']; function getZodConstraint(schema) { var processingPaths = new Map(); var aliases = []; var result = {}; var cache = {}; function updateConstraint(schema, data) { var _data$name; var name = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ''; // Detect re-entrant calls caused by getter-based recursive schemas var processingPath = processingPaths.get(schema); if (typeof processingPath !== 'undefined') { aliases.push({ from: dom.getPaths(name), to: dom.getPaths(processingPath) }); return; } processingPaths.set(schema, name); var constraint = name !== '' ? (_data$name = data[name]) !== null && _data$name !== void 0 ? _data$name : data[name] = { required: true } : {}; var def = schema._zod.def; if (def.type === 'object') { for (var key in def.shape) { // @ts-expect-error updateConstraint(def.shape[key], data, name ? "".concat(name, ".").concat(key) : key); } } else if (def.type === 'pipe') { // FIXME: What to do with .pipe()? if (def.out._zod.def.type === 'transform') { updateConstraint(def.in, data, name); } updateConstraint(def.out, data, name); } else if (def.type === 'intersection') { var leftResult = {}; var rightResult = {}; updateConstraint(def.left, leftResult, name); updateConstraint(def.right, rightResult, name); Object.assign(data, leftResult, rightResult); } else if (def.type === 'union' // || def.type === 'discriminatedUnion' ) { Object.assign(data, def.options.map(option => { var result = {}; updateConstraint(option, result, name); return result; }).reduce((prev, next) => { var list = new Set([...Object.keys(prev), ...Object.keys(next)]); var result = {}; for (var _name of list) { var prevConstraint = prev[_name]; var nextConstraint = next[_name]; if (prevConstraint && nextConstraint) { var _constraint = {}; result[_name] = _constraint; for (var _key of keys) { if (typeof prevConstraint[_key] !== 'undefined' && typeof nextConstraint[_key] !== 'undefined' && prevConstraint[_key] === nextConstraint[_key]) { // @ts-expect-error Both are on the same type _constraint[_key] = prevConstraint[_key]; } } } else { result[_name] = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, prevConstraint), nextConstraint), {}, { required: false }); } } return result; })); } else if (name === '') { // All the cases below are not allowed on root throw new Error('Unsupported schema'); } else if (def.type === 'array') { constraint.multiple = true; updateConstraint(def.element, data, "".concat(name, "[]")); } else if (def.type === 'string') { var _schema$_zod$bag$patt; var _schema = schema; if (_schema._zod.bag.minimum != null) { constraint.minLength = _schema._zod.bag.minimum; } if (_schema._zod.bag.maximum != null) { constraint.maxLength = _schema._zod.bag.maximum; } if ((_schema$_zod$bag$patt = _schema._zod.bag.patterns) !== null && _schema$_zod$bag$patt !== void 0 && _schema$_zod$bag$patt.size) { var pattern = future.serializeHtmlPattern([..._schema._zod.bag.patterns]); if (pattern) { constraint.pattern = pattern; } } } else if (def.type === 'optional') { constraint.required = false; updateConstraint(def.innerType, data, name); } else if (def.type === 'nullable') { updateConstraint(def.innerType, data, name); } else if (def.type === 'default') { constraint.required = false; updateConstraint(def.innerType, data, name); } else if (def.type === 'number') { var _schema2 = schema; if (_schema2._zod.bag.minimum != null) { constraint.min = _schema2._zod.bag.minimum; } if (_schema2._zod.bag.maximum != null) { constraint.max = _schema2._zod.bag.maximum; } } else if (def.type === 'enum') { constraint.pattern = Object.keys(def.entries).map(option => // To escape unsafe characters on regex option.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d')).join('|'); } else if (def.type === 'tuple') { for (var i = 0; i < def.items.length; i++) { // @ts-expect-error updateConstraint(def.items[i], data, "".concat(name, "[").concat(i, "]")); } } else if (def.type === 'file') { var _schema3 = schema; if (_schema3._zod.bag.mime) { constraint.accept = _schema3._zod.bag.mime.join(); } } else if (def.type === 'lazy') { var inner = def.getter(); updateConstraint(inner, data, name); } processingPaths.delete(schema); } function resolve(nameOrSegments) { var name = typeof nameOrSegments === 'string' ? nameOrSegments : dom.formatPaths(nameOrSegments); if (name in result) { return result[name]; } var segments = typeof nameOrSegments === 'string' ? dom.getPaths(nameOrSegments) : nameOrSegments; // Alias collapse first to handle tuple indices // like branch[0] before normalization would erase them for (var alias of aliases) { var tail = dom.getRelativePath(segments, alias.from); if (tail !== null && tail.length > 0) { return resolve([...alias.to, ...tail]); } } for (var i = segments.length - 1; i >= 0; i--) { if (typeof segments[i] === 'number') { // Normalizing indices by replacing rightmost numeric index with "[]" segments[i] = ''; return resolve(segments); } } return undefined; } updateConstraint(schema, result); return new Proxy(result, { get(target, name, receiver) { if (typeof name !== 'string') { return Reflect.get(target, name, receiver); } if (name in cache) { return cache[name]; } return cache[name] = resolve(name); } }); } exports.getZodConstraint = getZodConstraint;