🚀 Big News:Socket Has Acquired Secure Annex.Learn More
Socket
Book a DemoSign in
Socket

zod-form-data

Package Overview
Dependencies
Maintainers
1
Versions
29
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

zod-form-data - npm Package Compare versions

Comparing version
2.0.5
to
2.0.6
+2
-2
dist/index.d.ts

@@ -61,4 +61,4 @@ import { ZodString, ZodNumber, z, ZodArray, ZodTypeAny, ZodEffects, ZodObject } from 'zod';

type FormDataType = {
<T extends z.ZodRawShape>(shape: T): ZodEffects<ZodObject<T>, z.output<ZodObject<T>>, FormData | FormDataLikeInput>;
<T extends z.ZodTypeAny>(schema: T): ZodEffects<T, z.output<T>, FormData | FormDataLikeInput>;
<T extends z.ZodRawShape>(shape: T): ZodEffects<ZodObject<T>, z.output<ZodObject<T>>, FormData | FormDataLikeInput | z.input<ZodObject<T>>>;
<T extends z.ZodTypeAny>(schema: T): ZodEffects<T, z.output<T>, FormData | FormDataLikeInput | z.input<T>>;
};

@@ -65,0 +65,0 @@ declare const json: <T extends ZodTypeAny>(schema: T) => ZodEffects<T>;

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/index.ts","../src/helpers.ts","../../set-get/src/stringToPathArray.ts","../../set-get/src/setPath.ts","../../set-get/src/getPath.ts","../../set-get/src/pathArrayToString.ts","../../set-get/src/toPathObject.ts","../../set-get/src/mergePathStrings.ts"],"sourcesContent":["import * as zfd from \"./helpers\";\n\nexport * from \"./helpers\";\nexport { zfd };\n","import { setPath } from \"@rvf/set-get\";\nimport {\n z,\n ZodArray,\n ZodEffects,\n ZodNumber,\n ZodObject,\n ZodString,\n ZodType,\n ZodTypeAny,\n} from \"zod\";\n\ntype InputType<DefaultType extends ZodTypeAny> = {\n (): ZodEffects<DefaultType>;\n <ProvidedType extends ZodTypeAny>(\n schema: ProvidedType,\n ): ZodEffects<ProvidedType>;\n};\n\nconst stripEmpty = z.literal(\"\").transform(() => undefined);\n\nconst preprocessIfValid = (schema: ZodTypeAny) => (val: unknown) => {\n const result = schema.safeParse(val);\n if (result.success) return result.data;\n return val;\n};\n\n/**\n * Transforms any empty strings to `undefined` before validating.\n * This makes it so empty strings will fail required checks,\n * allowing you to use `optional` for optional fields instead of `nonempty` for required fields.\n * If you call `zfd.text` with no arguments, it will assume the field is a required string by default.\n * If you want to customize the schema, you can pass that as an argument.\n */\nexport const text: InputType<ZodString> = (schema = z.string()) =>\n z.preprocess(preprocessIfValid(stripEmpty), schema) as any;\n\n/**\n * Coerces numerical strings to numbers transforms empty strings to `undefined` before validating.\n * If you call `zfd.number` with no arguments,\n * it will assume the field is a required number by default.\n * If you want to customize the schema, you can pass that as an argument.\n */\nexport const numeric: InputType<ZodNumber> = (schema = z.number()) =>\n z.preprocess(\n preprocessIfValid(\n z.union([\n stripEmpty,\n z\n .string()\n .transform((val) => Number(val))\n .refine((val) => !Number.isNaN(val)),\n ]),\n ),\n schema,\n ) as any;\n\ntype CheckboxOpts = {\n trueValue?: string;\n};\n\n/**\n * Turns the value from a checkbox field into a boolean,\n * but does not require the checkbox to be checked.\n * For checkboxes with a `value` attribute, you can pass that as the `trueValue` option.\n *\n * @example\n * ```ts\n * const schema = zfd.formData({\n * defaultCheckbox: zfd.checkbox(),\n * checkboxWithValue: zfd.checkbox({ trueValue: \"true\" }),\n * mustBeTrue: zfd\n * .checkbox()\n * .refine((val) => val, \"Please check this box\"),\n * });\n * });\n * ```\n */\nexport const checkbox = ({ trueValue = \"on\" }: CheckboxOpts = {}) =>\n z.union([\n z.literal(trueValue).transform(() => true),\n z.literal(undefined).transform(() => false),\n ]);\n\nexport const file: InputType<z.ZodType<File>> = (schema = z.instanceof(File)) =>\n z.preprocess((val) => {\n //Empty File object on no user input, so convert to undefined\n return val instanceof File && val.size === 0 ? undefined : val;\n }, schema) as any;\n\n/**\n * Preprocesses a field where you expect multiple values could be present for the same field name\n * and transforms the value of that field to always be an array.\n * If you don't provide a schema, it will assume the field is an array of zfd.text fields\n * and will not require any values to be present.\n */\nexport const repeatable: InputType<ZodArray<any>> = (\n schema = z.array(text()),\n) => {\n return z.preprocess((val) => {\n if (Array.isArray(val)) return val;\n if (val === undefined) return [];\n return [val];\n }, schema) as any;\n};\n\n/**\n * A convenience wrapper for repeatable.\n * Instead of passing the schema for an entire array, you pass in the schema for the item type.\n */\nexport const repeatableOfType = <T extends ZodTypeAny>(\n schema: T,\n): ZodEffects<ZodArray<T>> => repeatable(z.array(schema));\n\nconst entries = z.array(z.tuple([z.string(), z.any()]));\n\ntype FormDataLikeInput = {\n [Symbol.iterator](): IterableIterator<[string, FormDataEntryValue]>;\n entries(): IterableIterator<[string, FormDataEntryValue]>;\n};\n\ntype FormDataType = {\n <T extends z.ZodRawShape>(\n shape: T,\n ): ZodEffects<\n ZodObject<T>,\n z.output<ZodObject<T>>,\n FormData | FormDataLikeInput\n >;\n <T extends z.ZodTypeAny>(\n schema: T,\n ): ZodEffects<T, z.output<T>, FormData | FormDataLikeInput>;\n};\n\nconst safeParseJson = (jsonString: string) => {\n try {\n return JSON.parse(jsonString);\n } catch {\n return jsonString;\n }\n};\n\nexport const json = <T extends ZodTypeAny>(schema: T): ZodEffects<T> =>\n z.preprocess(\n preprocessIfValid(\n z.union([stripEmpty, z.string().transform((val) => safeParseJson(val))]),\n ),\n schema,\n );\n\nconst processFormData = preprocessIfValid(\n // We're avoiding using `instanceof` here because different environments\n // won't necessarily have `FormData` or `URLSearchParams`\n z\n .any()\n .refine((val) => Symbol.iterator in val)\n .transform((val) => [...val])\n .refine(\n (val): val is z.infer<typeof entries> => entries.safeParse(val).success,\n )\n .transform((data): Record<string, unknown | unknown[]> => {\n const map: Map<string, unknown[]> = new Map();\n for (const [key, value] of data) {\n if (map.has(key)) {\n map.get(key)!.push(value);\n } else {\n map.set(key, [value]);\n }\n }\n\n return [...map.entries()].reduce(\n (acc, [key, value]) => {\n return setPath(acc, key, value.length === 1 ? value[0] : value);\n },\n {} as Record<string, unknown | unknown[]>,\n );\n }),\n);\n\nexport const preprocessFormData = processFormData as (\n formData: unknown,\n) => Record<string, unknown>;\n\n/**\n * This helper takes the place of the `z.object` at the root of your schema.\n * It wraps your schema in a `z.preprocess` that extracts all the data out of a `FormData`\n * and transforms it into a regular object.\n * If the `FormData` contains multiple entries with the same field name,\n * it will automatically turn that field into an array.\n */\nexport const formData: FormDataType = (shapeOrSchema: any): any =>\n z.preprocess(\n processFormData,\n shapeOrSchema instanceof ZodType ? shapeOrSchema : z.object(shapeOrSchema),\n );\n","export const stringToPathArray = <T extends string>(\n path: T,\n): (string | number)[] => {\n if (path.length === 0) return [];\n\n const match =\n path.match(/^\\[(.+?)\\](.*)$/) || path.match(/^\\.?([^\\.\\[\\]]+)(.*)$/);\n if (match) {\n const [_, key, rest] = match;\n return [/^\\d+$/.test(key) ? Number(key) : key, ...stringToPathArray(rest)];\n }\n return [path];\n};\n","import { stringToPathArray } from \"./stringToPathArray\";\n\nexport function setPath<T>(\n object: T,\n path: string | (string | number)[],\n value: unknown,\n) {\n // deeply mutate the data\n const parts = Array.isArray(path) ? path : stringToPathArray(path);\n let obj: any = object;\n\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n const nextPart = parts[i + 1];\n if (obj[part] === undefined) {\n if (typeof nextPart === \"number\") {\n obj[part] = [];\n } else {\n obj[part] = {};\n }\n }\n obj = obj[part];\n }\n\n obj[parts[parts.length - 1]] = value;\n return object;\n}\n","import { stringToPathArray } from \"./stringToPathArray\";\n\nexport const getPath = (object: any, path: string | (string | number)[]) => {\n const parts = Array.isArray(path) ? path : stringToPathArray(path);\n let value = object;\n for (const part of parts) {\n value = (value as any)?.[part];\n }\n return value;\n};\n","export const pathArrayToString = (path: (string | number)[]): string => {\n if (path.length === 0) return \"\";\n\n let result = \"\";\n for (const item of path) {\n if (result === \"\") {\n result += `${item}`;\n continue;\n }\n\n const asNumber = Number(item);\n if (Number.isNaN(asNumber)) result += `.${item}`;\n else result += `[${item}]`;\n }\n\n return result;\n};\n","import { pathArrayToString } from \"./pathArrayToString\";\n\nexport type GenericObject = { [key: string]: any };\n\nexport const toPathObject = (obj: GenericObject): Record<string, unknown> => {\n const entries = getLeafEntries(obj, []);\n const flatEntries = entries.map(\n ([path, value]) => [pathArrayToString(path), value] as const,\n );\n return Object.fromEntries(flatEntries);\n};\n\ntype PathArray = (string | number)[];\n\nconst getLeafEntries = (\n obj: unknown,\n prefix: PathArray,\n): Array<[PathArray, unknown]> => {\n if (obj == null || typeof obj !== \"object\") return [[prefix, obj]];\n if (Array.isArray(obj))\n return obj.flatMap((item, index) =>\n getLeafEntries(item, [...prefix, index]),\n );\n return Object.entries(obj).flatMap(([key, value]) =>\n getLeafEntries(value, [...prefix, key]),\n );\n};\n","import { pathArrayToString } from \"./pathArrayToString\";\nimport { stringToPathArray } from \"./stringToPathArray\";\n\nexport const mergePathStrings = (\n ...paths: (string | number | null | undefined)[]\n) => {\n return pathArrayToString(\n paths\n .filter((segment) => segment != null)\n .map(String)\n .flatMap(stringToPathArray)\n .filter((segment) => segment !== \"\"),\n );\n};\n"],"mappings":"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","names":[]}
{"version":3,"sources":["../src/index.ts","../src/helpers.ts","../../set-get/src/stringToPathArray.ts","../../set-get/src/setPath.ts","../../set-get/src/getPath.ts","../../set-get/src/pathArrayToString.ts","../../set-get/src/toPathObject.ts","../../set-get/src/mergePathStrings.ts"],"sourcesContent":["import * as zfd from \"./helpers\";\n\nexport * from \"./helpers\";\nexport { zfd };\n","import { setPath } from \"@rvf/set-get\";\nimport {\n z,\n ZodArray,\n ZodEffects,\n ZodNumber,\n ZodObject,\n ZodString,\n ZodType,\n ZodTypeAny,\n} from \"zod\";\n\ntype InputType<DefaultType extends ZodTypeAny> = {\n (): ZodEffects<DefaultType>;\n <ProvidedType extends ZodTypeAny>(\n schema: ProvidedType,\n ): ZodEffects<ProvidedType>;\n};\n\nconst stripEmpty = z.literal(\"\").transform(() => undefined);\n\nconst preprocessIfValid = (schema: ZodTypeAny) => (val: unknown) => {\n const result = schema.safeParse(val);\n if (result.success) return result.data;\n return val;\n};\n\n/**\n * Transforms any empty strings to `undefined` before validating.\n * This makes it so empty strings will fail required checks,\n * allowing you to use `optional` for optional fields instead of `nonempty` for required fields.\n * If you call `zfd.text` with no arguments, it will assume the field is a required string by default.\n * If you want to customize the schema, you can pass that as an argument.\n */\nexport const text: InputType<ZodString> = (schema = z.string()) =>\n z.preprocess(preprocessIfValid(stripEmpty), schema) as any;\n\n/**\n * Coerces numerical strings to numbers transforms empty strings to `undefined` before validating.\n * If you call `zfd.number` with no arguments,\n * it will assume the field is a required number by default.\n * If you want to customize the schema, you can pass that as an argument.\n */\nexport const numeric: InputType<ZodNumber> = (schema = z.number()) =>\n z.preprocess(\n preprocessIfValid(\n z.union([\n stripEmpty,\n z\n .string()\n .transform((val) => Number(val))\n .refine((val) => !Number.isNaN(val)),\n ]),\n ),\n schema,\n ) as any;\n\ntype CheckboxOpts = {\n trueValue?: string;\n};\n\n/**\n * Turns the value from a checkbox field into a boolean,\n * but does not require the checkbox to be checked.\n * For checkboxes with a `value` attribute, you can pass that as the `trueValue` option.\n *\n * @example\n * ```ts\n * const schema = zfd.formData({\n * defaultCheckbox: zfd.checkbox(),\n * checkboxWithValue: zfd.checkbox({ trueValue: \"true\" }),\n * mustBeTrue: zfd\n * .checkbox()\n * .refine((val) => val, \"Please check this box\"),\n * });\n * });\n * ```\n */\nexport const checkbox = ({ trueValue = \"on\" }: CheckboxOpts = {}) =>\n z.union([\n z.literal(trueValue).transform(() => true),\n z.literal(undefined).transform(() => false),\n ]);\n\nexport const file: InputType<z.ZodType<File>> = (schema = z.instanceof(File)) =>\n z.preprocess((val) => {\n //Empty File object on no user input, so convert to undefined\n return val instanceof File && val.size === 0 ? undefined : val;\n }, schema) as any;\n\n/**\n * Preprocesses a field where you expect multiple values could be present for the same field name\n * and transforms the value of that field to always be an array.\n * If you don't provide a schema, it will assume the field is an array of zfd.text fields\n * and will not require any values to be present.\n */\nexport const repeatable: InputType<ZodArray<any>> = (\n schema = z.array(text()),\n) => {\n return z.preprocess((val) => {\n if (Array.isArray(val)) return val;\n if (val === undefined) return [];\n return [val];\n }, schema) as any;\n};\n\n/**\n * A convenience wrapper for repeatable.\n * Instead of passing the schema for an entire array, you pass in the schema for the item type.\n */\nexport const repeatableOfType = <T extends ZodTypeAny>(\n schema: T,\n): ZodEffects<ZodArray<T>> => repeatable(z.array(schema));\n\nconst entries = z.array(z.tuple([z.string(), z.any()]));\n\ntype FormDataLikeInput = {\n [Symbol.iterator](): IterableIterator<[string, FormDataEntryValue]>;\n entries(): IterableIterator<[string, FormDataEntryValue]>;\n};\n\ntype FormDataType = {\n <T extends z.ZodRawShape>(\n shape: T,\n ): ZodEffects<\n ZodObject<T>,\n z.output<ZodObject<T>>,\n FormData | FormDataLikeInput | z.input<ZodObject<T>>\n >;\n <T extends z.ZodTypeAny>(\n schema: T,\n ): ZodEffects<T, z.output<T>, FormData | FormDataLikeInput | z.input<T>>;\n};\n\nconst safeParseJson = (jsonString: string) => {\n try {\n return JSON.parse(jsonString);\n } catch {\n return jsonString;\n }\n};\n\nexport const json = <T extends ZodTypeAny>(schema: T): ZodEffects<T> =>\n z.preprocess(\n preprocessIfValid(\n z.union([stripEmpty, z.string().transform((val) => safeParseJson(val))]),\n ),\n schema,\n );\n\nconst processFormData = preprocessIfValid(\n // We're avoiding using `instanceof` here because different environments\n // won't necessarily have `FormData` or `URLSearchParams`\n z\n .any()\n .refine((val) => Symbol.iterator in val)\n .transform((val) => [...val])\n .refine(\n (val): val is z.infer<typeof entries> => entries.safeParse(val).success,\n )\n .transform((data): Record<string, unknown | unknown[]> => {\n const map: Map<string, unknown[]> = new Map();\n for (const [key, value] of data) {\n if (map.has(key)) {\n map.get(key)!.push(value);\n } else {\n map.set(key, [value]);\n }\n }\n\n return [...map.entries()].reduce(\n (acc, [key, value]) => {\n return setPath(acc, key, value.length === 1 ? value[0] : value);\n },\n {} as Record<string, unknown | unknown[]>,\n );\n }),\n);\n\nexport const preprocessFormData = processFormData as (\n formData: unknown,\n) => Record<string, unknown>;\n\n/**\n * This helper takes the place of the `z.object` at the root of your schema.\n * It wraps your schema in a `z.preprocess` that extracts all the data out of a `FormData`\n * and transforms it into a regular object.\n * If the `FormData` contains multiple entries with the same field name,\n * it will automatically turn that field into an array.\n */\nexport const formData: FormDataType = (shapeOrSchema: any): any =>\n z.preprocess(\n processFormData,\n shapeOrSchema instanceof ZodType ? shapeOrSchema : z.object(shapeOrSchema),\n );\n","export const stringToPathArray = <T extends string>(\n path: T,\n): (string | number)[] => {\n if (path.length === 0) return [];\n\n const match =\n path.match(/^\\[(.+?)\\](.*)$/) || path.match(/^\\.?([^\\.\\[\\]]+)(.*)$/);\n if (match) {\n const [_, key, rest] = match;\n return [/^\\d+$/.test(key) ? Number(key) : key, ...stringToPathArray(rest)];\n }\n return [path];\n};\n","import { stringToPathArray } from \"./stringToPathArray\";\n\nexport function setPath<T>(\n object: T,\n path: string | (string | number)[],\n value: unknown,\n) {\n // deeply mutate the data\n const parts = Array.isArray(path) ? path : stringToPathArray(path);\n let obj: any = object;\n\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n const nextPart = parts[i + 1];\n if (obj[part] === undefined) {\n if (typeof nextPart === \"number\") {\n obj[part] = [];\n } else {\n obj[part] = {};\n }\n }\n obj = obj[part];\n }\n\n obj[parts[parts.length - 1]] = value;\n return object;\n}\n","import { stringToPathArray } from \"./stringToPathArray\";\n\nexport const getPath = (object: any, path: string | (string | number)[]) => {\n const parts = Array.isArray(path) ? path : stringToPathArray(path);\n let value = object;\n for (const part of parts) {\n value = (value as any)?.[part];\n }\n return value;\n};\n","export const pathArrayToString = (path: (string | number)[]): string => {\n if (path.length === 0) return \"\";\n\n let result = \"\";\n for (const item of path) {\n if (result === \"\") {\n result += `${item}`;\n continue;\n }\n\n const asNumber = Number(item);\n if (Number.isNaN(asNumber)) result += `.${item}`;\n else result += `[${item}]`;\n }\n\n return result;\n};\n","import { pathArrayToString } from \"./pathArrayToString\";\n\nexport type GenericObject = { [key: string]: any };\n\nexport const toPathObject = (obj: GenericObject): Record<string, unknown> => {\n const entries = getLeafEntries(obj, []);\n const flatEntries = entries.map(\n ([path, value]) => [pathArrayToString(path), value] as const,\n );\n return Object.fromEntries(flatEntries);\n};\n\ntype PathArray = (string | number)[];\n\nconst getLeafEntries = (\n obj: unknown,\n prefix: PathArray,\n): Array<[PathArray, unknown]> => {\n if (obj == null || typeof obj !== \"object\") return [[prefix, obj]];\n if (Array.isArray(obj))\n return obj.flatMap((item, index) =>\n getLeafEntries(item, [...prefix, index]),\n );\n return Object.entries(obj).flatMap(([key, value]) =>\n getLeafEntries(value, [...prefix, key]),\n );\n};\n","import { pathArrayToString } from \"./pathArrayToString\";\nimport { stringToPathArray } from \"./stringToPathArray\";\n\nexport const mergePathStrings = (\n ...paths: (string | number | null | undefined)[]\n) => {\n return pathArrayToString(\n paths\n .filter((segment) => segment != null)\n .map(String)\n .flatMap(stringToPathArray)\n .filter((segment) => segment !== \"\"),\n );\n};\n"],"mappings":"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","names":[]}

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/helpers.ts","../../set-get/src/stringToPathArray.ts","../../set-get/src/setPath.ts","../../set-get/src/getPath.ts","../../set-get/src/pathArrayToString.ts","../../set-get/src/toPathObject.ts","../../set-get/src/mergePathStrings.ts"],"sourcesContent":["import { setPath } from \"@rvf/set-get\";\nimport {\n z,\n ZodArray,\n ZodEffects,\n ZodNumber,\n ZodObject,\n ZodString,\n ZodType,\n ZodTypeAny,\n} from \"zod\";\n\ntype InputType<DefaultType extends ZodTypeAny> = {\n (): ZodEffects<DefaultType>;\n <ProvidedType extends ZodTypeAny>(\n schema: ProvidedType,\n ): ZodEffects<ProvidedType>;\n};\n\nconst stripEmpty = z.literal(\"\").transform(() => undefined);\n\nconst preprocessIfValid = (schema: ZodTypeAny) => (val: unknown) => {\n const result = schema.safeParse(val);\n if (result.success) return result.data;\n return val;\n};\n\n/**\n * Transforms any empty strings to `undefined` before validating.\n * This makes it so empty strings will fail required checks,\n * allowing you to use `optional` for optional fields instead of `nonempty` for required fields.\n * If you call `zfd.text` with no arguments, it will assume the field is a required string by default.\n * If you want to customize the schema, you can pass that as an argument.\n */\nexport const text: InputType<ZodString> = (schema = z.string()) =>\n z.preprocess(preprocessIfValid(stripEmpty), schema) as any;\n\n/**\n * Coerces numerical strings to numbers transforms empty strings to `undefined` before validating.\n * If you call `zfd.number` with no arguments,\n * it will assume the field is a required number by default.\n * If you want to customize the schema, you can pass that as an argument.\n */\nexport const numeric: InputType<ZodNumber> = (schema = z.number()) =>\n z.preprocess(\n preprocessIfValid(\n z.union([\n stripEmpty,\n z\n .string()\n .transform((val) => Number(val))\n .refine((val) => !Number.isNaN(val)),\n ]),\n ),\n schema,\n ) as any;\n\ntype CheckboxOpts = {\n trueValue?: string;\n};\n\n/**\n * Turns the value from a checkbox field into a boolean,\n * but does not require the checkbox to be checked.\n * For checkboxes with a `value` attribute, you can pass that as the `trueValue` option.\n *\n * @example\n * ```ts\n * const schema = zfd.formData({\n * defaultCheckbox: zfd.checkbox(),\n * checkboxWithValue: zfd.checkbox({ trueValue: \"true\" }),\n * mustBeTrue: zfd\n * .checkbox()\n * .refine((val) => val, \"Please check this box\"),\n * });\n * });\n * ```\n */\nexport const checkbox = ({ trueValue = \"on\" }: CheckboxOpts = {}) =>\n z.union([\n z.literal(trueValue).transform(() => true),\n z.literal(undefined).transform(() => false),\n ]);\n\nexport const file: InputType<z.ZodType<File>> = (schema = z.instanceof(File)) =>\n z.preprocess((val) => {\n //Empty File object on no user input, so convert to undefined\n return val instanceof File && val.size === 0 ? undefined : val;\n }, schema) as any;\n\n/**\n * Preprocesses a field where you expect multiple values could be present for the same field name\n * and transforms the value of that field to always be an array.\n * If you don't provide a schema, it will assume the field is an array of zfd.text fields\n * and will not require any values to be present.\n */\nexport const repeatable: InputType<ZodArray<any>> = (\n schema = z.array(text()),\n) => {\n return z.preprocess((val) => {\n if (Array.isArray(val)) return val;\n if (val === undefined) return [];\n return [val];\n }, schema) as any;\n};\n\n/**\n * A convenience wrapper for repeatable.\n * Instead of passing the schema for an entire array, you pass in the schema for the item type.\n */\nexport const repeatableOfType = <T extends ZodTypeAny>(\n schema: T,\n): ZodEffects<ZodArray<T>> => repeatable(z.array(schema));\n\nconst entries = z.array(z.tuple([z.string(), z.any()]));\n\ntype FormDataLikeInput = {\n [Symbol.iterator](): IterableIterator<[string, FormDataEntryValue]>;\n entries(): IterableIterator<[string, FormDataEntryValue]>;\n};\n\ntype FormDataType = {\n <T extends z.ZodRawShape>(\n shape: T,\n ): ZodEffects<\n ZodObject<T>,\n z.output<ZodObject<T>>,\n FormData | FormDataLikeInput\n >;\n <T extends z.ZodTypeAny>(\n schema: T,\n ): ZodEffects<T, z.output<T>, FormData | FormDataLikeInput>;\n};\n\nconst safeParseJson = (jsonString: string) => {\n try {\n return JSON.parse(jsonString);\n } catch {\n return jsonString;\n }\n};\n\nexport const json = <T extends ZodTypeAny>(schema: T): ZodEffects<T> =>\n z.preprocess(\n preprocessIfValid(\n z.union([stripEmpty, z.string().transform((val) => safeParseJson(val))]),\n ),\n schema,\n );\n\nconst processFormData = preprocessIfValid(\n // We're avoiding using `instanceof` here because different environments\n // won't necessarily have `FormData` or `URLSearchParams`\n z\n .any()\n .refine((val) => Symbol.iterator in val)\n .transform((val) => [...val])\n .refine(\n (val): val is z.infer<typeof entries> => entries.safeParse(val).success,\n )\n .transform((data): Record<string, unknown | unknown[]> => {\n const map: Map<string, unknown[]> = new Map();\n for (const [key, value] of data) {\n if (map.has(key)) {\n map.get(key)!.push(value);\n } else {\n map.set(key, [value]);\n }\n }\n\n return [...map.entries()].reduce(\n (acc, [key, value]) => {\n return setPath(acc, key, value.length === 1 ? value[0] : value);\n },\n {} as Record<string, unknown | unknown[]>,\n );\n }),\n);\n\nexport const preprocessFormData = processFormData as (\n formData: unknown,\n) => Record<string, unknown>;\n\n/**\n * This helper takes the place of the `z.object` at the root of your schema.\n * It wraps your schema in a `z.preprocess` that extracts all the data out of a `FormData`\n * and transforms it into a regular object.\n * If the `FormData` contains multiple entries with the same field name,\n * it will automatically turn that field into an array.\n */\nexport const formData: FormDataType = (shapeOrSchema: any): any =>\n z.preprocess(\n processFormData,\n shapeOrSchema instanceof ZodType ? shapeOrSchema : z.object(shapeOrSchema),\n );\n","export const stringToPathArray = <T extends string>(\n path: T,\n): (string | number)[] => {\n if (path.length === 0) return [];\n\n const match =\n path.match(/^\\[(.+?)\\](.*)$/) || path.match(/^\\.?([^\\.\\[\\]]+)(.*)$/);\n if (match) {\n const [_, key, rest] = match;\n return [/^\\d+$/.test(key) ? Number(key) : key, ...stringToPathArray(rest)];\n }\n return [path];\n};\n","import { stringToPathArray } from \"./stringToPathArray\";\n\nexport function setPath<T>(\n object: T,\n path: string | (string | number)[],\n value: unknown,\n) {\n // deeply mutate the data\n const parts = Array.isArray(path) ? path : stringToPathArray(path);\n let obj: any = object;\n\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n const nextPart = parts[i + 1];\n if (obj[part] === undefined) {\n if (typeof nextPart === \"number\") {\n obj[part] = [];\n } else {\n obj[part] = {};\n }\n }\n obj = obj[part];\n }\n\n obj[parts[parts.length - 1]] = value;\n return object;\n}\n","import { stringToPathArray } from \"./stringToPathArray\";\n\nexport const getPath = (object: any, path: string | (string | number)[]) => {\n const parts = Array.isArray(path) ? path : stringToPathArray(path);\n let value = object;\n for (const part of parts) {\n value = (value as any)?.[part];\n }\n return value;\n};\n","export const pathArrayToString = (path: (string | number)[]): string => {\n if (path.length === 0) return \"\";\n\n let result = \"\";\n for (const item of path) {\n if (result === \"\") {\n result += `${item}`;\n continue;\n }\n\n const asNumber = Number(item);\n if (Number.isNaN(asNumber)) result += `.${item}`;\n else result += `[${item}]`;\n }\n\n return result;\n};\n","import { pathArrayToString } from \"./pathArrayToString\";\n\nexport type GenericObject = { [key: string]: any };\n\nexport const toPathObject = (obj: GenericObject): Record<string, unknown> => {\n const entries = getLeafEntries(obj, []);\n const flatEntries = entries.map(\n ([path, value]) => [pathArrayToString(path), value] as const,\n );\n return Object.fromEntries(flatEntries);\n};\n\ntype PathArray = (string | number)[];\n\nconst getLeafEntries = (\n obj: unknown,\n prefix: PathArray,\n): Array<[PathArray, unknown]> => {\n if (obj == null || typeof obj !== \"object\") return [[prefix, obj]];\n if (Array.isArray(obj))\n return obj.flatMap((item, index) =>\n getLeafEntries(item, [...prefix, index]),\n );\n return Object.entries(obj).flatMap(([key, value]) =>\n getLeafEntries(value, [...prefix, key]),\n );\n};\n","import { pathArrayToString } from \"./pathArrayToString\";\nimport { stringToPathArray } from \"./stringToPathArray\";\n\nexport const mergePathStrings = (\n ...paths: (string | number | null | undefined)[]\n) => {\n return pathArrayToString(\n paths\n .filter((segment) => segment != null)\n .map(String)\n .flatMap(stringToPathArray)\n .filter((segment) => segment !== \"\"),\n );\n};\n"],"mappings":"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","names":[]}
{"version":3,"sources":["../src/helpers.ts","../../set-get/src/stringToPathArray.ts","../../set-get/src/setPath.ts","../../set-get/src/getPath.ts","../../set-get/src/pathArrayToString.ts","../../set-get/src/toPathObject.ts","../../set-get/src/mergePathStrings.ts"],"sourcesContent":["import { setPath } from \"@rvf/set-get\";\nimport {\n z,\n ZodArray,\n ZodEffects,\n ZodNumber,\n ZodObject,\n ZodString,\n ZodType,\n ZodTypeAny,\n} from \"zod\";\n\ntype InputType<DefaultType extends ZodTypeAny> = {\n (): ZodEffects<DefaultType>;\n <ProvidedType extends ZodTypeAny>(\n schema: ProvidedType,\n ): ZodEffects<ProvidedType>;\n};\n\nconst stripEmpty = z.literal(\"\").transform(() => undefined);\n\nconst preprocessIfValid = (schema: ZodTypeAny) => (val: unknown) => {\n const result = schema.safeParse(val);\n if (result.success) return result.data;\n return val;\n};\n\n/**\n * Transforms any empty strings to `undefined` before validating.\n * This makes it so empty strings will fail required checks,\n * allowing you to use `optional` for optional fields instead of `nonempty` for required fields.\n * If you call `zfd.text` with no arguments, it will assume the field is a required string by default.\n * If you want to customize the schema, you can pass that as an argument.\n */\nexport const text: InputType<ZodString> = (schema = z.string()) =>\n z.preprocess(preprocessIfValid(stripEmpty), schema) as any;\n\n/**\n * Coerces numerical strings to numbers transforms empty strings to `undefined` before validating.\n * If you call `zfd.number` with no arguments,\n * it will assume the field is a required number by default.\n * If you want to customize the schema, you can pass that as an argument.\n */\nexport const numeric: InputType<ZodNumber> = (schema = z.number()) =>\n z.preprocess(\n preprocessIfValid(\n z.union([\n stripEmpty,\n z\n .string()\n .transform((val) => Number(val))\n .refine((val) => !Number.isNaN(val)),\n ]),\n ),\n schema,\n ) as any;\n\ntype CheckboxOpts = {\n trueValue?: string;\n};\n\n/**\n * Turns the value from a checkbox field into a boolean,\n * but does not require the checkbox to be checked.\n * For checkboxes with a `value` attribute, you can pass that as the `trueValue` option.\n *\n * @example\n * ```ts\n * const schema = zfd.formData({\n * defaultCheckbox: zfd.checkbox(),\n * checkboxWithValue: zfd.checkbox({ trueValue: \"true\" }),\n * mustBeTrue: zfd\n * .checkbox()\n * .refine((val) => val, \"Please check this box\"),\n * });\n * });\n * ```\n */\nexport const checkbox = ({ trueValue = \"on\" }: CheckboxOpts = {}) =>\n z.union([\n z.literal(trueValue).transform(() => true),\n z.literal(undefined).transform(() => false),\n ]);\n\nexport const file: InputType<z.ZodType<File>> = (schema = z.instanceof(File)) =>\n z.preprocess((val) => {\n //Empty File object on no user input, so convert to undefined\n return val instanceof File && val.size === 0 ? undefined : val;\n }, schema) as any;\n\n/**\n * Preprocesses a field where you expect multiple values could be present for the same field name\n * and transforms the value of that field to always be an array.\n * If you don't provide a schema, it will assume the field is an array of zfd.text fields\n * and will not require any values to be present.\n */\nexport const repeatable: InputType<ZodArray<any>> = (\n schema = z.array(text()),\n) => {\n return z.preprocess((val) => {\n if (Array.isArray(val)) return val;\n if (val === undefined) return [];\n return [val];\n }, schema) as any;\n};\n\n/**\n * A convenience wrapper for repeatable.\n * Instead of passing the schema for an entire array, you pass in the schema for the item type.\n */\nexport const repeatableOfType = <T extends ZodTypeAny>(\n schema: T,\n): ZodEffects<ZodArray<T>> => repeatable(z.array(schema));\n\nconst entries = z.array(z.tuple([z.string(), z.any()]));\n\ntype FormDataLikeInput = {\n [Symbol.iterator](): IterableIterator<[string, FormDataEntryValue]>;\n entries(): IterableIterator<[string, FormDataEntryValue]>;\n};\n\ntype FormDataType = {\n <T extends z.ZodRawShape>(\n shape: T,\n ): ZodEffects<\n ZodObject<T>,\n z.output<ZodObject<T>>,\n FormData | FormDataLikeInput | z.input<ZodObject<T>>\n >;\n <T extends z.ZodTypeAny>(\n schema: T,\n ): ZodEffects<T, z.output<T>, FormData | FormDataLikeInput | z.input<T>>;\n};\n\nconst safeParseJson = (jsonString: string) => {\n try {\n return JSON.parse(jsonString);\n } catch {\n return jsonString;\n }\n};\n\nexport const json = <T extends ZodTypeAny>(schema: T): ZodEffects<T> =>\n z.preprocess(\n preprocessIfValid(\n z.union([stripEmpty, z.string().transform((val) => safeParseJson(val))]),\n ),\n schema,\n );\n\nconst processFormData = preprocessIfValid(\n // We're avoiding using `instanceof` here because different environments\n // won't necessarily have `FormData` or `URLSearchParams`\n z\n .any()\n .refine((val) => Symbol.iterator in val)\n .transform((val) => [...val])\n .refine(\n (val): val is z.infer<typeof entries> => entries.safeParse(val).success,\n )\n .transform((data): Record<string, unknown | unknown[]> => {\n const map: Map<string, unknown[]> = new Map();\n for (const [key, value] of data) {\n if (map.has(key)) {\n map.get(key)!.push(value);\n } else {\n map.set(key, [value]);\n }\n }\n\n return [...map.entries()].reduce(\n (acc, [key, value]) => {\n return setPath(acc, key, value.length === 1 ? value[0] : value);\n },\n {} as Record<string, unknown | unknown[]>,\n );\n }),\n);\n\nexport const preprocessFormData = processFormData as (\n formData: unknown,\n) => Record<string, unknown>;\n\n/**\n * This helper takes the place of the `z.object` at the root of your schema.\n * It wraps your schema in a `z.preprocess` that extracts all the data out of a `FormData`\n * and transforms it into a regular object.\n * If the `FormData` contains multiple entries with the same field name,\n * it will automatically turn that field into an array.\n */\nexport const formData: FormDataType = (shapeOrSchema: any): any =>\n z.preprocess(\n processFormData,\n shapeOrSchema instanceof ZodType ? shapeOrSchema : z.object(shapeOrSchema),\n );\n","export const stringToPathArray = <T extends string>(\n path: T,\n): (string | number)[] => {\n if (path.length === 0) return [];\n\n const match =\n path.match(/^\\[(.+?)\\](.*)$/) || path.match(/^\\.?([^\\.\\[\\]]+)(.*)$/);\n if (match) {\n const [_, key, rest] = match;\n return [/^\\d+$/.test(key) ? Number(key) : key, ...stringToPathArray(rest)];\n }\n return [path];\n};\n","import { stringToPathArray } from \"./stringToPathArray\";\n\nexport function setPath<T>(\n object: T,\n path: string | (string | number)[],\n value: unknown,\n) {\n // deeply mutate the data\n const parts = Array.isArray(path) ? path : stringToPathArray(path);\n let obj: any = object;\n\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n const nextPart = parts[i + 1];\n if (obj[part] === undefined) {\n if (typeof nextPart === \"number\") {\n obj[part] = [];\n } else {\n obj[part] = {};\n }\n }\n obj = obj[part];\n }\n\n obj[parts[parts.length - 1]] = value;\n return object;\n}\n","import { stringToPathArray } from \"./stringToPathArray\";\n\nexport const getPath = (object: any, path: string | (string | number)[]) => {\n const parts = Array.isArray(path) ? path : stringToPathArray(path);\n let value = object;\n for (const part of parts) {\n value = (value as any)?.[part];\n }\n return value;\n};\n","export const pathArrayToString = (path: (string | number)[]): string => {\n if (path.length === 0) return \"\";\n\n let result = \"\";\n for (const item of path) {\n if (result === \"\") {\n result += `${item}`;\n continue;\n }\n\n const asNumber = Number(item);\n if (Number.isNaN(asNumber)) result += `.${item}`;\n else result += `[${item}]`;\n }\n\n return result;\n};\n","import { pathArrayToString } from \"./pathArrayToString\";\n\nexport type GenericObject = { [key: string]: any };\n\nexport const toPathObject = (obj: GenericObject): Record<string, unknown> => {\n const entries = getLeafEntries(obj, []);\n const flatEntries = entries.map(\n ([path, value]) => [pathArrayToString(path), value] as const,\n );\n return Object.fromEntries(flatEntries);\n};\n\ntype PathArray = (string | number)[];\n\nconst getLeafEntries = (\n obj: unknown,\n prefix: PathArray,\n): Array<[PathArray, unknown]> => {\n if (obj == null || typeof obj !== \"object\") return [[prefix, obj]];\n if (Array.isArray(obj))\n return obj.flatMap((item, index) =>\n getLeafEntries(item, [...prefix, index]),\n );\n return Object.entries(obj).flatMap(([key, value]) =>\n getLeafEntries(value, [...prefix, key]),\n );\n};\n","import { pathArrayToString } from \"./pathArrayToString\";\nimport { stringToPathArray } from \"./stringToPathArray\";\n\nexport const mergePathStrings = (\n ...paths: (string | number | null | undefined)[]\n) => {\n return pathArrayToString(\n paths\n .filter((segment) => segment != null)\n .map(String)\n .flatMap(stringToPathArray)\n .filter((segment) => segment !== \"\"),\n );\n};\n"],"mappings":"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","names":[]}
{
"name": "zod-form-data",
"version": "2.0.5",
"version": "2.0.6",
"homepage": "https://github.com/airjp73/rvf/tree/main/packages/zod-form-data",

@@ -5,0 +5,0 @@ "main": "./dist/index.js",