feat: support custom required validation messages

This commit is contained in:
2026-07-13 20:34:36 +05:30
parent b273e30c2f
commit 7a1c6c0041
58 changed files with 169 additions and 93 deletions
+19 -2
View File
@@ -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,
};
+2 -2
View File
@@ -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);