milamer / parse-nested-form-data

A tiny node module for parsing FormData by name into objects and arrays
MIT License
38 stars 1 forks source link

[Feature request]: Add date-string to date parsing flag #3

Open iolyd opened 3 months ago

iolyd commented 3 months ago

Feature description

This package is proving itself quite useful when working with next-js form actions, but recently I came across a tiny roadbump when working with <input type="date">/ <input type="datetime-locale"> fields and I think it could be easily handled.

Say one has a data validation schema (zod in my case) with date fields, date-input elements will pass dates as ISO datestrings to FormData and server-side data validation will raise an error. One could use some coercion or transformation at the schema level, something like z.string().pipe( z.coerce.date() ) to overcome this, but this means the schema now expects a string value input and strays a little further from the expected Date value.

Maybe a new formData entry name prefix, here proposed as @, could be used by parse-nested-form-data to flag values that should be represented as Dates.

Ex.:

<form action={handleDate}>
  <input type="datetime-locale" defaultValue={new Date().toISOString()} name="@start" />
</form>
export async function handleDate(formData: FormData) {
  console.log(formData.get('@start')) // String
  const parsed = parseFormData(formData);
  console.log(parsed.start) // Date
}

For illustration, here's a draft implementation using transformEntry:

export const transformEntry: ParseFormDataOptions['transformEntry'] = (
  [path, value],
  defaultTransform
) => {
  if (path.startsWith('@') && typeof value === 'string') {
    return {
      path: path.slice(1),
      value: value.length ? new Date(value) : null,
    };
  }
  return defaultTransform([path, value]);
};
milamer commented 4 days ago

Hi @iolyd,

Sorry for the late reply:

To handle date parsing in your schema, try using z.coerce.date() with Zod. This will allow you to transform the ISO date string into a Date object. Here's an example:

const schema = z.object({
  start: z.string().pipe(z.coerce.date()),
  end: z.coerce.date()
});

This way, you won't need a special formData entry prefix. The schema will parse the date string correctly into a Date object. See the zod docs for more info

Hope this helps!

Chris