remix-params-helper
Version:
This package makes it simple to use Zod with standard URLSearchParams and FormData which are typically used in Remix apps.
236 lines (235 loc) • 7.54 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var helper_exports = {};
__export(helper_exports, {
getFormData: () => getFormData,
getFormDataOrFail: () => getFormDataOrFail,
getParams: () => getParams,
getParamsOrFail: () => getParamsOrFail,
getSearchParams: () => getSearchParams,
getSearchParamsOrFail: () => getSearchParamsOrFail,
useFormInputProps: () => useFormInputProps
});
module.exports = __toCommonJS(helper_exports);
var import_zod = require("zod");
function isIterable(maybeIterable) {
return Symbol.iterator in Object(maybeIterable);
}
function parseParams(o, schema, key, value) {
let shape = schema;
while (shape instanceof import_zod.ZodObject || shape instanceof import_zod.ZodEffects) {
shape = shape instanceof import_zod.ZodObject ? shape.shape : shape instanceof import_zod.ZodEffects ? shape._def.schema : null;
if (shape === null) {
throw new Error(`Could not find shape for key ${key}`);
}
}
if (key.includes(".")) {
let [parentProp, ...rest] = key.split(".");
o[parentProp] = o[parentProp] ?? {};
parseParams(o[parentProp], shape[parentProp], rest.join("."), value);
return;
}
let isArray = false;
if (key.includes("[]")) {
isArray = true;
key = key.replace("[]", "");
}
const def = shape[key];
if (def) {
processDef(def, o, key, value);
}
}
function getParamsInternal(params, schema) {
let o = {};
let entries = [];
if (isIterable(params)) {
entries = Array.from(params);
} else {
entries = Object.entries(params);
}
for (let [key, value] of entries) {
if (value === "") {
continue;
}
parseParams(o, schema, key, value);
}
const result = schema.safeParse(o);
if (result.success) {
return { success: true, data: result.data, errors: void 0 };
} else {
let errors = {};
const addError = (key, message) => {
if (!errors.hasOwnProperty(key)) {
errors[key] = message;
} else {
if (!Array.isArray(errors[key])) {
errors[key] = [errors[key]];
}
errors[key].push(message);
}
};
for (let issue of result.error.issues) {
const { message, path, code, expected, received } = issue;
const [key, index] = path;
let value = o[key];
let prop = key;
if (index !== void 0) {
value = value[index];
prop = `${key}[${index}]`;
}
addError(key, message);
}
return { success: false, data: void 0, errors };
}
}
function getParams(params, schema) {
return getParamsInternal(params, schema);
}
function getSearchParams(request, schema) {
let url = new URL(request.url);
return getParamsInternal(url.searchParams, schema);
}
async function getFormData(request, schema) {
let data = await request.formData();
return getParamsInternal(data, schema);
}
function getParamsOrFail(params, schema) {
const result = getParamsInternal(params, schema);
if (!result.success) {
throw new Error(JSON.stringify(result.errors));
}
return result.data;
}
function getSearchParamsOrFail(request, schema) {
let url = new URL(request.url);
const result = getParamsInternal(url.searchParams, schema);
if (!result.success) {
throw new Error(JSON.stringify(result.errors));
}
return result.data;
}
async function getFormDataOrFail(request, schema) {
let data = await request.formData();
const result = getParamsInternal(data, schema);
if (!result.success) {
throw new Error(JSON.stringify(result.errors));
}
return result.data;
}
function useFormInputProps(schema, options = {}) {
const shape = schema.shape;
const defaultOptions = options;
return function props(key, options2 = {}) {
options2 = { ...defaultOptions, ...options2 };
const def = shape[key];
if (!def) {
throw new Error(`no such key: ${key}`);
}
return getInputProps(key, def);
};
}
function processDef(def, o, key, value) {
let parsedValue;
if (def instanceof import_zod.ZodString || def instanceof import_zod.ZodLiteral) {
parsedValue = value;
} else if (def instanceof import_zod.ZodNumber) {
const num = Number(value);
parsedValue = isNaN(num) ? value : num;
} else if (def instanceof import_zod.ZodDate) {
const date = Date.parse(value);
parsedValue = isNaN(date) ? value : new Date(date);
} else if (def instanceof import_zod.ZodBoolean) {
parsedValue = value === "true" ? true : value === "false" ? false : Boolean(value);
} else if (def instanceof import_zod.ZodNativeEnum || def instanceof import_zod.ZodEnum) {
parsedValue = value;
} else if (def instanceof import_zod.ZodOptional || def instanceof import_zod.ZodDefault) {
processDef(def._def.innerType, o, key, value);
return;
} else if (def instanceof import_zod.ZodArray) {
if (o[key] === void 0) {
o[key] = [];
}
processDef(def.element, o, key, value);
return;
} else if (def instanceof import_zod.ZodEffects) {
processDef(def._def.schema, o, key, value);
return;
} else {
throw new Error(`Unexpected type ${def._def.typeName} for key ${key}`);
}
if (Array.isArray(o[key])) {
o[key].push(parsedValue);
} else {
o[key] = parsedValue;
}
}
function getInputProps(name, def) {
let type = "text";
let min, max, minlength, maxlength, pattern;
if (def instanceof import_zod.ZodString) {
if (def.isEmail) {
type = "email";
} else if (def.isURL) {
type = "url";
}
minlength = def.minLength ?? void 0;
maxlength = def.maxLength ?? void 0;
const check = def._def.checks.find((c) => c.kind === "regex");
pattern = check ? check.regex.source : void 0;
} else if (def instanceof import_zod.ZodNumber) {
type = "number";
min = def.minValue ?? void 0;
max = def.maxValue ?? void 0;
} else if (def instanceof import_zod.ZodBoolean) {
type = "checkbox";
} else if (def instanceof import_zod.ZodDate) {
type = "date";
} else if (def instanceof import_zod.ZodArray) {
return getInputProps(name, def.element);
} else if (def instanceof import_zod.ZodOptional) {
return getInputProps(name, def.unwrap());
}
let inputProps = {
name,
type
};
if (!def.isOptional())
inputProps.required = true;
if (min)
inputProps.min = min;
if (max)
inputProps.max = max;
if (minlength && Number.isFinite(minlength))
inputProps.minLength = minlength;
if (maxlength && Number.isFinite(maxlength))
inputProps.maxLength = maxlength;
if (pattern)
inputProps.pattern = pattern;
return inputProps;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
getFormData,
getFormDataOrFail,
getParams,
getParamsOrFail,
getSearchParams,
getSearchParamsOrFail,
useFormInputProps
});