feat: support custom required validation messages
This commit is contained in:
@@ -22,6 +22,8 @@ export type RuleDescriptor =
|
||||
export interface FieldDescriptor {
|
||||
type: "string" | "number" | "boolean";
|
||||
optional?: boolean;
|
||||
/** Message used when a required field is empty. Defaults to "Required". */
|
||||
requiredMessage?: string;
|
||||
label?: string;
|
||||
/** Trim string input before validating. */
|
||||
trim?: boolean;
|
||||
@@ -103,13 +105,20 @@ export function checkField(
|
||||
): { value: unknown; error: string | null } {
|
||||
if (desc.type === "boolean") {
|
||||
const value = raw === true || raw === "true" || raw === "on";
|
||||
if (!desc.optional && !value) return { value, error: "Required" };
|
||||
if (!desc.optional && !value) {
|
||||
return { value, error: desc.requiredMessage || "Required" };
|
||||
}
|
||||
return { value, error: null };
|
||||
}
|
||||
|
||||
const pre = desc.trim && typeof raw === "string" ? raw.trim() : raw;
|
||||
const empty = pre === undefined || pre === null || pre === "";
|
||||
if (empty) return { value: undefined, error: desc.optional ? null : "Required" };
|
||||
if (empty) {
|
||||
return {
|
||||
value: undefined,
|
||||
error: desc.optional ? null : desc.requiredMessage || "Required",
|
||||
};
|
||||
}
|
||||
|
||||
let value: unknown;
|
||||
if (desc.type === "number") {
|
||||
@@ -133,6 +142,7 @@ type Refinement = { fn: (value: unknown) => boolean | string; message?: string }
|
||||
abstract class FieldSchema {
|
||||
abstract readonly type: "string" | "number" | "boolean";
|
||||
protected _optional = false;
|
||||
protected _requiredMessage?: string;
|
||||
protected _label?: string;
|
||||
protected _default?: unknown;
|
||||
protected rules: RuleDescriptor[] = [];
|
||||
@@ -142,6 +152,12 @@ abstract class FieldSchema {
|
||||
this._optional = true;
|
||||
return this;
|
||||
}
|
||||
/** Require a non-empty value and optionally replace the default message. */
|
||||
required(message = "Required"): this {
|
||||
this._optional = false;
|
||||
this._requiredMessage = message;
|
||||
return this;
|
||||
}
|
||||
label(label: string): this {
|
||||
this._label = label;
|
||||
return this;
|
||||
@@ -183,6 +199,7 @@ abstract class FieldSchema {
|
||||
return {
|
||||
type: this.type,
|
||||
optional: this._optional || undefined,
|
||||
requiredMessage: this._requiredMessage,
|
||||
label: this._label,
|
||||
rules: this.rules,
|
||||
};
|
||||
|
||||
@@ -42,11 +42,11 @@ export const VALIDATE_RUNTIME = String.raw`
|
||||
function checkField(desc, raw) {
|
||||
if (desc.type === "boolean") {
|
||||
var b = raw === true || raw === "true" || raw === "on";
|
||||
return (!desc.optional && !b) ? "Required" : null;
|
||||
return (!desc.optional && !b) ? (desc.requiredMessage || "Required") : null;
|
||||
}
|
||||
var pre = desc.trim && typeof raw === "string" ? raw.trim() : raw;
|
||||
var empty = pre === undefined || pre === null || pre === "";
|
||||
if (empty) return desc.optional ? null : "Required";
|
||||
if (empty) return desc.optional ? null : (desc.requiredMessage || "Required");
|
||||
var value;
|
||||
if (desc.type === "number") { value = Number(pre); if (isNaN(value)) return "Must be a number"; }
|
||||
else value = String(pre);
|
||||
|
||||
Reference in New Issue
Block a user