@faivform/zod
Version:
Adapter to use Zod with @tuentyfaiv/svelte-form
79 lines (78 loc) • 2.32 kB
JavaScript
import { Adapter } from "@tuentyfaiv/svelte-form";
import { ZodError, ZodObject } from "zod";
class ZodAdapter extends Adapter {
#schema;
#resolveDeep;
constructor(config) {
super();
this.#schema = config.schema;
this.#resolveDeep = config.resolveDeep;
Object.freeze(this);
}
#setError = async (field, errros, error) => {
let message = null;
if (error instanceof ZodError) {
message = error.issues.reduce((_, issue) => issue.message, "");
}
await errros.update((prev) => ({ ...prev, [field]: message }));
};
initial = () => {
const start = Object.entries(this.#schema.shape).reduce((acc, [key, three]) => ({
fields: {
...acc.fields,
[key]: this.#resolveDeep(three),
},
errors: {
...acc.errors,
[key]: null,
},
}), {
fields: {},
errors: {},
});
return start;
};
validate = async (data) => {
await this.#schema.parse(data);
};
field = async (field, value, errors) => {
try {
this.#schema.shape[field].parse(value);
await this.#setError(field, errors);
}
catch (error) {
await this.#setError(field, errors, error);
}
};
errors = async (error, errors, handle) => {
await handle?.(error);
if (error instanceof ZodError) {
const messages = error.issues.reduce((acc, issue) => ({
...acc,
[issue.path.join(".")]: issue.message,
}), {});
await errors.update((prev) => ({
...prev,
...messages,
}));
}
};
}
export function adapter(schema) {
const resolveDeep = (three) => {
if (three instanceof ZodObject) {
return Object.entries(three.shape).reduce((acc, [key, value]) => ({
...acc,
[key]: resolveDeep(value),
}), {});
}
if (three.isNullable()) {
return null;
}
if (three.isOptional()) {
return undefined;
}
return null;
};
return new ZodAdapter({ schema, resolveDeep });
}