{"version":3,"sources":["../src/helpers.ts"],"sourcesContent":["import { setPath } from \"@rvf/set-get\";\nimport * as z from \"zod/v4\";\nimport {\n  ZodPipe,\n  ZodTransform,\n  ZodArray,\n  ZodNumber,\n  ZodObject,\n  ZodString,\n  ZodType,\n} from \"zod/v4\";\n\ntype InputType<DefaultType extends ZodType> = {\n  (): ZodPipe<ZodTransform, DefaultType>;\n  <ProvidedType extends ZodType>(\n    schema: ProvidedType,\n  ): ZodPipe<ZodTransform, ProvidedType>;\n};\n\nconst stripEmpty = z.literal(\"\").transform(() => undefined);\n\nconst preprocessIfValid = (schema: ZodType) => (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    z.boolean(),\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 ZodType>(\n  schema: T,\n): ZodPipe<ZodTransform, 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.core.$ZodShape>(\n    shape: T,\n  ): ZodPipe<\n    ZodTransform<\n      ZodObject<T>,\n      FormData | FormDataLikeInput | z.input<ZodObject<T>>\n    >,\n    ZodObject<T>\n  >;\n  <T extends ZodType>(\n    shape: T,\n  ): ZodPipe<ZodTransform<T, FormData | FormDataLikeInput | z.input<T>>, 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 ZodType>(schema: T): ZodPipe<ZodTransform, 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, { abort: true })\n    .transform((val) => [...val])\n    .refine(\n      (val): val is z.infer<typeof entries> => entries.safeParse(val).success,\n      { abort: true },\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"],"mappings":"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","names":[]}