@omer-x/bs-ui-kit
Version:
Bootstrap UI Kit for React.js
48 lines (47 loc) • 2.06 kB
JavaScript
import { bundleErrors } from "./zod-v4";
/**
* Defines a type-safe React server action for forms, validating form data with Zod and handling errors internally.
*
* @param definition - The form action definition object.
* @param definition.name - The unique name of the action.
* @param definition.middleware - An array of middleware functions to execute before the action. (Optional)
* @param definition.schema - The Zod schema used to validate form data.
* @param definition.action - The function to execute if validation succeeds.
* @returns An object containing the server action handler keyed by the action name.
*/
export function defineFormAction(definition) {
async function handler(...allParams) {
if (definition.middlewares) {
await Promise.all(definition.middlewares.map(middleware => middleware()));
}
const formData = allParams[allParams.length - 1];
const customArgs = allParams.slice(0, allParams.length - 2);
const validation = solveKnownIssues(definition.schema.strip(), Object.fromEntries(formData.entries()));
if (!validation.success) {
return bundleErrors(validation.error.issues);
}
return await definition.action(validation.data)(...customArgs);
}
return {
[definition.name]: handler,
};
}
function solveKnownIssues(schema, input) {
const validation = schema.safeParse(input);
if (!validation.success) {
for (const issue of validation.error.issues) {
if (issue.code === "invalid_type") {
if (issue.expected === "number" && issue.message.includes("expected number, received string")) {
const [location] = issue.path;
if (location in input) {
return solveKnownIssues(schema, {
...input,
[location]: parseFloat(input[location]),
});
}
}
}
}
}
return validation;
}