@lara-node/validator 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index-CJqaUTqU.d.ts +33 -0
- package/dist/index-CJqaUTqU.d.ts.map +1 -0
- package/dist/index.js +1108 -0
- package/dist/index.js.map +1 -0
- package/package.json +32 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/index.d.ts
|
|
2
|
+
declare class ValidationError extends Error {
|
|
3
|
+
errors: Record<string, string[]>;
|
|
4
|
+
messages: Record<string, string[]>;
|
|
5
|
+
message: string;
|
|
6
|
+
constructor(errors: Record<string, string[]>, messages?: Record<string, string[]>);
|
|
7
|
+
}
|
|
8
|
+
type RuleFn = (value: any, field: string, payload?: any) => true | {
|
|
9
|
+
ok: boolean;
|
|
10
|
+
message?: string;
|
|
11
|
+
value?: any;
|
|
12
|
+
} | false | Promise<any>;
|
|
13
|
+
type RuleSpec = string | RuleFn | {
|
|
14
|
+
rule: string | RuleFn;
|
|
15
|
+
messages?: Record<string, string>;
|
|
16
|
+
};
|
|
17
|
+
declare function formatMessage(template: string, ctx: Record<string, any>): string;
|
|
18
|
+
declare function resolveMessage(field: string, code: string, meta: Record<string, any>, custom?: Record<string, string>): string;
|
|
19
|
+
declare function validate<T extends Record<string, any>>(payload: any, rules: Record<string, RuleSpec>, customMessages?: Record<string, string>): Promise<T>;
|
|
20
|
+
declare const requiredIf: (otherField: string, value: any) => RuleFn;
|
|
21
|
+
declare const requiredUnless: (otherField: string, value: any) => RuleFn;
|
|
22
|
+
declare const fileRule: RuleFn;
|
|
23
|
+
declare const mimes: (allowedTypes: string[]) => RuleFn;
|
|
24
|
+
declare const maxFileSize: (maxSizeInMB: number) => RuleFn;
|
|
25
|
+
declare const phoneRule: RuleFn;
|
|
26
|
+
declare const creditCardRule: RuleFn;
|
|
27
|
+
declare const nestedRule: (rules: Record<string, RuleSpec>) => RuleFn;
|
|
28
|
+
declare const arrayOfObjectsRule: (rules: Record<string, RuleSpec>) => RuleFn;
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
export { RuleFn, RuleSpec, ValidationError, arrayOfObjectsRule, creditCardRule, fileRule, formatMessage, maxFileSize, mimes, nestedRule, phoneRule, requiredIf, requiredUnless, resolveMessage, validate };
|
|
33
|
+
//# sourceMappingURL=index-CJqaUTqU.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-CJqaUTqU.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";cAEa,eAAA,SAAwB,KAAA;EAAxB,MAAA,EACH,MADG,CAAA,MAAgB,EAAA,MAAA,EAAA,CAAA;EAAA,QAAA,EAEjB,MAFiB,CAAA,MAAA,EAAA,MAAA,EAAA,CAAA;SACnB,EAAA,MAAA;aACE,CAAA,MAAA,EAGU,MAHV,CAAA,MAAA,EAAA,MAAA,EAAA,CAAA,EAAA,QAAA,CAAA,EAG+C,MAH/C,CAAA,MAAA,EAAA,MAAA,EAAA,CAAA;;AAG+C,KAqB/C,MAAA,GArB+C,CAAA,KAAA,EAAA,GAAA,EAAA,KAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GAAA,EAAA,GAAA,IAAA,GAAA;MALtB,OAAA;EAAK,OAAA,CAAA,EAAA,MAAA;EA0B9B,KAAA,CAAA,EAAA,GAAM;AAMlB,CAAA,GAAY,KAAA,GAFyD,OAEjD,CAAA,GAAA,CAAA;AAAA,KAAR,QAAA,GAAQ,MAAA,GAEhB,MAFgB,GAAA;MAEhB,EAAA,MAAA,GACiB,MADjB;UACiB,CAAA,EAAmB,MAAnB,CAAA,MAAA,EAAA,MAAA,CAAA;;AAAyB,iBAgG9B,aAAA,CAhG8B,QAAA,EAAA,MAAA,EAAA,GAAA,EAgGO,MAhGP,CAAA,MAAA,EAAA,GAAA,CAAA,CAAA,EAAA,MAAA;AAgG9B,iBAMA,cAAA,CAN2C,KAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EASnD,MATmD,CAAA,MAAA,EAAA,GAAA,CAAA,EAAA,MAAA,CAAA,EAUhD,MAVgD,CAAA,MAAA,EAAA,MAAA,CAAA,CAAA,EAAA,MAAA;AAM3C,iBAmBM,QAnBQ,CAAA,UAmBW,MAnBX,CAAA,MAAA,EAAA,GAAA,CAAA,CAAA,CAAA,OAAA,EAAA,GAAA,EAAA,KAAA,EAqBrB,MArBqB,CAAA,MAAA,EAqBN,QArBM,CAAA,EAAA,cAAA,CAAA,EAsBX,MAtBW,CAAA,MAAA,EAAA,MAAA,CAAA,CAAA,EAuB3B,OAvB2B,CAuBnB,CAvBmB,CAAA;AAAA,cAgiBjB,UAhiBiB,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,KAAA,EAAA,GAAA,EAAA,GAiiBM,MAjiBN;AAGtB,cAsiBK,cAtiBL,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,KAAA,EAAA,GAAA,EAAA,GAuiB4B,MAviB5B;AACG,cA8iBE,QA9iBF,EA8iBY,MA9iBZ;AAAM,cAojBJ,KApjBI,EAAA,CAAA,YAAA,EAAA,MAAA,EAAA,EAAA,GAqjBW,MArjBX;AAeK,cAyjBT,WAzjBiB,EAAA,CAAA,WAAA,EAAA,MAAA,EAAA,GA0jBL,MA1jBK;AAAA,cAkkBjB,SAlkBiB,EAkkBN,MAlkBM;AAAW,cA2kB5B,cA3kB4B,EA2kBZ,MA3kBY;AAEjB,cAulBX,UAvlBW,EAAA,CAAA,KAAA,EAwlBd,MAxlBc,CAAA,MAAA,EAwlBC,QAxlBD,CAAA,EAAA,GAwlBa,MAxlBb;AAAf,cAgmBI,kBAhmBJ,EAAA,CAAA,KAAA,EAimBC,MAjmBD,CAAA,MAAA,EAimBgB,QAjmBhB,CAAA,EAAA,GAimB4B,MAjmB5B"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,1108 @@
|
|
|
1
|
+
import { Model } from "@lara-node/db";
|
|
2
|
+
//#region src/index.ts
|
|
3
|
+
var ValidationError = class ValidationError extends Error {
|
|
4
|
+
constructor(errors, messages) {
|
|
5
|
+
super("Validation failed");
|
|
6
|
+
this.errors = errors;
|
|
7
|
+
this.messages = messages || {};
|
|
8
|
+
this.message = "unknown error";
|
|
9
|
+
const totalErrors = Object.values(this.messages).reduce((sum, currentArray) => sum + currentArray.length, 0);
|
|
10
|
+
const firstError = Object.values(this.messages).find((arr) => arr.length > 0)?.[0];
|
|
11
|
+
if (firstError) if (totalErrors > 1) this.message = `${firstError} and ${totalErrors - 1} more error(s).`;
|
|
12
|
+
else this.message = firstError;
|
|
13
|
+
Object.setPrototypeOf(this, ValidationError.prototype);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const defaultMessages = {
|
|
17
|
+
required: ":attribute field is required.",
|
|
18
|
+
integer: ":attribute must be an integer.",
|
|
19
|
+
numeric: ":attribute must be a number.",
|
|
20
|
+
array: ":attribute must be an array.",
|
|
21
|
+
json: ":attribute must be valid JSON.",
|
|
22
|
+
email: ":attribute must be a valid email address.",
|
|
23
|
+
boolean: ":attribute must be true or false.",
|
|
24
|
+
date: ":attribute must be a valid date.",
|
|
25
|
+
url: ":attribute must be a valid URL.",
|
|
26
|
+
uuid: ":attribute must be a valid UUID.",
|
|
27
|
+
object: ":attribute must be an object.",
|
|
28
|
+
"min.numeric": ":attribute must be at least :min.",
|
|
29
|
+
"min.string": ":attribute must be at least :min characters.",
|
|
30
|
+
"min.array": ":attribute must have at least :min items.",
|
|
31
|
+
"max.numeric": ":attribute may not be greater than :max.",
|
|
32
|
+
"max.string": ":attribute may not be greater than :max characters.",
|
|
33
|
+
"max.array": ":attribute may not have more than :max items.",
|
|
34
|
+
"size.string": ":attribute must be exactly :size characters.",
|
|
35
|
+
"size.array": ":attribute must contain exactly :size items.",
|
|
36
|
+
"size.numeric": ":attribute must be exactly :size.",
|
|
37
|
+
"between.numeric": ":attribute must be between :min and :max.",
|
|
38
|
+
"between.string": ":attribute must be between :min and :max characters.",
|
|
39
|
+
"between.array": ":attribute must have between :min and :max items.",
|
|
40
|
+
regex: ":attribute format is invalid.",
|
|
41
|
+
regex_invalid: "Invalid regex pattern for :attribute validation.",
|
|
42
|
+
phone: ":attribute must be a valid phone number.",
|
|
43
|
+
credit_card: ":attribute must be a valid credit card number.",
|
|
44
|
+
in: ":attribute must be one of: :values.",
|
|
45
|
+
not_in: ":attribute must not be one of: :values.",
|
|
46
|
+
exists: "Selected :attribute is invalid.",
|
|
47
|
+
unique: ":attribute has already been taken.",
|
|
48
|
+
starts_with: ":attribute must start with one of: :prefixes.",
|
|
49
|
+
ends_with: ":attribute must end with one of: :suffixes.",
|
|
50
|
+
contains: ":attribute must contain :substring.",
|
|
51
|
+
accepted: ":attribute must be accepted.",
|
|
52
|
+
declined: ":attribute must be declined.",
|
|
53
|
+
confirmed: ":attribute confirmation does not match.",
|
|
54
|
+
different: ":attribute and :other must be different.",
|
|
55
|
+
same: ":attribute and :other must be the same.",
|
|
56
|
+
gt: ":attribute must be greater than :field.",
|
|
57
|
+
gte: ":attribute must be greater than or equal to :field.",
|
|
58
|
+
lt: ":attribute must be less than :field.",
|
|
59
|
+
lte: ":attribute must be less than or equal to :field.",
|
|
60
|
+
before: ":attribute must be a date before :field.",
|
|
61
|
+
before_or_equal: ":attribute must be a date before or equal to :field.",
|
|
62
|
+
after: ":attribute must be a date after :field.",
|
|
63
|
+
after_or_equal: ":attribute must be a date after or equal to :field.",
|
|
64
|
+
date_equals: ":attribute must be the same date as :field.",
|
|
65
|
+
date_format: ":attribute does not match the format :format.",
|
|
66
|
+
time: ":attribute must be a valid time (HH:MM or HH:MM:SS).",
|
|
67
|
+
datetime: ":attribute must be a valid date and time.",
|
|
68
|
+
timezone: ":attribute must be a valid timezone.",
|
|
69
|
+
file: ":attribute must be a file.",
|
|
70
|
+
mimes: ":attribute must be a file of type: :values.",
|
|
71
|
+
max_file_size: ":attribute may not be larger than :max MB.",
|
|
72
|
+
required_if: ":attribute is required.",
|
|
73
|
+
required_unless: ":attribute is required.",
|
|
74
|
+
required_with: ":attribute is required when :values is present.",
|
|
75
|
+
required_with_all: ":attribute is required when :values are all present.",
|
|
76
|
+
required_without: ":attribute is required when :values is not present.",
|
|
77
|
+
required_without_all: ":attribute is required when none of :values are present.",
|
|
78
|
+
present: ":attribute field must be present.",
|
|
79
|
+
invalid: ":attribute is invalid.",
|
|
80
|
+
nested_validation_failed: ":attribute contains invalid data.",
|
|
81
|
+
object_array: ":attribute must be an array of objects."
|
|
82
|
+
};
|
|
83
|
+
function parseDate(val) {
|
|
84
|
+
if (val instanceof Date) return isNaN(val.getTime()) ? null : val;
|
|
85
|
+
const str = String(val).trim();
|
|
86
|
+
for (const { re, y, m, d } of [
|
|
87
|
+
{
|
|
88
|
+
re: /^(\d{1,2})\/(\d{1,2})\/(\d{2,4})$/,
|
|
89
|
+
y: 3,
|
|
90
|
+
m: 2,
|
|
91
|
+
d: 1
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
re: /^(\d{1,2})-(\d{1,2})-(\d{2,4})$/,
|
|
95
|
+
y: 3,
|
|
96
|
+
m: 2,
|
|
97
|
+
d: 1
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
re: /^(\d{1,2})\.(\d{1,2})\.(\d{2,4})$/,
|
|
101
|
+
y: 3,
|
|
102
|
+
m: 2,
|
|
103
|
+
d: 1
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
re: /^(\d{4})\/(\d{1,2})\/(\d{1,2})$/,
|
|
107
|
+
y: 1,
|
|
108
|
+
m: 2,
|
|
109
|
+
d: 3
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
re: /^(\d{4})\.(\d{1,2})\.(\d{1,2})$/,
|
|
113
|
+
y: 1,
|
|
114
|
+
m: 2,
|
|
115
|
+
d: 3
|
|
116
|
+
}
|
|
117
|
+
]) {
|
|
118
|
+
const match = str.match(re);
|
|
119
|
+
if (match) {
|
|
120
|
+
let year = parseInt(match[y], 10);
|
|
121
|
+
if (year < 100) year += year < 70 ? 2e3 : 1900;
|
|
122
|
+
const month = parseInt(match[m], 10) - 1;
|
|
123
|
+
const day = parseInt(match[d], 10);
|
|
124
|
+
const dt = new Date(year, month, day);
|
|
125
|
+
if (!isNaN(dt.getTime()) && dt.getMonth() === month) return dt;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const native = new Date(str);
|
|
129
|
+
if (!isNaN(native.getTime())) return native;
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
function formatMessage(template, ctx) {
|
|
133
|
+
return template.replace(/:([a-zA-Z_]+)/g, (_, key) => ctx[key] !== void 0 ? String(ctx[key]) : ":" + key);
|
|
134
|
+
}
|
|
135
|
+
function resolveMessage(field, code, meta, custom) {
|
|
136
|
+
let variantCode = code;
|
|
137
|
+
if ([
|
|
138
|
+
"min",
|
|
139
|
+
"max",
|
|
140
|
+
"size",
|
|
141
|
+
"between"
|
|
142
|
+
].includes(code) && meta.kind) variantCode = `${code}.${meta.kind}`;
|
|
143
|
+
const attrLabel = custom && custom[`attributes.${field}`] ? custom[`attributes.${field}`] : field;
|
|
144
|
+
const candidates = [
|
|
145
|
+
`${field}.${variantCode}`,
|
|
146
|
+
`${field}.${code}`,
|
|
147
|
+
variantCode,
|
|
148
|
+
code
|
|
149
|
+
];
|
|
150
|
+
for (const c of candidates) {
|
|
151
|
+
if (custom && custom[c]) return formatMessage(custom[c], {
|
|
152
|
+
...meta,
|
|
153
|
+
attribute: attrLabel
|
|
154
|
+
});
|
|
155
|
+
if (defaultMessages[c]) return formatMessage(defaultMessages[c], {
|
|
156
|
+
...meta,
|
|
157
|
+
attribute: attrLabel
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
return formatMessage(defaultMessages.invalid || "Invalid value", {
|
|
161
|
+
...meta,
|
|
162
|
+
attribute: attrLabel
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
async function validate(payload, rules, customMessages) {
|
|
166
|
+
const out = { ...payload || {} };
|
|
167
|
+
const errors = {};
|
|
168
|
+
const messageErrors = {};
|
|
169
|
+
const metaErrors = {};
|
|
170
|
+
const fieldMessagesMap = {};
|
|
171
|
+
function normalizePattern(p) {
|
|
172
|
+
return p.replace(/\.\.+/g, ".*").replace(/(^|\.)\*(\.|$)/g, (_, a, b) => "*" + (b ? "." : "")).replace(/\.\*/g, ".*");
|
|
173
|
+
}
|
|
174
|
+
function splitSegments(pattern) {
|
|
175
|
+
return pattern.split(".").map((s) => s === "" ? "*" : s);
|
|
176
|
+
}
|
|
177
|
+
function getAtPath(obj, path) {
|
|
178
|
+
if (!obj) return void 0;
|
|
179
|
+
const segs = path.split(".");
|
|
180
|
+
let cur = obj;
|
|
181
|
+
for (const s of segs) {
|
|
182
|
+
if (cur === void 0 || cur === null) return void 0;
|
|
183
|
+
if (/^\d+$/.test(s)) cur = cur[Number(s)];
|
|
184
|
+
else cur = cur[s];
|
|
185
|
+
}
|
|
186
|
+
return cur;
|
|
187
|
+
}
|
|
188
|
+
function setAtPath(obj, path, value) {
|
|
189
|
+
const segs = path.split(".");
|
|
190
|
+
let cur = obj;
|
|
191
|
+
for (let i = 0; i < segs.length; i++) {
|
|
192
|
+
const s = segs[i];
|
|
193
|
+
const isLast = i === segs.length - 1;
|
|
194
|
+
const key = /^\d+$/.test(s) ? Number(s) : s;
|
|
195
|
+
if (isLast) {
|
|
196
|
+
cur[key] = value;
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (cur[key] === void 0 || cur[key] === null) {
|
|
200
|
+
const nextSeg = segs[i + 1];
|
|
201
|
+
cur[key] = /^\d+$/.test(nextSeg) ? [] : {};
|
|
202
|
+
}
|
|
203
|
+
cur = cur[key];
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function expandFieldPaths(obj, pattern) {
|
|
207
|
+
if (!pattern) return [];
|
|
208
|
+
const segs = splitSegments(normalizePattern(pattern));
|
|
209
|
+
const results = [];
|
|
210
|
+
function recurse(current, idx, prefix) {
|
|
211
|
+
if (idx >= segs.length) {
|
|
212
|
+
results.push(prefix.replace(/^\./, ""));
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const seg = segs[idx];
|
|
216
|
+
if (seg === "*" || seg === "") if (Array.isArray(current)) for (let i = 0; i < current.length; i++) recurse(current[i], idx + 1, prefix + "." + i);
|
|
217
|
+
else if (current && typeof current === "object") for (const k of Object.keys(current)) recurse(current[k], idx + 1, prefix + "." + k);
|
|
218
|
+
else {
|
|
219
|
+
const parentPath = prefix.replace(/^\./, "");
|
|
220
|
+
let parentVal = void 0;
|
|
221
|
+
try {
|
|
222
|
+
parentVal = parentPath ? getAtPath(obj, parentPath) : obj;
|
|
223
|
+
} catch {
|
|
224
|
+
parentVal = void 0;
|
|
225
|
+
}
|
|
226
|
+
if (typeof parentVal === "string") {
|
|
227
|
+
try {
|
|
228
|
+
const parsed = JSON.parse(parentVal);
|
|
229
|
+
if (Array.isArray(parsed)) {
|
|
230
|
+
for (let i = 0; i < parsed.length; i++) recurse(parsed[i], idx + 1, prefix + "." + i);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
} catch {}
|
|
234
|
+
if (parentVal.includes(",")) {
|
|
235
|
+
const parts = parentVal.split(",").map((s) => s.trim()).filter(Boolean);
|
|
236
|
+
for (let i = 0; i < parts.length; i++) recurse(parts[i], idx + 1, prefix + "." + i);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
recurse(void 0, idx + 1, prefix + ".*");
|
|
241
|
+
}
|
|
242
|
+
else if (current && (typeof current === "object" || Array.isArray(current)) && seg in current) recurse(current[seg], idx + 1, prefix + "." + seg);
|
|
243
|
+
else if (current && Array.isArray(current) && /^\d+$/.test(seg)) recurse(current[Number(seg)], idx + 1, prefix + "." + seg);
|
|
244
|
+
else recurse(void 0, idx + 1, prefix + "." + seg);
|
|
245
|
+
}
|
|
246
|
+
recurse(obj, 0, "");
|
|
247
|
+
if (results.length === 0) {
|
|
248
|
+
if (!pattern.includes("*")) return [pattern];
|
|
249
|
+
return [];
|
|
250
|
+
}
|
|
251
|
+
return Array.from(new Set(results));
|
|
252
|
+
}
|
|
253
|
+
for (const fieldPattern of Object.keys(rules)) {
|
|
254
|
+
const spec = rules[fieldPattern];
|
|
255
|
+
let fieldRule;
|
|
256
|
+
if (typeof spec === "object" && spec && typeof spec !== "function" && "rule" in spec) {
|
|
257
|
+
fieldRule = spec.rule;
|
|
258
|
+
if (spec.messages) {
|
|
259
|
+
const prefixed = {};
|
|
260
|
+
for (const [k, v] of Object.entries(spec.messages)) prefixed[k.startsWith(fieldPattern + ".") ? k : `${fieldPattern}.${k}`] = v;
|
|
261
|
+
fieldMessagesMap[fieldPattern] = prefixed;
|
|
262
|
+
}
|
|
263
|
+
} else fieldRule = spec;
|
|
264
|
+
const targetPaths = expandFieldPaths(out, fieldPattern);
|
|
265
|
+
if (fieldPattern.includes("*") && targetPaths.length === 0) continue;
|
|
266
|
+
let pathsToValidate = [];
|
|
267
|
+
for (const tp of targetPaths.length ? targetPaths : [fieldPattern]) if (tp.includes(".*") || tp.includes("*")) {
|
|
268
|
+
const parentPath = tp.replace(/\.(?:\*|\.)+$/, "").replace(/\*$/, "");
|
|
269
|
+
const parentVal = parentPath ? getAtPath(out, parentPath) : out;
|
|
270
|
+
if (Array.isArray(parentVal)) {
|
|
271
|
+
for (let i = 0; i < parentVal.length; i++) pathsToValidate.push(`${parentPath}.${i}`);
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
if (typeof parentVal === "string") {
|
|
275
|
+
try {
|
|
276
|
+
const parsed = JSON.parse(parentVal);
|
|
277
|
+
if (Array.isArray(parsed)) {
|
|
278
|
+
for (let i = 0; i < parsed.length; i++) pathsToValidate.push(`${parentPath}.${i}`);
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
} catch {}
|
|
282
|
+
if (parentVal.includes(",")) {
|
|
283
|
+
const parts = parentVal.split(",").map((s) => s.trim()).filter(Boolean);
|
|
284
|
+
for (let i = 0; i < parts.length; i++) pathsToValidate.push(`${parentPath}.${i}`);
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
pathsToValidate.push(tp);
|
|
289
|
+
} else pathsToValidate.push(tp);
|
|
290
|
+
for (const field of pathsToValidate) {
|
|
291
|
+
const raw = getAtPath(out, field);
|
|
292
|
+
if (typeof fieldRule === "function") {
|
|
293
|
+
const res = await fieldRule(raw, field, out);
|
|
294
|
+
if (res === true) continue;
|
|
295
|
+
if (res === false) {
|
|
296
|
+
pushError(field, "invalid", {
|
|
297
|
+
value: raw,
|
|
298
|
+
kind: typeof raw
|
|
299
|
+
});
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
if (res && res.ok === false) {
|
|
303
|
+
pushError(field, res.message || "invalid", {
|
|
304
|
+
value: raw,
|
|
305
|
+
kind: typeof raw
|
|
306
|
+
});
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
if (res && res.ok === true && "value" in res) {
|
|
310
|
+
setAtPath(out, field, res.value);
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
const parts = String(fieldRule).split("|").map((s) => s.trim()).filter(Boolean);
|
|
316
|
+
const isRequired = parts.includes("required");
|
|
317
|
+
const isNullable = parts.includes("nullable");
|
|
318
|
+
const isSometimes = parts.includes("sometimes");
|
|
319
|
+
const isPresent = parts.includes("present");
|
|
320
|
+
const present = raw !== void 0 && raw !== null && raw !== "";
|
|
321
|
+
let conditionalRequired = false;
|
|
322
|
+
for (const p of parts) if (p.startsWith("required_if:")) {
|
|
323
|
+
const [condField, ...values] = p.slice(12).split(",").map((s) => s.trim());
|
|
324
|
+
if (values.some((v) => v === String(getAtPath(out, condField) ?? ""))) conditionalRequired = true;
|
|
325
|
+
} else if (p.startsWith("required_unless:")) {
|
|
326
|
+
const [condField, ...values] = p.slice(16).split(",").map((s) => s.trim());
|
|
327
|
+
if (!values.some((v) => v === String(getAtPath(out, condField) ?? ""))) conditionalRequired = true;
|
|
328
|
+
} else if (p.startsWith("required_with:")) {
|
|
329
|
+
if (p.slice(14).split(",").map((s) => s.trim()).some((f) => {
|
|
330
|
+
const v = getAtPath(out, f);
|
|
331
|
+
return v !== void 0 && v !== null && v !== "";
|
|
332
|
+
})) conditionalRequired = true;
|
|
333
|
+
} else if (p.startsWith("required_with_all:")) {
|
|
334
|
+
if (p.slice(18).split(",").map((s) => s.trim()).every((f) => {
|
|
335
|
+
const v = getAtPath(out, f);
|
|
336
|
+
return v !== void 0 && v !== null && v !== "";
|
|
337
|
+
})) conditionalRequired = true;
|
|
338
|
+
} else if (p.startsWith("required_without:")) {
|
|
339
|
+
if (p.slice(17).split(",").map((s) => s.trim()).some((f) => {
|
|
340
|
+
const v = getAtPath(out, f);
|
|
341
|
+
return v === void 0 || v === null || v === "";
|
|
342
|
+
})) conditionalRequired = true;
|
|
343
|
+
} else if (p.startsWith("required_without_all:")) {
|
|
344
|
+
if (p.slice(21).split(",").map((s) => s.trim()).every((f) => {
|
|
345
|
+
const v = getAtPath(out, f);
|
|
346
|
+
return v === void 0 || v === null || v === "";
|
|
347
|
+
})) conditionalRequired = true;
|
|
348
|
+
}
|
|
349
|
+
const effectiveRequired = isRequired || conditionalRequired;
|
|
350
|
+
if (isSometimes && !present) continue;
|
|
351
|
+
if (isPresent && raw === void 0) {
|
|
352
|
+
pushError(field, "present", { value: raw });
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
if (effectiveRequired && !present) {
|
|
356
|
+
pushError(field, "required", { value: raw });
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
if (!present && (isNullable || !effectiveRequired)) continue;
|
|
360
|
+
let val = raw;
|
|
361
|
+
let failed = false;
|
|
362
|
+
for (const p of parts) {
|
|
363
|
+
if ([
|
|
364
|
+
"required",
|
|
365
|
+
"nullable",
|
|
366
|
+
"sometimes",
|
|
367
|
+
"present"
|
|
368
|
+
].includes(p)) continue;
|
|
369
|
+
if (p.startsWith("required_if:") || p.startsWith("required_unless:") || p.startsWith("required_with:") || p.startsWith("required_with_all:") || p.startsWith("required_without:") || p.startsWith("required_without_all:")) continue;
|
|
370
|
+
if (failed) break;
|
|
371
|
+
switch (true) {
|
|
372
|
+
case p === "string":
|
|
373
|
+
if (typeof val !== "string") val = String(val);
|
|
374
|
+
break;
|
|
375
|
+
case p === "email":
|
|
376
|
+
if (typeof val !== "string") val = String(val);
|
|
377
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val)) {
|
|
378
|
+
pushError(field, "email", {
|
|
379
|
+
value: val,
|
|
380
|
+
kind: "string"
|
|
381
|
+
});
|
|
382
|
+
failed = true;
|
|
383
|
+
}
|
|
384
|
+
break;
|
|
385
|
+
case p === "int" || p === "integer": {
|
|
386
|
+
const intVal = parseInt(val, 10);
|
|
387
|
+
if (Number.isNaN(intVal)) {
|
|
388
|
+
pushError(field, "integer", {
|
|
389
|
+
value: val,
|
|
390
|
+
kind: typeof val
|
|
391
|
+
});
|
|
392
|
+
failed = true;
|
|
393
|
+
} else val = intVal;
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
case p === "numeric" || p === "float" || p === "double": {
|
|
397
|
+
const numVal = Number(val);
|
|
398
|
+
if (Number.isNaN(numVal)) {
|
|
399
|
+
pushError(field, "numeric", {
|
|
400
|
+
value: val,
|
|
401
|
+
kind: typeof val
|
|
402
|
+
});
|
|
403
|
+
failed = true;
|
|
404
|
+
} else val = numVal;
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
407
|
+
case p === "boolean":
|
|
408
|
+
if (typeof val === "string") {
|
|
409
|
+
const lv = val.toLowerCase();
|
|
410
|
+
if ([
|
|
411
|
+
"true",
|
|
412
|
+
"1",
|
|
413
|
+
"yes",
|
|
414
|
+
"on"
|
|
415
|
+
].includes(lv)) val = true;
|
|
416
|
+
else if ([
|
|
417
|
+
"false",
|
|
418
|
+
"0",
|
|
419
|
+
"no",
|
|
420
|
+
"off"
|
|
421
|
+
].includes(lv)) val = false;
|
|
422
|
+
else {
|
|
423
|
+
pushError(field, "boolean", {
|
|
424
|
+
value: val,
|
|
425
|
+
kind: typeof val
|
|
426
|
+
});
|
|
427
|
+
failed = true;
|
|
428
|
+
}
|
|
429
|
+
} else if (typeof val !== "boolean") {
|
|
430
|
+
pushError(field, "boolean", {
|
|
431
|
+
value: val,
|
|
432
|
+
kind: typeof val
|
|
433
|
+
});
|
|
434
|
+
failed = true;
|
|
435
|
+
}
|
|
436
|
+
break;
|
|
437
|
+
case p === "array":
|
|
438
|
+
if (!Array.isArray(val)) if (typeof val === "string") try {
|
|
439
|
+
const p2 = JSON.parse(val);
|
|
440
|
+
if (Array.isArray(p2)) val = p2;
|
|
441
|
+
else {
|
|
442
|
+
pushError(field, "array", {
|
|
443
|
+
value: val,
|
|
444
|
+
kind: typeof val
|
|
445
|
+
});
|
|
446
|
+
failed = true;
|
|
447
|
+
}
|
|
448
|
+
} catch {
|
|
449
|
+
pushError(field, "array", {
|
|
450
|
+
value: val,
|
|
451
|
+
kind: typeof val
|
|
452
|
+
});
|
|
453
|
+
failed = true;
|
|
454
|
+
}
|
|
455
|
+
else {
|
|
456
|
+
pushError(field, "array", {
|
|
457
|
+
value: val,
|
|
458
|
+
kind: typeof val
|
|
459
|
+
});
|
|
460
|
+
failed = true;
|
|
461
|
+
}
|
|
462
|
+
break;
|
|
463
|
+
case p === "json":
|
|
464
|
+
if (typeof val === "string") try {
|
|
465
|
+
val = JSON.parse(val);
|
|
466
|
+
} catch {
|
|
467
|
+
pushError(field, "json", {
|
|
468
|
+
value: val,
|
|
469
|
+
kind: typeof val
|
|
470
|
+
});
|
|
471
|
+
failed = true;
|
|
472
|
+
}
|
|
473
|
+
break;
|
|
474
|
+
case p === "date": {
|
|
475
|
+
const date = parseDate(val);
|
|
476
|
+
if (!date) {
|
|
477
|
+
pushError(field, "date", {
|
|
478
|
+
value: val,
|
|
479
|
+
kind: typeof val
|
|
480
|
+
});
|
|
481
|
+
failed = true;
|
|
482
|
+
} else val = date;
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
case p === "url":
|
|
486
|
+
try {
|
|
487
|
+
new URL(val);
|
|
488
|
+
} catch {
|
|
489
|
+
pushError(field, "url", {
|
|
490
|
+
value: val,
|
|
491
|
+
kind: typeof val
|
|
492
|
+
});
|
|
493
|
+
failed = true;
|
|
494
|
+
}
|
|
495
|
+
break;
|
|
496
|
+
case p === "uuid":
|
|
497
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(String(val))) {
|
|
498
|
+
pushError(field, "uuid", {
|
|
499
|
+
value: val,
|
|
500
|
+
kind: typeof val
|
|
501
|
+
});
|
|
502
|
+
failed = true;
|
|
503
|
+
}
|
|
504
|
+
break;
|
|
505
|
+
case p === "phone": {
|
|
506
|
+
const phoneRegex = /^(\+\d{1,3}[\s-]?)?([0-9]|\(\d{1,4}\))[\d\s-]{5,}$/;
|
|
507
|
+
const dc = String(val).replace(/[\s\-()]/g, "").replace(/\D/g, "").length;
|
|
508
|
+
if (!phoneRegex.test(String(val)) || dc < 7 || dc > 15) {
|
|
509
|
+
pushError(field, "phone", {
|
|
510
|
+
value: val,
|
|
511
|
+
kind: typeof val
|
|
512
|
+
});
|
|
513
|
+
failed = true;
|
|
514
|
+
}
|
|
515
|
+
break;
|
|
516
|
+
}
|
|
517
|
+
case p.startsWith("min:"):
|
|
518
|
+
await handleMinRule(field, val, p);
|
|
519
|
+
break;
|
|
520
|
+
case p.startsWith("max:"):
|
|
521
|
+
await handleMaxRule(field, val, p);
|
|
522
|
+
break;
|
|
523
|
+
case p.startsWith("size:"):
|
|
524
|
+
await handleSizeRule(field, val, p);
|
|
525
|
+
break;
|
|
526
|
+
case p.startsWith("between:"):
|
|
527
|
+
await handleBetweenRule(field, val, p);
|
|
528
|
+
break;
|
|
529
|
+
case p.startsWith("in:"):
|
|
530
|
+
await handleInRule(field, val, p);
|
|
531
|
+
break;
|
|
532
|
+
case p.startsWith("not_in:"):
|
|
533
|
+
await handleNotInRule(field, val, p);
|
|
534
|
+
break;
|
|
535
|
+
case p.startsWith("exists:"):
|
|
536
|
+
if (!((raw === void 0 || raw === null || raw === "") && parts.includes("nullable"))) await handleExistsRule(field, val, p);
|
|
537
|
+
break;
|
|
538
|
+
case p.startsWith("unique:"):
|
|
539
|
+
await handleUniqueRule(field, val, p);
|
|
540
|
+
break;
|
|
541
|
+
case p.startsWith("regex:"):
|
|
542
|
+
await handleRegexRule(field, val, p);
|
|
543
|
+
break;
|
|
544
|
+
case p.startsWith("starts_with:"):
|
|
545
|
+
await handleStartsWithRule(field, val, p);
|
|
546
|
+
break;
|
|
547
|
+
case p.startsWith("ends_with:"):
|
|
548
|
+
await handleEndsWithRule(field, val, p);
|
|
549
|
+
break;
|
|
550
|
+
case p.startsWith("contains:"):
|
|
551
|
+
await handleContainsRule(field, val, p);
|
|
552
|
+
break;
|
|
553
|
+
case p.startsWith("gt:"):
|
|
554
|
+
await handleComparisonRule(field, val, p, "gt", out);
|
|
555
|
+
break;
|
|
556
|
+
case p.startsWith("gte:"):
|
|
557
|
+
await handleComparisonRule(field, val, p, "gte", out);
|
|
558
|
+
break;
|
|
559
|
+
case p.startsWith("lt:"):
|
|
560
|
+
await handleComparisonRule(field, val, p, "lt", out);
|
|
561
|
+
break;
|
|
562
|
+
case p.startsWith("lte:"):
|
|
563
|
+
await handleComparisonRule(field, val, p, "lte", out);
|
|
564
|
+
break;
|
|
565
|
+
case p.startsWith("before:"):
|
|
566
|
+
await handleDateComparisonRule(field, val, p, "before", out);
|
|
567
|
+
break;
|
|
568
|
+
case p.startsWith("before_or_equal:"):
|
|
569
|
+
await handleDateComparisonRule(field, val, p, "before_or_equal", out);
|
|
570
|
+
break;
|
|
571
|
+
case p.startsWith("after:"):
|
|
572
|
+
await handleDateComparisonRule(field, val, p, "after", out);
|
|
573
|
+
break;
|
|
574
|
+
case p.startsWith("after_or_equal:"):
|
|
575
|
+
await handleDateComparisonRule(field, val, p, "after_or_equal", out);
|
|
576
|
+
break;
|
|
577
|
+
case p.startsWith("date_equals:"):
|
|
578
|
+
await handleDateComparisonRule(field, val, p, "date_equals", out);
|
|
579
|
+
break;
|
|
580
|
+
case p.startsWith("date_format:"):
|
|
581
|
+
await handleDateFormatRule(field, raw, p);
|
|
582
|
+
break;
|
|
583
|
+
case p === "time":
|
|
584
|
+
if (typeof val !== "string" || !/^\d{2}:\d{2}(:\d{2})?$/.test(val)) {
|
|
585
|
+
pushError(field, "time", { value: val });
|
|
586
|
+
failed = true;
|
|
587
|
+
}
|
|
588
|
+
break;
|
|
589
|
+
case p === "datetime": {
|
|
590
|
+
const dtVal = parseDate(val);
|
|
591
|
+
if (!dtVal) {
|
|
592
|
+
pushError(field, "datetime", { value: val });
|
|
593
|
+
failed = true;
|
|
594
|
+
} else val = dtVal;
|
|
595
|
+
break;
|
|
596
|
+
}
|
|
597
|
+
case p === "timezone":
|
|
598
|
+
try {
|
|
599
|
+
Intl.DateTimeFormat(void 0, { timeZone: String(val) });
|
|
600
|
+
} catch {
|
|
601
|
+
pushError(field, "timezone", { value: val });
|
|
602
|
+
failed = true;
|
|
603
|
+
}
|
|
604
|
+
break;
|
|
605
|
+
case p === "accepted":
|
|
606
|
+
if (![
|
|
607
|
+
true,
|
|
608
|
+
1,
|
|
609
|
+
"1",
|
|
610
|
+
"yes",
|
|
611
|
+
"on"
|
|
612
|
+
].includes(val)) {
|
|
613
|
+
pushError(field, "accepted", { value: val });
|
|
614
|
+
failed = true;
|
|
615
|
+
}
|
|
616
|
+
break;
|
|
617
|
+
case p === "declined":
|
|
618
|
+
if (![
|
|
619
|
+
false,
|
|
620
|
+
0,
|
|
621
|
+
"0",
|
|
622
|
+
"no",
|
|
623
|
+
"off"
|
|
624
|
+
].includes(val)) {
|
|
625
|
+
pushError(field, "declined", { value: val });
|
|
626
|
+
failed = true;
|
|
627
|
+
}
|
|
628
|
+
break;
|
|
629
|
+
case p === "confirmed": {
|
|
630
|
+
const cf = `${field}_confirmation`;
|
|
631
|
+
if (out && (out[cf] || out["confirmation_" + field] || out[field + "_confirmed"] || out["confirmed_" + field] || out["confirm_" + field]) !== val) {
|
|
632
|
+
pushError(field, "confirmed", { other: cf });
|
|
633
|
+
failed = true;
|
|
634
|
+
}
|
|
635
|
+
break;
|
|
636
|
+
}
|
|
637
|
+
case p.startsWith("different:"): {
|
|
638
|
+
const df = p.split(":")[1];
|
|
639
|
+
if (out && out[df] === val) {
|
|
640
|
+
pushError(field, "different", { other: df });
|
|
641
|
+
failed = true;
|
|
642
|
+
}
|
|
643
|
+
break;
|
|
644
|
+
}
|
|
645
|
+
case p.startsWith("same:"): {
|
|
646
|
+
const sf = p.split(":")[1];
|
|
647
|
+
if (out && out[sf] !== val) {
|
|
648
|
+
pushError(field, "same", { other: sf });
|
|
649
|
+
failed = true;
|
|
650
|
+
}
|
|
651
|
+
break;
|
|
652
|
+
}
|
|
653
|
+
default: break;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
if (!failed) setAtPath(out, field, val);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
function pushError(field, code, meta = {}) {
|
|
660
|
+
errors[field] = errors[field] || [];
|
|
661
|
+
errors[field].push(code);
|
|
662
|
+
metaErrors[field] = metaErrors[field] || [];
|
|
663
|
+
metaErrors[field].push({
|
|
664
|
+
code,
|
|
665
|
+
meta
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
for (const field of Object.keys(metaErrors)) for (const item of metaErrors[field]) {
|
|
669
|
+
const merged = {
|
|
670
|
+
...customMessages || {},
|
|
671
|
+
...fieldMessagesMap[field] || {}
|
|
672
|
+
};
|
|
673
|
+
const msg = resolveMessage(field, item.code, item.meta, merged);
|
|
674
|
+
messageErrors[field] = messageErrors[field] || [];
|
|
675
|
+
messageErrors[field].push(msg);
|
|
676
|
+
}
|
|
677
|
+
if (Object.keys(errors).length) throw new ValidationError(errors, messageErrors);
|
|
678
|
+
return out;
|
|
679
|
+
async function handleMinRule(field, val, rule) {
|
|
680
|
+
const arg = Number(rule.split(":")[1]);
|
|
681
|
+
if (typeof val === "number" && val < arg) pushError(field, "min", {
|
|
682
|
+
min: arg,
|
|
683
|
+
value: val,
|
|
684
|
+
kind: "numeric"
|
|
685
|
+
});
|
|
686
|
+
else if (typeof val === "string" && val.length < arg) pushError(field, "min", {
|
|
687
|
+
min: arg,
|
|
688
|
+
value: val,
|
|
689
|
+
kind: "string"
|
|
690
|
+
});
|
|
691
|
+
else if (Array.isArray(val) && val.length < arg) pushError(field, "min", {
|
|
692
|
+
min: arg,
|
|
693
|
+
value: val,
|
|
694
|
+
kind: "array"
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
async function handleMaxRule(field, val, rule) {
|
|
698
|
+
const arg = Number(rule.split(":")[1]);
|
|
699
|
+
if (typeof val === "number" && val > arg) pushError(field, "max", {
|
|
700
|
+
max: arg,
|
|
701
|
+
value: val,
|
|
702
|
+
kind: "numeric"
|
|
703
|
+
});
|
|
704
|
+
else if (typeof val === "string" && val.length > arg) pushError(field, "max", {
|
|
705
|
+
max: arg,
|
|
706
|
+
value: val,
|
|
707
|
+
kind: "string"
|
|
708
|
+
});
|
|
709
|
+
else if (Array.isArray(val) && val.length > arg) pushError(field, "max", {
|
|
710
|
+
max: arg,
|
|
711
|
+
value: val,
|
|
712
|
+
kind: "array"
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
async function handleSizeRule(field, val, rule) {
|
|
716
|
+
const arg = Number(rule.split(":")[1]);
|
|
717
|
+
if (typeof val === "number" && val !== arg) pushError(field, "size", {
|
|
718
|
+
size: arg,
|
|
719
|
+
value: val,
|
|
720
|
+
kind: "numeric"
|
|
721
|
+
});
|
|
722
|
+
else if (typeof val === "string" && val.length !== arg) pushError(field, "size", {
|
|
723
|
+
size: arg,
|
|
724
|
+
value: val,
|
|
725
|
+
kind: "string"
|
|
726
|
+
});
|
|
727
|
+
else if (Array.isArray(val) && val.length !== arg) pushError(field, "size", {
|
|
728
|
+
size: arg,
|
|
729
|
+
value: val,
|
|
730
|
+
kind: "array"
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
async function handleBetweenRule(field, val, rule) {
|
|
734
|
+
const [min, max] = rule.split(":")[1].split(",").map(Number);
|
|
735
|
+
if (typeof val === "number" && (val < min || val > max)) pushError(field, "between", {
|
|
736
|
+
min,
|
|
737
|
+
max,
|
|
738
|
+
value: val,
|
|
739
|
+
kind: "numeric"
|
|
740
|
+
});
|
|
741
|
+
else if (typeof val === "string" && (val.length < min || val.length > max)) pushError(field, "between", {
|
|
742
|
+
min,
|
|
743
|
+
max,
|
|
744
|
+
value: val,
|
|
745
|
+
kind: "string"
|
|
746
|
+
});
|
|
747
|
+
else if (Array.isArray(val) && (val.length < min || val.length > max)) pushError(field, "between", {
|
|
748
|
+
min,
|
|
749
|
+
max,
|
|
750
|
+
value: val,
|
|
751
|
+
kind: "array"
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
async function handleInRule(field, val, rule) {
|
|
755
|
+
const opts = rule.split(":")[1].split(",").map((s) => s.trim());
|
|
756
|
+
if (!opts.includes(String(val))) pushError(field, "in", {
|
|
757
|
+
value: val,
|
|
758
|
+
values: opts.join(", ")
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
async function handleNotInRule(field, val, rule) {
|
|
762
|
+
const opts = rule.split(":")[1].split(",").map((s) => s.trim());
|
|
763
|
+
if (opts.includes(String(val))) pushError(field, "not_in", {
|
|
764
|
+
value: val,
|
|
765
|
+
values: opts.join(", ")
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
async function handleExistsRule(field, val, rule) {
|
|
769
|
+
try {
|
|
770
|
+
let [table, column] = rule.split(":")[1].split(",");
|
|
771
|
+
table = (table || "").trim();
|
|
772
|
+
column = (column || "id").trim();
|
|
773
|
+
class VM extends Model {
|
|
774
|
+
static {
|
|
775
|
+
this.table = table;
|
|
776
|
+
}
|
|
777
|
+
static {
|
|
778
|
+
this.primaryKey = "id";
|
|
779
|
+
}
|
|
780
|
+
static {
|
|
781
|
+
this.fillable = [column];
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
if (!await VM.query().where(column, "=", val).exists()) pushError(field, "exists", {
|
|
785
|
+
value: val,
|
|
786
|
+
table,
|
|
787
|
+
column
|
|
788
|
+
});
|
|
789
|
+
} catch {
|
|
790
|
+
pushError(field, "exists", { value: val });
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
async function handleUniqueRule(field, val, rule) {
|
|
794
|
+
try {
|
|
795
|
+
const partsSpec = rule.split(":")[1].split(",").map((s) => s.trim());
|
|
796
|
+
const table = partsSpec[0];
|
|
797
|
+
const column = partsSpec[1] || "id";
|
|
798
|
+
const exceptArg = partsSpec[2];
|
|
799
|
+
const exceptArg2 = partsSpec[3];
|
|
800
|
+
class VM extends Model {
|
|
801
|
+
static {
|
|
802
|
+
this.table = table;
|
|
803
|
+
}
|
|
804
|
+
static {
|
|
805
|
+
this.primaryKey = "id";
|
|
806
|
+
}
|
|
807
|
+
static {
|
|
808
|
+
this.fillable = [column];
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
let exceptColumn = VM.primaryKey, exceptValue = exceptArg;
|
|
812
|
+
if (exceptArg2 !== void 0) {
|
|
813
|
+
exceptColumn = exceptArg;
|
|
814
|
+
exceptValue = exceptArg2;
|
|
815
|
+
}
|
|
816
|
+
let q = VM.query().where(column, "=", val);
|
|
817
|
+
if (exceptValue !== void 0 && exceptValue !== null && String(exceptValue) !== "") q = q.where(function(query) {
|
|
818
|
+
query.where(exceptColumn, "!=", exceptValue);
|
|
819
|
+
});
|
|
820
|
+
if (await q.exists()) pushError(field, "unique", {
|
|
821
|
+
value: val,
|
|
822
|
+
table,
|
|
823
|
+
column
|
|
824
|
+
});
|
|
825
|
+
} catch {
|
|
826
|
+
pushError(field, "unique", { value: val });
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
async function handleRegexRule(field, val, rule) {
|
|
830
|
+
const pattern = rule.split(":")[1];
|
|
831
|
+
try {
|
|
832
|
+
if (!new RegExp(pattern).test(String(val))) pushError(field, "regex", {
|
|
833
|
+
value: val,
|
|
834
|
+
pattern
|
|
835
|
+
});
|
|
836
|
+
} catch {
|
|
837
|
+
pushError(field, "regex_invalid", {
|
|
838
|
+
value: val,
|
|
839
|
+
pattern
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
async function handleStartsWithRule(field, val, rule) {
|
|
844
|
+
const prefixes = rule.split(":")[1].split(",").map((s) => s.trim());
|
|
845
|
+
if (!prefixes.some((p2) => String(val).startsWith(p2))) pushError(field, "starts_with", {
|
|
846
|
+
value: val,
|
|
847
|
+
prefixes: prefixes.join(", ")
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
async function handleEndsWithRule(field, val, rule) {
|
|
851
|
+
const suffixes = rule.split(":")[1].split(",").map((s) => s.trim());
|
|
852
|
+
if (!suffixes.some((s) => String(val).endsWith(s))) pushError(field, "ends_with", {
|
|
853
|
+
value: val,
|
|
854
|
+
suffixes: suffixes.join(", ")
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
async function handleContainsRule(field, val, rule) {
|
|
858
|
+
const substring = rule.split(":")[1];
|
|
859
|
+
if (!String(val).includes(substring)) pushError(field, "contains", {
|
|
860
|
+
value: val,
|
|
861
|
+
substring
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
async function handleComparisonRule(field, val, rule, operator, payload) {
|
|
865
|
+
const otherField = rule.split(":")[1];
|
|
866
|
+
const otherValue = payload ? getAtPath(payload, otherField) : void 0;
|
|
867
|
+
if (otherValue === void 0) return;
|
|
868
|
+
const numVal = Number(val), numOther = Number(otherValue);
|
|
869
|
+
if (!isNaN(numVal) && !isNaN(numOther)) {
|
|
870
|
+
if (!(operator === "gt" ? numVal > numOther : operator === "gte" ? numVal >= numOther : operator === "lt" ? numVal < numOther : numVal <= numOther)) pushError(field, operator, {
|
|
871
|
+
field: otherField,
|
|
872
|
+
value: val,
|
|
873
|
+
other: otherValue
|
|
874
|
+
});
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
const dv = parseDate(val), dOther = parseDate(otherValue);
|
|
878
|
+
if (dv && dOther) {
|
|
879
|
+
const tv = dv.getTime(), to = dOther.getTime();
|
|
880
|
+
if (!(operator === "gt" ? tv > to : operator === "gte" ? tv >= to : operator === "lt" ? tv < to : tv <= to)) pushError(field, operator, {
|
|
881
|
+
field: otherField,
|
|
882
|
+
value: val,
|
|
883
|
+
other: otherValue
|
|
884
|
+
});
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
const sv = String(val), so = String(otherValue);
|
|
888
|
+
if (!(operator === "gt" ? sv > so : operator === "gte" ? sv >= so : operator === "lt" ? sv < so : sv <= so)) pushError(field, operator, {
|
|
889
|
+
field: otherField,
|
|
890
|
+
value: val,
|
|
891
|
+
other: otherValue
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
async function handleDateComparisonRule(field, val, rule, operator, payload) {
|
|
895
|
+
const otherField = rule.split(":")[1];
|
|
896
|
+
let otherRaw = payload ? getAtPath(payload, otherField) : void 0;
|
|
897
|
+
if (otherRaw === void 0) otherRaw = otherField;
|
|
898
|
+
if (typeof otherRaw === "string") {
|
|
899
|
+
const lower = otherRaw.toLowerCase().trim();
|
|
900
|
+
if (lower === "today") {
|
|
901
|
+
const t = /* @__PURE__ */ new Date();
|
|
902
|
+
t.setHours(0, 0, 0, 0);
|
|
903
|
+
otherRaw = t;
|
|
904
|
+
} else if (lower === "yesterday") {
|
|
905
|
+
const t = /* @__PURE__ */ new Date();
|
|
906
|
+
t.setDate(t.getDate() - 1);
|
|
907
|
+
t.setHours(0, 0, 0, 0);
|
|
908
|
+
otherRaw = t;
|
|
909
|
+
} else if (lower === "tomorrow") {
|
|
910
|
+
const t = /* @__PURE__ */ new Date();
|
|
911
|
+
t.setDate(t.getDate() + 1);
|
|
912
|
+
t.setHours(0, 0, 0, 0);
|
|
913
|
+
otherRaw = t;
|
|
914
|
+
} else {
|
|
915
|
+
const rm = lower.match(/^(today|yesterday|tomorrow|now)([+-])(\d+)(days?|weeks?|months?|years?)$/);
|
|
916
|
+
if (rm) {
|
|
917
|
+
const [, anchor, sign, numStr, unit] = rm;
|
|
918
|
+
const n = parseInt(numStr, 10) * (sign === "+" ? 1 : -1);
|
|
919
|
+
const t = /* @__PURE__ */ new Date();
|
|
920
|
+
t.setHours(0, 0, 0, 0);
|
|
921
|
+
if (anchor === "yesterday") t.setDate(t.getDate() - 1);
|
|
922
|
+
if (anchor === "tomorrow") t.setDate(t.getDate() + 1);
|
|
923
|
+
if (unit.startsWith("day")) t.setDate(t.getDate() + n);
|
|
924
|
+
if (unit.startsWith("week")) t.setDate(t.getDate() + n * 7);
|
|
925
|
+
if (unit.startsWith("month")) t.setMonth(t.getMonth() + n);
|
|
926
|
+
if (unit.startsWith("year")) t.setFullYear(t.getFullYear() + n);
|
|
927
|
+
otherRaw = t;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
const dv = parseDate(val), dOther = parseDate(otherRaw);
|
|
932
|
+
if (!dv) {
|
|
933
|
+
pushError(field, "date", { value: val });
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
if (!dOther) return;
|
|
937
|
+
const tv = dv.getTime(), to = dOther.getTime();
|
|
938
|
+
if (!(operator === "before" ? tv < to : operator === "before_or_equal" ? tv <= to : operator === "after" ? tv > to : operator === "after_or_equal" ? tv >= to : tv === to)) pushError(field, operator, {
|
|
939
|
+
field: otherField,
|
|
940
|
+
value: val,
|
|
941
|
+
other: otherRaw
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
async function handleDateFormatRule(field, val, rule) {
|
|
945
|
+
const format = rule.slice(12);
|
|
946
|
+
const strVal = String(val);
|
|
947
|
+
const tokenMap = {
|
|
948
|
+
YYYY: "\\d{4}",
|
|
949
|
+
YY: "\\d{2}",
|
|
950
|
+
MM: "(?:0[1-9]|1[0-2])",
|
|
951
|
+
DD: "(?:0[1-9]|[12]\\d|3[01])",
|
|
952
|
+
HH: "(?:[01]\\d|2[0-3])",
|
|
953
|
+
mm: "[0-5]\\d",
|
|
954
|
+
ss: "[0-5]\\d",
|
|
955
|
+
SSS: "\\d{3}",
|
|
956
|
+
Z: "(?:Z|[+-]\\d{2}:\\d{2})"
|
|
957
|
+
};
|
|
958
|
+
let pattern = format.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
959
|
+
for (const token of Object.keys(tokenMap).sort((a, b) => b.length - a.length)) pattern = pattern.replace(new RegExp(token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), tokenMap[token]);
|
|
960
|
+
if (!new RegExp("^" + pattern + "$").test(strVal)) pushError(field, "date_format", {
|
|
961
|
+
value: val,
|
|
962
|
+
format
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
const requiredIf = (otherField, value) => async (val, _field, payload) => {
|
|
967
|
+
if (payload && payload[otherField] === value) {
|
|
968
|
+
if (val === void 0 || val === null || val === "") return {
|
|
969
|
+
ok: false,
|
|
970
|
+
message: "required"
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
return true;
|
|
974
|
+
};
|
|
975
|
+
const requiredUnless = (otherField, value) => async (val, _field, payload) => {
|
|
976
|
+
if (payload && payload[otherField] !== value) {
|
|
977
|
+
if (val === void 0 || val === null || val === "") return {
|
|
978
|
+
ok: false,
|
|
979
|
+
message: "required"
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
return true;
|
|
983
|
+
};
|
|
984
|
+
const fileRule = async (value) => {
|
|
985
|
+
if (!value) return true;
|
|
986
|
+
if (typeof value === "object" && (value instanceof File || "name" in value && "size" in value)) return true;
|
|
987
|
+
return {
|
|
988
|
+
ok: false,
|
|
989
|
+
message: "file"
|
|
990
|
+
};
|
|
991
|
+
};
|
|
992
|
+
const mimes = (allowedTypes) => async (value) => {
|
|
993
|
+
if (!value) return true;
|
|
994
|
+
const extension = (typeof value === "string" ? value : value?.name || "").split(".").pop()?.toLowerCase() || "";
|
|
995
|
+
const mimeTypes = {
|
|
996
|
+
jpg: ["image/jpeg"],
|
|
997
|
+
jpeg: ["image/jpeg"],
|
|
998
|
+
png: ["image/png"],
|
|
999
|
+
gif: ["image/gif"],
|
|
1000
|
+
pdf: ["application/pdf"],
|
|
1001
|
+
doc: ["application/msword"],
|
|
1002
|
+
docx: ["application/vnd.openxmlformats-officedocument.wordprocessingml.document"]
|
|
1003
|
+
};
|
|
1004
|
+
if (!allowedTypes.map((type) => {
|
|
1005
|
+
for (const [ext, mimes2] of Object.entries(mimeTypes)) if (mimes2.includes(type)) return ext;
|
|
1006
|
+
return type.split("/").pop();
|
|
1007
|
+
}).filter(Boolean).includes(extension)) return {
|
|
1008
|
+
ok: false,
|
|
1009
|
+
message: "mimes",
|
|
1010
|
+
value: allowedTypes.join(", ")
|
|
1011
|
+
};
|
|
1012
|
+
return true;
|
|
1013
|
+
};
|
|
1014
|
+
const maxFileSize = (maxSizeInMB) => async (value) => {
|
|
1015
|
+
if (!value) return true;
|
|
1016
|
+
if ((value instanceof File ? value.size : value?.size || 0) > maxSizeInMB * 1024 * 1024) return {
|
|
1017
|
+
ok: false,
|
|
1018
|
+
message: "max_file_size",
|
|
1019
|
+
value: maxSizeInMB
|
|
1020
|
+
};
|
|
1021
|
+
return true;
|
|
1022
|
+
};
|
|
1023
|
+
const phoneRule = (value) => {
|
|
1024
|
+
if (!value) return true;
|
|
1025
|
+
const phoneRegex = /^(\+\d{1,3}[\s-]?)?([0-9]|\(\d{1,4}\))[\d\s-]{5,}$/;
|
|
1026
|
+
const dc = String(value).replace(/[\s\-()]/g, "").replace(/\D/g, "").length;
|
|
1027
|
+
if (!phoneRegex.test(String(value)) || dc < 7 || dc > 15) return {
|
|
1028
|
+
ok: false,
|
|
1029
|
+
message: "phone"
|
|
1030
|
+
};
|
|
1031
|
+
return true;
|
|
1032
|
+
};
|
|
1033
|
+
const creditCardRule = (value) => {
|
|
1034
|
+
if (!value) return true;
|
|
1035
|
+
const str = String(value).replace(/\s+/g, "");
|
|
1036
|
+
if (!/^\d+$/.test(str)) return {
|
|
1037
|
+
ok: false,
|
|
1038
|
+
message: "credit_card"
|
|
1039
|
+
};
|
|
1040
|
+
let sum = 0, isEven = false;
|
|
1041
|
+
for (let i = str.length - 1; i >= 0; i--) {
|
|
1042
|
+
let digit = parseInt(str.charAt(i), 10);
|
|
1043
|
+
if (isEven) {
|
|
1044
|
+
digit *= 2;
|
|
1045
|
+
if (digit > 9) digit -= 9;
|
|
1046
|
+
}
|
|
1047
|
+
sum += digit;
|
|
1048
|
+
isEven = !isEven;
|
|
1049
|
+
}
|
|
1050
|
+
if (sum % 10 !== 0) return {
|
|
1051
|
+
ok: false,
|
|
1052
|
+
message: "credit_card"
|
|
1053
|
+
};
|
|
1054
|
+
return true;
|
|
1055
|
+
};
|
|
1056
|
+
const nestedRule = (rules) => async (value) => {
|
|
1057
|
+
if (value === void 0 || value === null) return true;
|
|
1058
|
+
if (typeof value !== "object" || Array.isArray(value)) return {
|
|
1059
|
+
ok: false,
|
|
1060
|
+
message: "object"
|
|
1061
|
+
};
|
|
1062
|
+
try {
|
|
1063
|
+
await validate(value, rules);
|
|
1064
|
+
return true;
|
|
1065
|
+
} catch {
|
|
1066
|
+
return {
|
|
1067
|
+
ok: false,
|
|
1068
|
+
message: "nested_validation_failed"
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
};
|
|
1072
|
+
const arrayOfObjectsRule = (rules) => async (value) => {
|
|
1073
|
+
if (value === void 0 || value === null) return true;
|
|
1074
|
+
let array;
|
|
1075
|
+
if (Array.isArray(value)) array = value;
|
|
1076
|
+
else if (typeof value === "string") try {
|
|
1077
|
+
const p = JSON.parse(value);
|
|
1078
|
+
array = Array.isArray(p) ? p : [p];
|
|
1079
|
+
} catch {
|
|
1080
|
+
return {
|
|
1081
|
+
ok: false,
|
|
1082
|
+
message: "array"
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
else array = [value];
|
|
1086
|
+
for (let i = 0; i < array.length; i++) {
|
|
1087
|
+
if (typeof array[i] !== "object" || Array.isArray(array[i])) return {
|
|
1088
|
+
ok: false,
|
|
1089
|
+
message: "object_array"
|
|
1090
|
+
};
|
|
1091
|
+
try {
|
|
1092
|
+
await validate(array[i], rules);
|
|
1093
|
+
} catch {
|
|
1094
|
+
return {
|
|
1095
|
+
ok: false,
|
|
1096
|
+
message: `items[${i}].validation_failed`
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
return {
|
|
1101
|
+
ok: true,
|
|
1102
|
+
value: array
|
|
1103
|
+
};
|
|
1104
|
+
};
|
|
1105
|
+
//#endregion
|
|
1106
|
+
export { ValidationError, arrayOfObjectsRule, creditCardRule, fileRule, formatMessage, maxFileSize, mimes, nestedRule, phoneRule, requiredIf, requiredUnless, resolveMessage, validate };
|
|
1107
|
+
|
|
1108
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { Model } from \"@lara-node/db\";\n\nexport class ValidationError extends Error {\n errors: Record<string, string[]>;\n messages: Record<string, string[]>;\n message: string;\n\n constructor(errors: Record<string, string[]>, messages?: Record<string, string[]>) {\n super(\"Validation failed\");\n this.errors = errors;\n this.messages = messages || {};\n this.message = \"unknown error\";\n const totalErrors = Object.values(this.messages).reduce(\n (sum, currentArray) => sum + currentArray.length,\n 0,\n );\n const firstError = Object.values(this.messages).find((arr) => arr.length > 0)?.[0];\n if (firstError) {\n if (totalErrors > 1) {\n this.message = `${firstError} and ${totalErrors - 1} more error(s).`;\n } else {\n this.message = firstError;\n }\n }\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\nexport type RuleFn = (\n value: any,\n field: string,\n payload?: any,\n) => true | { ok: boolean; message?: string; value?: any } | false | Promise<any>;\n\nexport type RuleSpec =\n | string\n | RuleFn\n | { rule: string | RuleFn; messages?: Record<string, string> };\n\nconst defaultMessages: Record<string, string> = {\n required: \":attribute field is required.\",\n integer: \":attribute must be an integer.\",\n numeric: \":attribute must be a number.\",\n array: \":attribute must be an array.\",\n json: \":attribute must be valid JSON.\",\n email: \":attribute must be a valid email address.\",\n boolean: \":attribute must be true or false.\",\n date: \":attribute must be a valid date.\",\n url: \":attribute must be a valid URL.\",\n uuid: \":attribute must be a valid UUID.\",\n object: \":attribute must be an object.\",\n \"min.numeric\": \":attribute must be at least :min.\",\n \"min.string\": \":attribute must be at least :min characters.\",\n \"min.array\": \":attribute must have at least :min items.\",\n \"max.numeric\": \":attribute may not be greater than :max.\",\n \"max.string\": \":attribute may not be greater than :max characters.\",\n \"max.array\": \":attribute may not have more than :max items.\",\n \"size.string\": \":attribute must be exactly :size characters.\",\n \"size.array\": \":attribute must contain exactly :size items.\",\n \"size.numeric\": \":attribute must be exactly :size.\",\n \"between.numeric\": \":attribute must be between :min and :max.\",\n \"between.string\": \":attribute must be between :min and :max characters.\",\n \"between.array\": \":attribute must have between :min and :max items.\",\n regex: \":attribute format is invalid.\",\n regex_invalid: \"Invalid regex pattern for :attribute validation.\",\n phone: \":attribute must be a valid phone number.\",\n credit_card: \":attribute must be a valid credit card number.\",\n in: \":attribute must be one of: :values.\",\n not_in: \":attribute must not be one of: :values.\",\n exists: \"Selected :attribute is invalid.\",\n unique: \":attribute has already been taken.\",\n starts_with: \":attribute must start with one of: :prefixes.\",\n ends_with: \":attribute must end with one of: :suffixes.\",\n contains: \":attribute must contain :substring.\",\n accepted: \":attribute must be accepted.\",\n declined: \":attribute must be declined.\",\n confirmed: \":attribute confirmation does not match.\",\n different: \":attribute and :other must be different.\",\n same: \":attribute and :other must be the same.\",\n gt: \":attribute must be greater than :field.\",\n gte: \":attribute must be greater than or equal to :field.\",\n lt: \":attribute must be less than :field.\",\n lte: \":attribute must be less than or equal to :field.\",\n before: \":attribute must be a date before :field.\",\n before_or_equal: \":attribute must be a date before or equal to :field.\",\n after: \":attribute must be a date after :field.\",\n after_or_equal: \":attribute must be a date after or equal to :field.\",\n date_equals: \":attribute must be the same date as :field.\",\n date_format: \":attribute does not match the format :format.\",\n time: \":attribute must be a valid time (HH:MM or HH:MM:SS).\",\n datetime: \":attribute must be a valid date and time.\",\n timezone: \":attribute must be a valid timezone.\",\n file: \":attribute must be a file.\",\n mimes: \":attribute must be a file of type: :values.\",\n max_file_size: \":attribute may not be larger than :max MB.\",\n required_if: \":attribute is required.\",\n required_unless: \":attribute is required.\",\n required_with: \":attribute is required when :values is present.\",\n required_with_all: \":attribute is required when :values are all present.\",\n required_without: \":attribute is required when :values is not present.\",\n required_without_all: \":attribute is required when none of :values are present.\",\n present: \":attribute field must be present.\",\n invalid: \":attribute is invalid.\",\n nested_validation_failed: \":attribute contains invalid data.\",\n object_array: \":attribute must be an array of objects.\",\n};\n\nfunction parseDate(val: any): Date | null {\n if (val instanceof Date) return isNaN(val.getTime()) ? null : val;\n const str = String(val).trim();\n const patterns: Array<{ re: RegExp; y: number; m: number; d: number }> = [\n { re: /^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{2,4})$/, y: 3, m: 2, d: 1 },\n { re: /^(\\d{1,2})-(\\d{1,2})-(\\d{2,4})$/, y: 3, m: 2, d: 1 },\n { re: /^(\\d{1,2})\\.(\\d{1,2})\\.(\\d{2,4})$/, y: 3, m: 2, d: 1 },\n { re: /^(\\d{4})\\/(\\d{1,2})\\/(\\d{1,2})$/, y: 1, m: 2, d: 3 },\n { re: /^(\\d{4})\\.(\\d{1,2})\\.(\\d{1,2})$/, y: 1, m: 2, d: 3 },\n ];\n for (const { re, y, m, d } of patterns) {\n const match = str.match(re);\n if (match) {\n let year = parseInt(match[y], 10);\n if (year < 100) year += year < 70 ? 2000 : 1900;\n const month = parseInt(match[m], 10) - 1;\n const day = parseInt(match[d], 10);\n const dt = new Date(year, month, day);\n if (!isNaN(dt.getTime()) && dt.getMonth() === month) return dt;\n }\n }\n const native = new Date(str);\n if (!isNaN(native.getTime())) return native;\n return null;\n}\n\nexport function formatMessage(template: string, ctx: Record<string, any>): string {\n return template.replace(/:([a-zA-Z_]+)/g, (_, key) =>\n ctx[key] !== undefined ? String(ctx[key]) : \":\" + key,\n );\n}\n\nexport function resolveMessage(\n field: string,\n code: string,\n meta: Record<string, any>,\n custom?: Record<string, string>,\n): string {\n let variantCode = code;\n if ([\"min\", \"max\", \"size\", \"between\"].includes(code) && meta.kind) {\n variantCode = `${code}.${meta.kind}`;\n }\n const attrLabel = custom && custom[`attributes.${field}`] ? custom[`attributes.${field}`] : field;\n const candidates = [`${field}.${variantCode}`, `${field}.${code}`, variantCode, code];\n for (const c of candidates) {\n if (custom && custom[c]) return formatMessage(custom[c], { ...meta, attribute: attrLabel });\n if (defaultMessages[c]) return formatMessage(defaultMessages[c], { ...meta, attribute: attrLabel });\n }\n return formatMessage(defaultMessages.invalid || \"Invalid value\", { ...meta, attribute: attrLabel });\n}\n\nexport async function validate<T extends Record<string, any>>(\n payload: any,\n rules: Record<string, RuleSpec>,\n customMessages?: Record<string, string>,\n): Promise<T> {\n const out = { ...(payload || {}) } as unknown as T & Record<string, any>;\n const errors: Record<string, string[]> = {};\n const messageErrors: Record<string, string[]> = {};\n const metaErrors: Record<string, { code: string; meta: Record<string, any> }[]> = {};\n const fieldMessagesMap: Record<string, Record<string, string>> = {};\n\n function normalizePattern(p: string) {\n return p\n .replace(/\\.\\.+/g, \".*\")\n .replace(/(^|\\.)\\*(\\.|$)/g, (_, a, b) => \"*\" + (b ? \".\" : \"\"))\n .replace(/\\.\\*/g, \".*\");\n }\n\n function splitSegments(pattern: string) {\n return pattern.split(\".\").map((s) => (s === \"\" ? \"*\" : s));\n }\n\n function getAtPath(obj: any, path: string) {\n if (!obj) return undefined;\n const segs = path.split(\".\");\n let cur = obj;\n for (const s of segs) {\n if (cur === undefined || cur === null) return undefined;\n if (/^\\d+$/.test(s)) {\n cur = cur[Number(s)];\n } else {\n cur = cur[s];\n }\n }\n return cur;\n }\n\n function setAtPath(obj: any, path: string, value: any) {\n const segs = path.split(\".\");\n let cur = obj;\n for (let i = 0; i < segs.length; i++) {\n const s = segs[i];\n const isLast = i === segs.length - 1;\n const numeric = /^\\d+$/.test(s);\n const key: any = numeric ? Number(s) : s;\n if (isLast) { cur[key] = value; return; }\n if (cur[key] === undefined || cur[key] === null) {\n const nextSeg = segs[i + 1];\n cur[key] = /^\\d+$/.test(nextSeg) ? [] : {};\n }\n cur = cur[key];\n }\n }\n\n function expandFieldPaths(obj: any, pattern: string): string[] {\n if (!pattern) return [];\n const normalized = normalizePattern(pattern);\n const segs = splitSegments(normalized);\n const results: string[] = [];\n\n function recurse(current: any, idx: number, prefix: string) {\n if (idx >= segs.length) { results.push(prefix.replace(/^\\./, \"\")); return; }\n const seg = segs[idx];\n if (seg === \"*\" || seg === \"\") {\n if (Array.isArray(current)) {\n for (let i = 0; i < current.length; i++) recurse(current[i], idx + 1, prefix + \".\" + i);\n } else if (current && typeof current === \"object\") {\n for (const k of Object.keys(current)) recurse(current[k], idx + 1, prefix + \".\" + k);\n } else {\n const parentPath = prefix.replace(/^\\./, \"\");\n let parentVal: any = undefined;\n try { parentVal = parentPath ? getAtPath(obj, parentPath) : obj; } catch { parentVal = undefined; }\n if (typeof parentVal === \"string\") {\n try {\n const parsed = JSON.parse(parentVal);\n if (Array.isArray(parsed)) {\n for (let i = 0; i < parsed.length; i++) recurse(parsed[i], idx + 1, prefix + \".\" + i);\n return;\n }\n } catch {}\n if (parentVal.includes(\",\")) {\n const parts = parentVal.split(\",\").map((s: string) => s.trim()).filter(Boolean);\n for (let i = 0; i < parts.length; i++) recurse(parts[i], idx + 1, prefix + \".\" + i);\n return;\n }\n }\n recurse(undefined, idx + 1, prefix + \".*\");\n }\n } else {\n if (current && (typeof current === \"object\" || Array.isArray(current)) && seg in current) {\n recurse(current[seg], idx + 1, prefix + \".\" + seg);\n } else if (current && Array.isArray(current) && /^\\d+$/.test(seg)) {\n recurse(current[Number(seg)], idx + 1, prefix + \".\" + seg);\n } else {\n recurse(undefined, idx + 1, prefix + \".\" + seg);\n }\n }\n }\n\n recurse(obj, 0, \"\");\n if (results.length === 0) {\n if (!pattern.includes(\"*\")) return [pattern];\n return [];\n }\n return Array.from(new Set(results));\n }\n\n for (const fieldPattern of Object.keys(rules)) {\n const spec = rules[fieldPattern];\n let fieldRule: string | RuleFn;\n\n if (typeof spec === \"object\" && spec && typeof spec !== \"function\" && \"rule\" in spec) {\n fieldRule = spec.rule as any;\n if (spec.messages) {\n const prefixed: Record<string, string> = {};\n for (const [k, v] of Object.entries(spec.messages)) {\n prefixed[k.startsWith(fieldPattern + \".\") ? k : `${fieldPattern}.${k}`] = v;\n }\n fieldMessagesMap[fieldPattern] = prefixed;\n }\n } else {\n fieldRule = spec as any;\n }\n\n const targetPaths = expandFieldPaths(out, fieldPattern);\n if (fieldPattern.includes(\"*\") && targetPaths.length === 0) continue;\n\n let pathsToValidate: string[] = [];\n for (const tp of targetPaths.length ? targetPaths : [fieldPattern]) {\n if (tp.includes(\".*\") || tp.includes(\"*\")) {\n const parentPath = tp.replace(/\\.(?:\\*|\\.)+$/, \"\").replace(/\\*$/, \"\");\n const parentVal = parentPath ? getAtPath(out, parentPath) : out;\n if (Array.isArray(parentVal)) {\n for (let i = 0; i < parentVal.length; i++) pathsToValidate.push(`${parentPath}.${i}`);\n continue;\n }\n if (typeof parentVal === \"string\") {\n try {\n const parsed = JSON.parse(parentVal);\n if (Array.isArray(parsed)) {\n for (let i = 0; i < parsed.length; i++) pathsToValidate.push(`${parentPath}.${i}`);\n continue;\n }\n } catch {}\n if (parentVal.includes(\",\")) {\n const parts = parentVal.split(\",\").map((s: string) => s.trim()).filter(Boolean);\n for (let i = 0; i < parts.length; i++) pathsToValidate.push(`${parentPath}.${i}`);\n continue;\n }\n }\n pathsToValidate.push(tp);\n } else {\n pathsToValidate.push(tp);\n }\n }\n\n for (const field of pathsToValidate) {\n const raw = getAtPath(out, field);\n\n if (typeof fieldRule === \"function\") {\n const res = await (fieldRule as RuleFn)(raw, field, out);\n if (res === true) continue;\n if (res === false) { pushError(field, \"invalid\", { value: raw, kind: typeof raw }); continue; }\n if (res && (res as any).ok === false) {\n pushError(field, (res as any).message || \"invalid\", { value: raw, kind: typeof raw });\n continue;\n }\n if (res && (res as any).ok === true && \"value\" in (res as any)) {\n setAtPath(out, field, (res as any).value);\n continue;\n }\n continue;\n }\n\n const parts = String(fieldRule).split(\"|\").map((s) => s.trim()).filter(Boolean);\n const isRequired = parts.includes(\"required\");\n const isNullable = parts.includes(\"nullable\");\n const isSometimes = parts.includes(\"sometimes\");\n const isPresent = parts.includes(\"present\");\n const present = raw !== undefined && raw !== null && raw !== \"\";\n\n let conditionalRequired = false;\n for (const p of parts) {\n if (p.startsWith(\"required_if:\")) {\n const [condField, ...values] = p.slice(\"required_if:\".length).split(\",\").map((s) => s.trim());\n if (values.some((v) => v === String(getAtPath(out, condField) ?? \"\"))) conditionalRequired = true;\n } else if (p.startsWith(\"required_unless:\")) {\n const [condField, ...values] = p.slice(\"required_unless:\".length).split(\",\").map((s) => s.trim());\n if (!values.some((v) => v === String(getAtPath(out, condField) ?? \"\"))) conditionalRequired = true;\n } else if (p.startsWith(\"required_with:\")) {\n const fields = p.slice(\"required_with:\".length).split(\",\").map((s) => s.trim());\n if (fields.some((f) => { const v = getAtPath(out, f); return v !== undefined && v !== null && v !== \"\"; })) conditionalRequired = true;\n } else if (p.startsWith(\"required_with_all:\")) {\n const fields = p.slice(\"required_with_all:\".length).split(\",\").map((s) => s.trim());\n if (fields.every((f) => { const v = getAtPath(out, f); return v !== undefined && v !== null && v !== \"\"; })) conditionalRequired = true;\n } else if (p.startsWith(\"required_without:\")) {\n const fields = p.slice(\"required_without:\".length).split(\",\").map((s) => s.trim());\n if (fields.some((f) => { const v = getAtPath(out, f); return v === undefined || v === null || v === \"\"; })) conditionalRequired = true;\n } else if (p.startsWith(\"required_without_all:\")) {\n const fields = p.slice(\"required_without_all:\".length).split(\",\").map((s) => s.trim());\n if (fields.every((f) => { const v = getAtPath(out, f); return v === undefined || v === null || v === \"\"; })) conditionalRequired = true;\n }\n }\n\n const effectiveRequired = isRequired || conditionalRequired;\n if (isSometimes && !present) continue;\n if (isPresent && raw === undefined) { pushError(field, \"present\", { value: raw }); continue; }\n if (effectiveRequired && !present) { pushError(field, \"required\", { value: raw }); continue; }\n if (!present && (isNullable || !effectiveRequired)) continue;\n\n let val: any = raw;\n let failed = false;\n\n for (const p of parts) {\n if ([\"required\", \"nullable\", \"sometimes\", \"present\"].includes(p)) continue;\n if (p.startsWith(\"required_if:\") || p.startsWith(\"required_unless:\") ||\n p.startsWith(\"required_with:\") || p.startsWith(\"required_with_all:\") ||\n p.startsWith(\"required_without:\") || p.startsWith(\"required_without_all:\")) continue;\n if (failed) break;\n\n switch (true) {\n case p === \"string\":\n if (typeof val !== \"string\") val = String(val);\n break;\n case p === \"email\": {\n if (typeof val !== \"string\") val = String(val);\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(val)) { pushError(field, \"email\", { value: val, kind: \"string\" }); failed = true; }\n break;\n }\n case p === \"int\" || p === \"integer\": {\n const intVal = parseInt(val, 10);\n if (Number.isNaN(intVal)) { pushError(field, \"integer\", { value: val, kind: typeof val }); failed = true; } else val = intVal;\n break;\n }\n case p === \"numeric\" || p === \"float\" || p === \"double\": {\n const numVal = Number(val);\n if (Number.isNaN(numVal)) { pushError(field, \"numeric\", { value: val, kind: typeof val }); failed = true; } else val = numVal;\n break;\n }\n case p === \"boolean\":\n if (typeof val === \"string\") {\n const lv = val.toLowerCase();\n if ([\"true\", \"1\", \"yes\", \"on\"].includes(lv)) val = true;\n else if ([\"false\", \"0\", \"no\", \"off\"].includes(lv)) val = false;\n else { pushError(field, \"boolean\", { value: val, kind: typeof val }); failed = true; }\n } else if (typeof val !== \"boolean\") { pushError(field, \"boolean\", { value: val, kind: typeof val }); failed = true; }\n break;\n case p === \"array\":\n if (!Array.isArray(val)) {\n if (typeof val === \"string\") {\n try { const p2 = JSON.parse(val); if (Array.isArray(p2)) val = p2; else { pushError(field, \"array\", { value: val, kind: typeof val }); failed = true; } }\n catch { pushError(field, \"array\", { value: val, kind: typeof val }); failed = true; }\n } else { pushError(field, \"array\", { value: val, kind: typeof val }); failed = true; }\n }\n break;\n case p === \"json\":\n if (typeof val === \"string\") {\n try { val = JSON.parse(val); } catch { pushError(field, \"json\", { value: val, kind: typeof val }); failed = true; }\n }\n break;\n case p === \"date\": {\n const date = parseDate(val);\n if (!date) { pushError(field, \"date\", { value: val, kind: typeof val }); failed = true; } else val = date;\n break;\n }\n case p === \"url\":\n try { new URL(val); } catch { pushError(field, \"url\", { value: val, kind: typeof val }); failed = true; }\n break;\n case p === \"uuid\":\n if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(String(val))) {\n pushError(field, \"uuid\", { value: val, kind: typeof val }); failed = true;\n }\n break;\n case p === \"phone\": {\n const phoneRegex = /^(\\+\\d{1,3}[\\s-]?)?([0-9]|\\(\\d{1,4}\\))[\\d\\s-]{5,}$/;\n const cleaned = String(val).replace(/[\\s\\-()]/g, \"\");\n const dc = cleaned.replace(/\\D/g, \"\").length;\n if (!phoneRegex.test(String(val)) || dc < 7 || dc > 15) { pushError(field, \"phone\", { value: val, kind: typeof val }); failed = true; }\n break;\n }\n case p.startsWith(\"min:\"): await handleMinRule(field, val, p); break;\n case p.startsWith(\"max:\"): await handleMaxRule(field, val, p); break;\n case p.startsWith(\"size:\"): await handleSizeRule(field, val, p); break;\n case p.startsWith(\"between:\"): await handleBetweenRule(field, val, p); break;\n case p.startsWith(\"in:\"): await handleInRule(field, val, p); break;\n case p.startsWith(\"not_in:\"): await handleNotInRule(field, val, p); break;\n case p.startsWith(\"exists:\"):\n if (!((raw === undefined || raw === null || raw === \"\") && parts.includes(\"nullable\"))) await handleExistsRule(field, val, p);\n break;\n case p.startsWith(\"unique:\"): await handleUniqueRule(field, val, p); break;\n case p.startsWith(\"regex:\"): await handleRegexRule(field, val, p); break;\n case p.startsWith(\"starts_with:\"): await handleStartsWithRule(field, val, p); break;\n case p.startsWith(\"ends_with:\"): await handleEndsWithRule(field, val, p); break;\n case p.startsWith(\"contains:\"): await handleContainsRule(field, val, p); break;\n case p.startsWith(\"gt:\"): await handleComparisonRule(field, val, p, \"gt\", out); break;\n case p.startsWith(\"gte:\"): await handleComparisonRule(field, val, p, \"gte\", out); break;\n case p.startsWith(\"lt:\"): await handleComparisonRule(field, val, p, \"lt\", out); break;\n case p.startsWith(\"lte:\"): await handleComparisonRule(field, val, p, \"lte\", out); break;\n case p.startsWith(\"before:\"): await handleDateComparisonRule(field, val, p, \"before\", out); break;\n case p.startsWith(\"before_or_equal:\"): await handleDateComparisonRule(field, val, p, \"before_or_equal\", out); break;\n case p.startsWith(\"after:\"): await handleDateComparisonRule(field, val, p, \"after\", out); break;\n case p.startsWith(\"after_or_equal:\"): await handleDateComparisonRule(field, val, p, \"after_or_equal\", out); break;\n case p.startsWith(\"date_equals:\"): await handleDateComparisonRule(field, val, p, \"date_equals\", out); break;\n case p.startsWith(\"date_format:\"): await handleDateFormatRule(field, raw, p); break;\n case p === \"time\":\n if (typeof val !== \"string\" || !/^\\d{2}:\\d{2}(:\\d{2})?$/.test(val)) { pushError(field, \"time\", { value: val }); failed = true; }\n break;\n case p === \"datetime\": {\n const dtVal = parseDate(val);\n if (!dtVal) { pushError(field, \"datetime\", { value: val }); failed = true; } else val = dtVal;\n break;\n }\n case p === \"timezone\":\n try { Intl.DateTimeFormat(undefined, { timeZone: String(val) }); }\n catch { pushError(field, \"timezone\", { value: val }); failed = true; }\n break;\n case p === \"accepted\":\n if (![true, 1, \"1\", \"yes\", \"on\"].includes(val)) { pushError(field, \"accepted\", { value: val }); failed = true; }\n break;\n case p === \"declined\":\n if (![false, 0, \"0\", \"no\", \"off\"].includes(val)) { pushError(field, \"declined\", { value: val }); failed = true; }\n break;\n case p === \"confirmed\": {\n const cf = `${field}_confirmation`;\n if (out && (out[cf] || out[\"confirmation_\" + field] || out[field + \"_confirmed\"] || out[\"confirmed_\" + field] || out[\"confirm_\" + field]) !== val) {\n pushError(field, \"confirmed\", { other: cf }); failed = true;\n }\n break;\n }\n case p.startsWith(\"different:\"): {\n const df = p.split(\":\")[1];\n if (out && out[df] === val) { pushError(field, \"different\", { other: df }); failed = true; }\n break;\n }\n case p.startsWith(\"same:\"): {\n const sf = p.split(\":\")[1];\n if (out && out[sf] !== val) { pushError(field, \"same\", { other: sf }); failed = true; }\n break;\n }\n default: break;\n }\n }\n\n if (!failed) setAtPath(out, field, val);\n }\n }\n\n function pushError(field: string, code: string, meta: Record<string, any> = {}) {\n errors[field] = errors[field] || [];\n errors[field].push(code);\n metaErrors[field] = metaErrors[field] || [];\n metaErrors[field].push({ code, meta });\n }\n\n for (const field of Object.keys(metaErrors)) {\n for (const item of metaErrors[field]) {\n const merged = { ...(customMessages || {}), ...(fieldMessagesMap[field] || {}) };\n const msg = resolveMessage(field, item.code, item.meta, merged);\n messageErrors[field] = messageErrors[field] || [];\n messageErrors[field].push(msg);\n }\n }\n\n if (Object.keys(errors).length) throw new ValidationError(errors, messageErrors);\n return out as T;\n\n async function handleMinRule(field: string, val: any, rule: string) {\n const arg = Number(rule.split(\":\")[1]);\n if (typeof val === \"number\" && val < arg) pushError(field, \"min\", { min: arg, value: val, kind: \"numeric\" });\n else if (typeof val === \"string\" && val.length < arg) pushError(field, \"min\", { min: arg, value: val, kind: \"string\" });\n else if (Array.isArray(val) && val.length < arg) pushError(field, \"min\", { min: arg, value: val, kind: \"array\" });\n }\n\n async function handleMaxRule(field: string, val: any, rule: string) {\n const arg = Number(rule.split(\":\")[1]);\n if (typeof val === \"number\" && val > arg) pushError(field, \"max\", { max: arg, value: val, kind: \"numeric\" });\n else if (typeof val === \"string\" && val.length > arg) pushError(field, \"max\", { max: arg, value: val, kind: \"string\" });\n else if (Array.isArray(val) && val.length > arg) pushError(field, \"max\", { max: arg, value: val, kind: \"array\" });\n }\n\n async function handleSizeRule(field: string, val: any, rule: string) {\n const arg = Number(rule.split(\":\")[1]);\n if (typeof val === \"number\" && val !== arg) pushError(field, \"size\", { size: arg, value: val, kind: \"numeric\" });\n else if (typeof val === \"string\" && val.length !== arg) pushError(field, \"size\", { size: arg, value: val, kind: \"string\" });\n else if (Array.isArray(val) && val.length !== arg) pushError(field, \"size\", { size: arg, value: val, kind: \"array\" });\n }\n\n async function handleBetweenRule(field: string, val: any, rule: string) {\n const [min, max] = rule.split(\":\")[1].split(\",\").map(Number);\n if (typeof val === \"number\" && (val < min || val > max)) pushError(field, \"between\", { min, max, value: val, kind: \"numeric\" });\n else if (typeof val === \"string\" && (val.length < min || val.length > max)) pushError(field, \"between\", { min, max, value: val, kind: \"string\" });\n else if (Array.isArray(val) && (val.length < min || val.length > max)) pushError(field, \"between\", { min, max, value: val, kind: \"array\" });\n }\n\n async function handleInRule(field: string, val: any, rule: string) {\n const opts = rule.split(\":\")[1].split(\",\").map((s) => s.trim());\n if (!opts.includes(String(val))) pushError(field, \"in\", { value: val, values: opts.join(\", \") });\n }\n\n async function handleNotInRule(field: string, val: any, rule: string) {\n const opts = rule.split(\":\")[1].split(\",\").map((s) => s.trim());\n if (opts.includes(String(val))) pushError(field, \"not_in\", { value: val, values: opts.join(\", \") });\n }\n\n async function handleExistsRule(field: string, val: any, rule: string) {\n try {\n const spec = rule.split(\":\")[1];\n let [table, column] = spec.split(\",\");\n table = (table || \"\").trim(); column = (column || \"id\").trim();\n class VM extends Model { static table = table; static primaryKey = \"id\"; static fillable = [column]; }\n const exists = await VM.query().where(column, \"=\", val).exists();\n if (!exists) pushError(field, \"exists\", { value: val, table, column });\n } catch { pushError(field, \"exists\", { value: val }); }\n }\n\n async function handleUniqueRule(field: string, val: any, rule: string) {\n try {\n const spec = rule.split(\":\")[1];\n const partsSpec = spec.split(\",\").map((s) => s.trim());\n const table = partsSpec[0];\n const column = partsSpec[1] || \"id\";\n const exceptArg = partsSpec[2]; const exceptArg2 = partsSpec[3];\n class VM extends Model { static table = table; static primaryKey = \"id\"; static fillable = [column]; }\n let exceptColumn = VM.primaryKey, exceptValue = exceptArg;\n if (exceptArg2 !== undefined) { exceptColumn = exceptArg; exceptValue = exceptArg2; }\n let q = VM.query().where(column, \"=\", val);\n if (exceptValue !== undefined && exceptValue !== null && String(exceptValue) !== \"\") {\n q = q.where(function (query: any) { query.where(exceptColumn, \"!=\", exceptValue); });\n }\n if (await q.exists()) pushError(field, \"unique\", { value: val, table, column });\n } catch { pushError(field, \"unique\", { value: val }); }\n }\n\n async function handleRegexRule(field: string, val: any, rule: string) {\n const pattern = rule.split(\":\")[1];\n try {\n if (!new RegExp(pattern).test(String(val))) pushError(field, \"regex\", { value: val, pattern });\n } catch { pushError(field, \"regex_invalid\", { value: val, pattern }); }\n }\n\n async function handleStartsWithRule(field: string, val: any, rule: string) {\n const prefixes = rule.split(\":\")[1].split(\",\").map((s) => s.trim());\n if (!prefixes.some((p2) => String(val).startsWith(p2))) pushError(field, \"starts_with\", { value: val, prefixes: prefixes.join(\", \") });\n }\n\n async function handleEndsWithRule(field: string, val: any, rule: string) {\n const suffixes = rule.split(\":\")[1].split(\",\").map((s) => s.trim());\n if (!suffixes.some((s) => String(val).endsWith(s))) pushError(field, \"ends_with\", { value: val, suffixes: suffixes.join(\", \") });\n }\n\n async function handleContainsRule(field: string, val: any, rule: string) {\n const substring = rule.split(\":\")[1];\n if (!String(val).includes(substring)) pushError(field, \"contains\", { value: val, substring });\n }\n\n async function handleComparisonRule(field: string, val: any, rule: string, operator: string, payload: any) {\n const otherField = rule.split(\":\")[1];\n const otherValue = payload ? getAtPath(payload, otherField) : undefined;\n if (otherValue === undefined) return;\n const numVal = Number(val), numOther = Number(otherValue);\n if (!isNaN(numVal) && !isNaN(numOther)) {\n const ok = operator === \"gt\" ? numVal > numOther : operator === \"gte\" ? numVal >= numOther : operator === \"lt\" ? numVal < numOther : numVal <= numOther;\n if (!ok) pushError(field, operator, { field: otherField, value: val, other: otherValue });\n return;\n }\n const dv = parseDate(val), dOther = parseDate(otherValue);\n if (dv && dOther) {\n const tv = dv.getTime(), to = dOther.getTime();\n const ok = operator === \"gt\" ? tv > to : operator === \"gte\" ? tv >= to : operator === \"lt\" ? tv < to : tv <= to;\n if (!ok) pushError(field, operator, { field: otherField, value: val, other: otherValue });\n return;\n }\n const sv = String(val), so = String(otherValue);\n const ok = operator === \"gt\" ? sv > so : operator === \"gte\" ? sv >= so : operator === \"lt\" ? sv < so : sv <= so;\n if (!ok) pushError(field, operator, { field: otherField, value: val, other: otherValue });\n }\n\n async function handleDateComparisonRule(field: string, val: any, rule: string, operator: string, payload: any) {\n const otherField = rule.split(\":\")[1];\n let otherRaw = payload ? getAtPath(payload, otherField) : undefined;\n if (otherRaw === undefined) otherRaw = otherField;\n if (typeof otherRaw === \"string\") {\n const lower = otherRaw.toLowerCase().trim();\n if (lower === \"today\") { const t = new Date(); t.setHours(0,0,0,0); otherRaw = t; }\n else if (lower === \"yesterday\") { const t = new Date(); t.setDate(t.getDate()-1); t.setHours(0,0,0,0); otherRaw = t; }\n else if (lower === \"tomorrow\") { const t = new Date(); t.setDate(t.getDate()+1); t.setHours(0,0,0,0); otherRaw = t; }\n else {\n const rm = lower.match(/^(today|yesterday|tomorrow|now)([+-])(\\d+)(days?|weeks?|months?|years?)$/);\n if (rm) {\n const [, anchor, sign, numStr, unit] = rm;\n const n = parseInt(numStr, 10) * (sign === \"+\" ? 1 : -1);\n const t = new Date(); t.setHours(0,0,0,0);\n if (anchor === \"yesterday\") t.setDate(t.getDate()-1);\n if (anchor === \"tomorrow\") t.setDate(t.getDate()+1);\n if (unit.startsWith(\"day\")) t.setDate(t.getDate()+n);\n if (unit.startsWith(\"week\")) t.setDate(t.getDate()+n*7);\n if (unit.startsWith(\"month\")) t.setMonth(t.getMonth()+n);\n if (unit.startsWith(\"year\")) t.setFullYear(t.getFullYear()+n);\n otherRaw = t;\n }\n }\n }\n const dv = parseDate(val), dOther = parseDate(otherRaw);\n if (!dv) { pushError(field, \"date\", { value: val }); return; }\n if (!dOther) return;\n const tv = dv.getTime(), to = dOther.getTime();\n const ok = operator === \"before\" ? tv < to : operator === \"before_or_equal\" ? tv <= to : operator === \"after\" ? tv > to : operator === \"after_or_equal\" ? tv >= to : tv === to;\n if (!ok) pushError(field, operator, { field: otherField, value: val, other: otherRaw });\n }\n\n async function handleDateFormatRule(field: string, val: any, rule: string) {\n const format = rule.slice(\"date_format:\".length);\n const strVal = String(val);\n const tokenMap: Record<string, string> = {\n YYYY: \"\\\\d{4}\", YY: \"\\\\d{2}\", MM: \"(?:0[1-9]|1[0-2])\", DD: \"(?:0[1-9]|[12]\\\\d|3[01])\",\n HH: \"(?:[01]\\\\d|2[0-3])\", mm: \"[0-5]\\\\d\", ss: \"[0-5]\\\\d\", SSS: \"\\\\d{3}\", Z: \"(?:Z|[+-]\\\\d{2}:\\\\d{2})\",\n };\n let pattern = format.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n for (const token of Object.keys(tokenMap).sort((a, b) => b.length - a.length)) {\n pattern = pattern.replace(new RegExp(token.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\"), \"g\"), tokenMap[token]);\n }\n if (!new RegExp(\"^\" + pattern + \"$\").test(strVal)) pushError(field, \"date_format\", { value: val, format });\n }\n}\n\nexport const requiredIf =\n (otherField: string, value: any): RuleFn =>\n async (val, _field, payload) => {\n if (payload && payload[otherField] === value) {\n if (val === undefined || val === null || val === \"\") return { ok: false, message: \"required\" };\n }\n return true;\n };\n\nexport const requiredUnless =\n (otherField: string, value: any): RuleFn =>\n async (val, _field, payload) => {\n if (payload && payload[otherField] !== value) {\n if (val === undefined || val === null || val === \"\") return { ok: false, message: \"required\" };\n }\n return true;\n };\n\nexport const fileRule: RuleFn = async (value) => {\n if (!value) return true;\n if (typeof value === \"object\" && (value instanceof File || (\"name\" in value && \"size\" in value))) return true;\n return { ok: false, message: \"file\" };\n};\n\nexport const mimes =\n (allowedTypes: string[]): RuleFn =>\n async (value) => {\n if (!value) return true;\n let fileName = typeof value === \"string\" ? value : (value?.name || \"\");\n const extension = fileName.split(\".\").pop()?.toLowerCase() || \"\";\n const mimeTypes: Record<string, string[]> = {\n jpg: [\"image/jpeg\"], jpeg: [\"image/jpeg\"], png: [\"image/png\"],\n gif: [\"image/gif\"], pdf: [\"application/pdf\"],\n doc: [\"application/msword\"],\n docx: [\"application/vnd.openxmlformats-officedocument.wordprocessingml.document\"],\n };\n const allowedExts = allowedTypes.map((type) => {\n for (const [ext, mimes2] of Object.entries(mimeTypes)) if (mimes2.includes(type)) return ext;\n return type.split(\"/\").pop();\n }).filter(Boolean);\n if (!allowedExts.includes(extension)) return { ok: false, message: \"mimes\", value: allowedTypes.join(\", \") };\n return true;\n };\n\nexport const maxFileSize =\n (maxSizeInMB: number): RuleFn =>\n async (value) => {\n if (!value) return true;\n const fileSize = value instanceof File ? value.size : (value?.size || 0);\n if (fileSize > maxSizeInMB * 1024 * 1024) return { ok: false, message: \"max_file_size\", value: maxSizeInMB };\n return true;\n };\n\nexport const phoneRule: RuleFn = (value) => {\n if (!value) return true;\n const phoneRegex = /^(\\+\\d{1,3}[\\s-]?)?([0-9]|\\(\\d{1,4}\\))[\\d\\s-]{5,}$/;\n const cleaned = String(value).replace(/[\\s\\-()]/g, \"\");\n const dc = cleaned.replace(/\\D/g, \"\").length;\n if (!phoneRegex.test(String(value)) || dc < 7 || dc > 15) return { ok: false, message: \"phone\" };\n return true;\n};\n\nexport const creditCardRule: RuleFn = (value) => {\n if (!value) return true;\n const str = String(value).replace(/\\s+/g, \"\");\n if (!/^\\d+$/.test(str)) return { ok: false, message: \"credit_card\" };\n let sum = 0, isEven = false;\n for (let i = str.length - 1; i >= 0; i--) {\n let digit = parseInt(str.charAt(i), 10);\n if (isEven) { digit *= 2; if (digit > 9) digit -= 9; }\n sum += digit; isEven = !isEven;\n }\n if (sum % 10 !== 0) return { ok: false, message: \"credit_card\" };\n return true;\n};\n\nexport const nestedRule =\n (rules: Record<string, RuleSpec>): RuleFn =>\n async (value) => {\n if (value === undefined || value === null) return true;\n if (typeof value !== \"object\" || Array.isArray(value)) return { ok: false, message: \"object\" };\n try { await validate(value, rules); return true; }\n catch { return { ok: false, message: \"nested_validation_failed\" }; }\n };\n\nexport const arrayOfObjectsRule =\n (rules: Record<string, RuleSpec>): RuleFn =>\n async (value) => {\n if (value === undefined || value === null) return true;\n let array: any[];\n if (Array.isArray(value)) array = value;\n else if (typeof value === \"string\") {\n try { const p = JSON.parse(value); array = Array.isArray(p) ? p : [p]; }\n catch { return { ok: false, message: \"array\" }; }\n } else array = [value];\n for (let i = 0; i < array.length; i++) {\n if (typeof array[i] !== \"object\" || Array.isArray(array[i])) return { ok: false, message: \"object_array\" };\n try { await validate(array[i], rules); }\n catch { return { ok: false, message: `items[${i}].validation_failed` }; }\n }\n return { ok: true, value: array };\n };\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lara-node/validator",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Laravel-inspired validation engine for Lara-Node",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@lara-node/db": "0.1.1"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/node": "^24.12.2",
|
|
22
|
+
"rimraf": "^6.0.1",
|
|
23
|
+
"tsdown": "^0.12.9",
|
|
24
|
+
"typescript": "^5.9.3"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsdown src/index.ts --format esm --out-dir dist --dts",
|
|
28
|
+
"dev": "tsdown src/index.ts --format esm --out-dir dist --dts --watch",
|
|
29
|
+
"clean": "rimraf dist",
|
|
30
|
+
"typecheck": "tsc --noEmit"
|
|
31
|
+
}
|
|
32
|
+
}
|