zod-urlsearchparams
Version:
serializes and deserializes a zod schema to URLSearchParams
236 lines • 7.27 kB
JavaScript
// src/index.ts
import { z } from "zod";
function isScalar(value) {
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" || value instanceof Date;
}
function isEqual(value1, value2) {
if (isScalar(value1) && isScalar(value2)) {
return value1 === value2;
}
return JSON.stringify(value1) === JSON.stringify(value2);
}
var booleanToString = z.boolean().transform((val) => val ? "t" : "f");
var numberToString = z.number().transform((val) => val.toString());
var dateToString = z.date().transform((val) => val.toISOString());
var bigIntToString = z.bigint().transform((val) => val.toString());
var utf8ToBase64 = (str) => {
return btoa(
encodeURIComponent(str).replace(
/%([0-9A-F]{2})/g,
(_, p1) => String.fromCharCode(Number.parseInt(p1, 16))
)
).replace(/=+$/, "");
};
var base64ToUtf8 = (str) => {
const paddedStr = str.padEnd(str.length + (4 - str.length % 4) % 4, "=");
return decodeURIComponent(
atob(paddedStr).split("").map((c) => `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`).join("")
);
};
var otherToString = z.unknown().transform((val) => utf8ToBase64(JSON.stringify(val)));
var stringToBoolean = z.string().transform((val) => val === "t" || val === "true");
var stringToNumber = z.string().transform((val) => {
const num = Number(val);
return Number.isNaN(num) ? void 0 : num;
});
var stringToDate = z.string().transform((val) => new Date(val));
var stringToBigInt = z.string().transform((val) => BigInt(val));
var stringToOther = z.string().transform((val) => {
try {
return JSON.parse(base64ToUtf8(val));
} catch (error) {
return void 0;
}
});
function parseValue(value, schemaType) {
if (schemaType instanceof z.ZodNumber) {
return stringToNumber.parse(value);
}
if (schemaType instanceof z.ZodBoolean) {
return stringToBoolean.parse(value);
}
if (schemaType instanceof z.ZodString) {
return value;
}
if (schemaType instanceof z.ZodDate) {
return stringToDate.parse(value);
}
if (schemaType instanceof z.ZodBigInt) {
return stringToBigInt.parse(value);
}
if (schemaType instanceof z.ZodEffects) {
return parseValue(value, schemaType._def.schema);
}
if (schemaType instanceof z.ZodDefault) {
return parseValue(value, schemaType._def.innerType);
}
if (schemaType instanceof z.ZodOptional) {
return parseValue(value, schemaType._def.innerType);
}
if (schemaType instanceof z.ZodEnum || schemaType instanceof z.ZodNativeEnum || schemaType instanceof z.ZodLiteral || schemaType instanceof z.ZodUnion && schemaType._def.options.every(
(option) => option instanceof z.ZodLiteral || option instanceof z.ZodEnum || option instanceof z.ZodNativeEnum
)) {
return value;
}
return stringToOther.parse(value);
}
function serializeValue(value, schemaType) {
if (schemaType instanceof z.ZodString || schemaType instanceof z.ZodEnum || schemaType instanceof z.ZodNativeEnum || schemaType instanceof z.ZodLiteral || schemaType instanceof z.ZodUnion && schemaType._def.options.every(
(option) => option instanceof z.ZodLiteral || option instanceof z.ZodEnum || option instanceof z.ZodNativeEnum
)) {
return value;
}
if (schemaType instanceof z.ZodNumber) {
return numberToString.parse(value);
}
if (schemaType instanceof z.ZodBoolean) {
return booleanToString.parse(value);
}
if (schemaType instanceof z.ZodDate) {
return dateToString.parse(value);
}
if (schemaType instanceof z.ZodBigInt) {
return bigIntToString.parse(value);
}
if (schemaType instanceof z.ZodEffects) {
return serializeValue(value, schemaType._def.schema);
}
if (schemaType instanceof z.ZodDefault) {
let serialized = serializeValue(value, schemaType._def.innerType);
let defaultValue = serializeValue(schemaType._def.defaultValue(), schemaType._def.innerType);
if (serialized === defaultValue) return void 0;
return serialized;
}
if (schemaType instanceof z.ZodOptional) {
return serializeValue(value, schemaType._def.innerType);
}
return otherToString.parse(value);
}
function shape({
schema,
input,
defaultData
}) {
let obj = defaultData ? { ...defaultData } : {};
let schemaShape = schema.shape;
for (let key in schemaShape) {
let values = input.getAll(key);
let schemaType = schemaShape[key];
if (schemaType instanceof z.ZodArray) {
obj[key] = values.map((value) => parseValue(value, schemaType.element));
} else if (values.length > 0) {
let value = values[values.length - 1];
obj[key] = parseValue(value, schemaType);
}
}
return obj;
}
function parse({ schema, input, defaultData }) {
const shapedObject = shape({ schema, input, defaultData });
return schema.parse(shapedObject);
}
function safeParse({
schema,
input,
defaultData
}) {
const shapedObject = shape({ schema, input, defaultData });
return schema.safeParse(shapedObject);
}
function lenientParse({
schema,
input,
defaultData
}) {
const result = safeParse({ schema, input, defaultData });
if (result.success) {
return result.data;
}
const validFields = { ...defaultData };
const shapedObject = shape({ schema, input, defaultData });
for (const key in schema.shape) {
try {
const fieldSchema = schema.shape[key];
if (fieldSchema) {
const parsedValue = fieldSchema.parse(shapedObject[key]);
validFields[key] = parsedValue;
}
} catch (error) {
validFields[key] = defaultData[key];
}
}
const finalResult = schema.safeParse(validFields);
if (finalResult.success) {
return finalResult.data;
}
return defaultData;
}
function serialize({
schema,
data,
defaultData
}) {
let params = new URLSearchParams();
let schemaShape = schema.shape;
for (let key in data) {
if (Object.hasOwn(data, key)) {
let value = data[key];
let schemaType = schemaShape[key];
if (defaultData == null || !isEqual(value, defaultData[key])) {
if (schemaType instanceof z.ZodArray) {
for (let item of value) {
let serialized = serializeValue(item, schemaType.element);
if (serialized !== void 0) params.append(key, serialized);
}
} else {
let serialized = serializeValue(value, schemaType);
if (serialized !== void 0) params.append(key, serialized);
}
}
}
}
return params;
}
var ZodURLSearchParamSerializer = class {
constructor(schema, defaultData) {
this.schema = schema;
this.defaultData = defaultData;
}
serialize(data) {
return serialize({
data,
schema: this.schema,
defaultData: this.defaultData
});
}
parse(input) {
return parse({
input,
schema: this.schema,
defaultData: this.defaultData
});
}
safeParse(input) {
return safeParse({
input,
schema: this.schema,
defaultData: this.defaultData
});
}
lenientParse(input, defaultData) {
return lenientParse({
input,
schema: this.schema,
defaultData
});
}
};
export {
ZodURLSearchParamSerializer,
lenientParse,
parse,
safeParse,
serialize,
shape
};
//# sourceMappingURL=index.mjs.map