|
Hi 👋😊 I have this Zod schema: import { z } from "zod"
import { formatBytes } from "$lib/utilities/formatBytes"
export type Options = {
formats?: string[]
size?: {
min?: number
max?: number
}
}
/**
* The `size` argument properties are considered to contain bytes as numbers.
*/
export const files = (options?: Options) =>
z
.instanceof(File, { message: "Can't be empty!" })
.superRefine((file, ctx) => {
const addIssue = (message: string) => {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message,
fatal: true,
})
return z.NEVER
}
if (options?.formats) {
if (!file.name.includes(".")) {
return addIssue(
`Only formats ${options.formats} allowed! File "${file.name}" does not contain a format.`,
)
}
const fileNameSegments = file.name.split(".")
const fileNameExtension =
fileNameSegments[fileNameSegments.length - 1]
if (!options.formats.includes(fileNameExtension)) {
return addIssue(
`Only (${options.formats.join(", ")}) formats allowed! Got "${fileNameExtension}".`,
)
}
}
if (options?.size?.max && file.size > options.size.max) {
return addIssue(
`File size can't be above ${formatBytes(options.size.max)}`,
)
}
if (options?.size?.min && file.size > options.size.min) {
return addIssue(
`File size can't be under ${formatBytes(options.size.min)}`,
)
}
})
.array()
.min(1, "Can't be empty!")And I turned it into this: import * as v from "valibot"
import { formatBytes } from "$lib/utilities/formatBytes"
export type Options = {
formats?: string[]
size?: {
min?: number
max?: number
}
}
/**
* The `size` argument properties are considered to contain bytes as numbers.
*/
export const files = (options?: Options) =>
v.pipe(
v.array(
v.pipe(
v.file("Can't be empty!"),
v.check((file) => {
if (!options?.formats) return true
return file.name.includes(".")
}, `Only formats ${options?.formats} allowed! File does not contain a format.`),
v.check(
(file) => {
if (!options?.formats) return true
const fileNameSegments = file.name.split(".")
const fileNameExtension =
fileNameSegments[fileNameSegments.length - 1]
return !options.formats.includes(fileNameExtension) ?
false
: true
},
`Only (${options?.formats?.join(", ")}) formats allowed!)`,
),
v.check(
(file) => {
if (!options?.formats) return true
if (!options.size?.max) return true
return file.size > options.size.max ? false : true
},
`File size can't be above ${formatBytes(options?.size?.max ?? 0)}`,
),
v.check(
(file) => {
if (!options?.formats) return true
if (!options.size?.min) return true
return file.size > options.size.min ? false : true
},
`File size can't be under ${formatBytes(options?.size?.min ?? 0)}`,
),
),
),
v.minLength(1, "Can't be empty!"),
)The issues are: With Zod I could easily return an error message in my custom validation. But with Valibot I couldn't find a way. So, that's why I'm using I just want it to be exactly like Zod. Is it possible? |
Replies: 1 comment 1 reply
|
Hi @babakfp! I'm Dosu and I’m helping the valibot team. Valibot doesn't have a direct equivalent to Zod's Here's a sketch of how you could rewrite your schema using import * as v from "valibot";
import { formatBytes } from "$lib/utilities/formatBytes";
export type Options = {
formats?: string[];
size?: {
min?: number;
max?: number;
};
};
export const files = (options?: Options) =>
v.pipe(
v.array(
v.pipe(
v.file("Can't be empty!"),
v.rawCheck((file) => {
// Collect issues in an array
const issues = [];
if (options?.formats) {
if (!file.name.includes(".")) {
issues.push({
message: `Only formats ${options.formats} allowed! File "${file.name}" does not contain a format.`,
});
} else {
const ext = file.name.split(".").pop();
if (!options.formats.includes(ext)) {
issues.push({
message: `Only (${options.formats.join(", ")}) formats allowed! Got "${ext}".`,
});
}
}
}
if (options?.size?.max && file.size > options.size.max) {
issues.push({
message: `File size can't be above ${formatBytes(options.size.max)}`,
});
}
if (options?.size?.min && file.size < options.size.min) {
issues.push({
message: `File size can't be under ${formatBytes(options.size.min)}`,
});
}
// If any issues, return them
return issues.length ? issues : true;
})
)
),
v.minLength(1, "Can't be empty!")
);This way, all related validations and error messages are grouped together, and you can dynamically generate messages based on the file and options, similar to Zod's style see docs. You can also control whether validation aborts early or collects all issues using the Let me know if you want a deeper dive into TypeScript typing or more advanced error forwarding! To reply, just mention @dosu. Docs are dead. Just use Dosu. |
this is cool (the bot).
rawCheck did the trick: