kanun 0.1.0

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.cjs ADDED
@@ -0,0 +1,3071 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ //#region src/Rules/baseRule.ts
4
+ var BaseRule = class {};
5
+
6
+ //#endregion
7
+ //#region src/locales/en.ts
8
+ var en_default = {
9
+ accepted: "The :attribute must be accepted.",
10
+ accepted_if: "The :attribute must be accepted when :other is :value.",
11
+ after: "The :attribute must be a date after :date.",
12
+ after_or_equal: "The :attribute must be a date after or equal to :date.",
13
+ alpha: "The :attribute must only contain letters.",
14
+ alpha_dash: "The :attribute must only contain at least one letter or one number, and optionally dashes and underscores.",
15
+ alpha_num: "The :attribute must only contain letters and numbers.",
16
+ array: "The :attribute must be an array.",
17
+ array_unique: "The :attribute must be an array with unique values.",
18
+ before: "The :attribute must be a date before :date.",
19
+ before_or_equal: "The :attribute must be a date before or equal to :date.",
20
+ between: {
21
+ number: "The :attribute must be between :min and :max.",
22
+ string: "The :attribute must be between :min and :max characters.",
23
+ array: "The :attribute must have between :min and :max items.",
24
+ object: "The :attribute must have between :min and :max items."
25
+ },
26
+ boolean: "The :attribute field must be true or false.",
27
+ confirmed: "The :attribute confirmation does not match.",
28
+ date: "The :attribute is not a valid date.",
29
+ date_equals: "The :attribute must be a date equal to :date.",
30
+ declined: "The :attribute must be declined.",
31
+ declined_if: "The :attribute must be declined when :other is :value.",
32
+ different: "The :attribute and :other must be different.",
33
+ digits: "The :attribute must be :digits digits.",
34
+ digits_between: "The :attribute must be between :min and :max digits.",
35
+ email: "The :attribute must be a valid email address.",
36
+ ends_with: "The :attribute must end with one of the following: :values.",
37
+ gt: {
38
+ number: "The :attribute must be greater than :value.",
39
+ string: "The :attribute must be greater than :value characters.",
40
+ array: "The :attribute must have more than :value items.",
41
+ object: "The :attribute must have more than :value items."
42
+ },
43
+ gte: {
44
+ number: "The :attribute must be greater than or equal :value.",
45
+ string: "The :attribute must be greater than or equal :value characters.",
46
+ array: "The :attribute must have :value items or more.",
47
+ object: "The :attribute must have :value items or more."
48
+ },
49
+ in: "The :attribute must be one of the following :values.",
50
+ integer: "The :attribute must be an integer.",
51
+ json: "The :attribute must be a valid JSON string.",
52
+ lt: {
53
+ number: "The :attribute must be less than :value.",
54
+ string: "The :attribute must be less than :value characters.",
55
+ array: "The :attribute must have less than :value items.",
56
+ object: "The :attribute must have less than :value items."
57
+ },
58
+ lte: {
59
+ number: "The :attribute must be less than or equal :value.",
60
+ string: "The :attribute must be less than or equal :value characters.",
61
+ array: "The :attribute must have :value items or less.",
62
+ object: "The :attribute must have :value items or less."
63
+ },
64
+ max: {
65
+ number: "The :attribute must not be greater than :max.",
66
+ string: "The :attribute must not be greater than :max characters.",
67
+ array: "The :attribute must not have more than :max items.",
68
+ object: "The :attribute must not have more than :max items."
69
+ },
70
+ min: {
71
+ number: "The :attribute must be at least :min.",
72
+ string: "The :attribute must be at least :min characters.",
73
+ array: "The :attribute must have at least :min items.",
74
+ object: "The :attribute must have at least :min items."
75
+ },
76
+ not_in: "The selected :attribute is invalid.",
77
+ not_regex: "The :attribute format is invalid.",
78
+ numeric: "The :attribute must be a number.",
79
+ object: "The :attribute must be an object.",
80
+ password: {
81
+ letter: "The :attribute must contain at least one letter.",
82
+ letters: "The :attribute must contain at least :amount letters.",
83
+ lower_case: "The :attribute must contain at least one lowercase letter.",
84
+ lower_cases: "The :attribute must contain at least :amount lowercase letters.",
85
+ number: "The :attribute must contain at least one number.",
86
+ numbers: "The :attribute must contain at least :amount numbers.",
87
+ symbol: "The :attribute must contain at least one symbol.",
88
+ symbols: "The :attribute must contain at least :amount symbols.",
89
+ upper_case: "The :attribute must contain at least one uppercase letter.",
90
+ upper_cases: "The :attribute must contain at least :amount uppercase letters."
91
+ },
92
+ present: "The :attribute field must be present.",
93
+ regex: "The :attribute format is invalid.",
94
+ required: "The :attribute field is required.",
95
+ required_if: "The :attribute field is required when :other is :value.",
96
+ required_unless: "The :attribute field is required unless :other is in :values.",
97
+ required_with: "The :attribute field is required when :values is present.",
98
+ required_with_all: "The :attribute field is required when :values are present.",
99
+ required_without: "The :attribute field is required when :values is not present.",
100
+ required_without_all: "The :attribute field is required when none of :values are present.",
101
+ starts_with: "The :attribute must start with one of the following: :values.",
102
+ same: "The :attribute and :other must match.",
103
+ size: {
104
+ number: "The :attribute must be :size.",
105
+ string: "The :attribute must be :size characters.",
106
+ array: "The :attribute must contain :size items.",
107
+ object: "The :attribute must contain :size items."
108
+ },
109
+ string: "The :attribute must be a string.",
110
+ url: "The :attribute must have a valid URL format."
111
+ };
112
+
113
+ //#endregion
114
+ //#region src/locales/ar.ts
115
+ var ar_default = {
116
+ accepted: "يجب قبول الحقل :attribute",
117
+ accepted_if: "الحقل :attribute مقبول في حال ما إذا كان :other يساوي :value.",
118
+ after: "يجب على الحقل :attribute أن يكون تاريخا لاحقا للتاريخ :date.",
119
+ after_or_equal: "الحقل :attribute يجب أن يكون تاريخاً لاحقاً أو مطابقاً للتاريخ :date.",
120
+ alpha: "يجب أن لا يحتوي الحقل :attribute سوى على حروف",
121
+ alpha_dash: "يجب أن يحتوي الحقل :attribute على حرف واحد أو رقم واحد على الأقل، بالإضافة إلى شرطات وشرطات سفلية بشكل اختياري",
122
+ alpha_num: "يجب أن يحتوي :attribute على حروف وأرقام فقط",
123
+ array: "يجب أن يكون الحقل :attribute ًمصفوفة",
124
+ before: "يجب على الحقل :attribute أن يكون تاريخا سابقا للتاريخ :date.",
125
+ before_or_equal: "الحقل :attribute يجب أن يكون تاريخا سابقا أو مطابقا للتاريخ :date",
126
+ between: {
127
+ number: "يجب أن تكون قيمة :attribute بين :min و :max.",
128
+ string: "يجب أن يكون عدد حروف النّص :attribute بين :min و :max",
129
+ array: "يجب أن يحتوي :attribute على عدد من العناصر بين :min و :max",
130
+ object: "يجب أن يحتوي :attribute على عدد من العناصر بين :min و :max"
131
+ },
132
+ boolean: "يجب أن تكون قيمة الحقل :attribute إما true أو false",
133
+ confirmed: "حقل التأكيد غير مُطابق للحقل :attribute",
134
+ date: "الحقل :attribute ليس تاريخًا صحيحًا",
135
+ date_equals: "لا يساوي الحقل :attribute مع :date.",
136
+ declined: "يجب رفض الحقل :attribute",
137
+ declined_if: "الحقل :attribute مرفوض في حال ما إذا كان :other يساوي :value.",
138
+ different: "يجب أن يكون الحقلان :attribute و :other مُختلفان",
139
+ digits: "يجب أن يحتوي الحقل :attribute على :digits رقمًا/أرقام",
140
+ digits_between: "يجب أن يحتوي الحقل :attribute بين :min و :max رقمًا/أرقام",
141
+ email: "يجب أن يكون :attribute عنوان بريد إلكتروني صحيح البُنية",
142
+ ends_with: "حقل :attribute يجب ان ينتهي بأحد القيم التالية :value.",
143
+ gt: {
144
+ number: "حقل :attribute يجب ان يكون اكبر من :value.",
145
+ string: "حقل :attribute يجب ان يكون اكبر من :value حروفٍ/حرفًا.",
146
+ array: "حقل :attribute يجب ان يحتوي علي اكثر من :value عناصر/عنصر.",
147
+ object: "حقل :attribute يجب ان يحتوي علي اكثر من :value عناصر/عنصر."
148
+ },
149
+ gte: {
150
+ number: "حقل :attribute يجب ان يكون اكبر من او يساوي :value.",
151
+ string: "حقل :attribute يجب ان يكون اكبر من او يساوي :value حروفٍ/حرفًا.",
152
+ array: "حقل :attribute يجب ان يحتوي علي :value عناصر/عنصر او اكثر.",
153
+ object: "حقل :attribute يجب ان يحتوي علي :value عناصر/عنصر او اكثر."
154
+ },
155
+ in: "الحقل :attribute غير صالح",
156
+ integer: "يجب أن يكون الحقل :attribute عددًا صحيحًا",
157
+ json: "يجب أن يكون الحقل :attribute نصا من نوع JSON.",
158
+ lt: {
159
+ number: "حقل :attribute يجب ان يكون اقل من :value.",
160
+ string: "حقل :attribute يجب ان يكون اقل من :value حروفٍ/حرفًا.",
161
+ array: "حقل :attribute يجب ان يحتوي علي اقل من :value عناصر/عنصر.",
162
+ object: "حقل :attribute يجب ان يحتوي علي اقل من :value عناصر/عنصر."
163
+ },
164
+ lte: {
165
+ number: "حقل :attribute يجب ان يكون اقل من او يساوي :value.",
166
+ string: "حقل :attribute يجب ان يكون اقل من او يساوي :value حروفٍ/حرفًا.",
167
+ array: "حقل :attribute يجب ان يحتوي علي اكثر من :value عناصر/عنصر.",
168
+ object: "حقل :attribute يجب ان يحتوي علي اكثر من :value عناصر/عنصر."
169
+ },
170
+ max: {
171
+ number: "يجب أن تكون قيمة الحقل :attribute مساوية أو أصغر لـ :max.",
172
+ string: "يجب أن لا يتجاوز طول نص :attribute :max حروفٍ/حرفًا",
173
+ array: "يجب أن لا يحتوي الحقل :attribute على أكثر من :max عناصر/عنصر.",
174
+ object: "يجب أن لا يحتوي الحقل :attribute على أكثر من :max عناصر/عنصر."
175
+ },
176
+ min: {
177
+ number: "يجب أن تكون قيمة الحقل :attribute مساوية أو أكبر لـ :min.",
178
+ string: "يجب أن يكون طول نص :attribute على الأقل :min حروفٍ/حرفًا",
179
+ array: "يجب أن يحتوي الحقل :attribute على الأقل على :min عُنصرًا/عناصر",
180
+ object: "يجب أن يحتوي الحقل :attribute على الأقل على :min عُنصرًا/عناصر"
181
+ },
182
+ not_in: "الحقل :attribute غير صالح",
183
+ not_regex: "الحقل :attribute نوعه غير صالح",
184
+ numeric: "يجب على الحقل :attribute أن يكون رقمًا",
185
+ object: "الحقل :attribute يجب ان يكون من نوع object.",
186
+ password: {
187
+ letter: "يجب ان يشمل حقل :attribute على حرف واحد على الاقل.",
188
+ letters: "يجب ان يشمل حقل :attribute على عدد :amount حروف على الاقل.",
189
+ lower_case: "يجب ان يشمل حقل :attribute على حرف واحد من صيغة صغيرة على الاقل.",
190
+ lower_cases: "يجب ان يشمل حقل :attribute على عدد :amount حروف صغيرة على الاقل.",
191
+ number: "يجب ان يشمل حقل :attribute على رقم واحد على الاقل.",
192
+ numbers: "يجب ان يشمل حقل :attribute على عدد :amount من الارقام على الاقل.",
193
+ symbol: "يجب ان يشمل حقل :attribute على رمز واحد على الاقل.",
194
+ symbols: "يجب ان يشمل حقل :attribute على عدد :amount رموز على الاقل.",
195
+ upper_case: "يجب ان يشمل حقل :attribute على حرف كبير واحد على الاقل.",
196
+ upper_cases: "يجب ان يشمل حقل :attribute على عدد :amount حروف كبيرة على الاقل."
197
+ },
198
+ present: "يجب تقديم الحقل :attribute",
199
+ regex: "صيغة الحقل :attribute .غير صحيحة",
200
+ required: "الحقل :attribute مطلوب.",
201
+ required_if: "الحقل :attribute مطلوب في حال ما إذا كان :other يساوي :value.",
202
+ required_unless: "الحقل :attribute مطلوب في حال ما لم يكن :other يساوي :values.",
203
+ required_with: "الحقل :attribute اجباري إذا توفّر :values.",
204
+ required_with_all: "الحقل :attribute اجباري إذا توفّر :values.",
205
+ required_without: "الحقل :attribute اجباري إذا لم يتوفّر :values.",
206
+ required_without_all: "الحقل :attribute اجباري إذا لم يتوفّر :values.",
207
+ starts_with: "الحقل :attribute يجب ان يبدأ بأحد القيم التالية: :values.",
208
+ same: "يجب أن يتطابق الحقل :attribute مع :other",
209
+ size: {
210
+ number: "يجب أن تكون قيمة الحقل :attribute مساوية لـ :size",
211
+ string: "يجب أن يحتوي النص :attribute على :size حروفٍ/حرفًا بالظبط",
212
+ array: "يجب أن يحتوي الحقل :attribute على :size عنصرٍ/عناصر بالظبط",
213
+ object: "يجب أن يحتوي الحقل :attribute على :size عنصرٍ/عناصر بالظبط"
214
+ },
215
+ string: "يجب أن يكون الحقل :attribute نصآ.",
216
+ url: "صيغة الرابط :attribute غير صحيحة"
217
+ };
218
+
219
+ //#endregion
220
+ //#region src/locales/index.ts
221
+ var locales_default = {
222
+ en: en_default,
223
+ ar: ar_default
224
+ };
225
+
226
+ //#endregion
227
+ //#region src/Lang.ts
228
+ var Lang = class {
229
+ /**
230
+ * Default lang to be used, when lang is not specified
231
+ */
232
+ static defaultLang = "en";
233
+ /**
234
+ * Determines the locale to be used when tu current one is not available
235
+ */
236
+ static fallbackLang = "en";
237
+ /**
238
+ * The existing langs that are supported by the library
239
+ */
240
+ static existingLangs = ["en"];
241
+ /**
242
+ * Store the translations passed by the user
243
+ */
244
+ static translations = {};
245
+ /**
246
+ * Stores the messages that are already loaded
247
+ */
248
+ static messages = {};
249
+ /**
250
+ * Stores the default messages
251
+ */
252
+ static defaultMessages = {};
253
+ /**
254
+ * Stores the fallback messages
255
+ */
256
+ static fallbackMessages = locales_default.en;
257
+ /**
258
+ * Get messages for lang
259
+ *
260
+ * @param lang
261
+ * @returns
262
+ */
263
+ static get(lang) {
264
+ lang ??= this.defaultLang;
265
+ this.load(lang);
266
+ return this.messages[lang];
267
+ }
268
+ /**
269
+ * Set the translation object passed by the user
270
+ *
271
+ * @param translations
272
+ */
273
+ static setTranslationObject(translations) {
274
+ this.translations = translations;
275
+ this.existingLangs = Array.from(new Set([...this.existingLangs, ...Object.keys(translations)]));
276
+ this.setDefaultLang(this.defaultLang);
277
+ }
278
+ /**
279
+ * Set the default lang that should be used. And assign the default messages
280
+ *
281
+ * @param lang
282
+ */
283
+ static setDefaultLang(lang) {
284
+ this.defaultLang = lang;
285
+ this.load(lang);
286
+ }
287
+ /**
288
+ * Set the fallback lang to be used. And assign the fallback messages
289
+ *
290
+ * @param lang
291
+ */
292
+ static setFallbackLang(lang) {
293
+ this.fallbackLang = lang;
294
+ this.fallbackMessages = locales_default.en;
295
+ if (Object.prototype.hasOwnProperty.call(locales_default, lang)) this.fallbackMessages = mergeDeep(this.fallbackMessages, locales_default[lang]);
296
+ if (Object.prototype.hasOwnProperty.call(this.translations, lang)) this.fallbackMessages = mergeDeep(this.fallbackMessages, this.translations[lang]);
297
+ }
298
+ /**
299
+ * Get the default language
300
+ *
301
+ * @returns
302
+ */
303
+ static getDefaultLang() {
304
+ return this.defaultLang;
305
+ }
306
+ /**
307
+ * Load the messages based on the specified language
308
+ *
309
+ * @param lang
310
+ * @returns
311
+ */
312
+ static load(lang) {
313
+ if (this.messages[lang]) return;
314
+ if (Object.prototype.hasOwnProperty.call(locales_default, lang)) this.messages[lang] = mergeDeep(this.fallbackMessages, locales_default[lang]);
315
+ else this.messages[lang] = mergeDeep({}, this.fallbackMessages);
316
+ if (Object.prototype.hasOwnProperty.call(this.translations, lang)) this.messages[lang] = mergeDeep(this.messages[lang], this.translations[lang]);
317
+ }
318
+ };
319
+
320
+ //#endregion
321
+ //#region src/Rules/IRuleContract.ts
322
+ var IRuleContract = class {
323
+ /**
324
+ * The validation error message.
325
+ */
326
+ message = "";
327
+ /**
328
+ * All of the data under validation.
329
+ */
330
+ data = {};
331
+ /**
332
+ * The lang used to return error messages
333
+ */
334
+ lang;
335
+ /**
336
+ * Determine if the validation rule passes.
337
+ */
338
+ passes(_value, _attribute) {
339
+ return true;
340
+ }
341
+ /**
342
+ * Get the validation error message.
343
+ */
344
+ getMessage() {
345
+ return this.message;
346
+ }
347
+ /**
348
+ * Set the data under validation.
349
+ */
350
+ setData(data) {
351
+ this.data = data;
352
+ return this;
353
+ }
354
+ /**
355
+ * Set the tranlation language
356
+ */
357
+ setLang(lang) {
358
+ this.lang = lang;
359
+ return this;
360
+ }
361
+ /**
362
+ * Get the translated error message based on the specified path
363
+ */
364
+ trans(path, params = {}) {
365
+ let message = deepFind(Lang.get(this.lang), path) || "";
366
+ if (!message) return message;
367
+ for (const key in params) message = message.replace(`:${key}`, params[key]);
368
+ return message;
369
+ }
370
+ };
371
+
372
+ //#endregion
373
+ //#region src/utilities/general.ts
374
+ const implicitRues = [
375
+ "accepted",
376
+ "accepted_if",
377
+ "declined",
378
+ "declined_if",
379
+ "filled",
380
+ "present",
381
+ "required",
382
+ "required_if",
383
+ "required_unless",
384
+ "required_with",
385
+ "required_with_all",
386
+ "required_without",
387
+ "required_without_all"
388
+ ];
389
+ /**
390
+ * Get the size of a value based on its type
391
+ */
392
+ function getSize(value, hasNumericRule = false) {
393
+ if (typeof value === "number" || isNaN(value) === false && hasNumericRule === true) return Number(value);
394
+ else if (typeof value === "string" || Array.isArray(value)) return value.length;
395
+ else if (typeof value === "object" && value !== null) return Object.keys(value).length;
396
+ return -1;
397
+ }
398
+ /**
399
+ * Check if two values are of the same type
400
+ */
401
+ function sameType(value, otherValue) {
402
+ return (Array.isArray(value) ? "array" : value === null ? null : typeof value) === (Array.isArray(otherValue) ? "array" : otherValue === null ? null : typeof otherValue);
403
+ }
404
+ /**
405
+ * Check if Value is an Ineteger
406
+ */
407
+ function isInteger(value) {
408
+ return value !== null && isNaN(value) === false && value % 1 === 0;
409
+ }
410
+ /**
411
+ * Check if the value can be considered as rule
412
+ */
413
+ function isRule(value) {
414
+ return typeof value === "string" || typeof value === "function" || value instanceof IRuleContract || value instanceof BaseRule;
415
+ }
416
+ /**
417
+ * Check if the array contain any potentiel valid rule
418
+ */
419
+ function isArrayOfRules(values) {
420
+ for (let i = 0; i < values.length; i++) if (isRule(values[i])) return true;
421
+ return false;
422
+ }
423
+ /**
424
+ * Check if the rule is related to size
425
+ */
426
+ function isSizeRule(rule) {
427
+ return [
428
+ "size",
429
+ "between",
430
+ "min",
431
+ "max",
432
+ "gt",
433
+ "lt",
434
+ "gte",
435
+ "lte"
436
+ ].indexOf(rule) !== -1;
437
+ }
438
+ /**
439
+ * Check if rule implies that the field is required
440
+ */
441
+ function isImplicitRule(rule) {
442
+ if (rule instanceof IRuleContract && rule.__isImplicitRule === true) return true;
443
+ if (typeof rule === "string") return implicitRues.indexOf(rule) !== -1;
444
+ return false;
445
+ }
446
+ /**
447
+ * Add a new implicit rule
448
+ */
449
+ function addImplicitRule(rule) {
450
+ implicitRues.push(rule);
451
+ }
452
+ /**
453
+ * Returns the numeric rules
454
+ */
455
+ function getNumericRules() {
456
+ return ["numeric", "integer"];
457
+ }
458
+ /**
459
+ * Check if the rule is numeric
460
+ */
461
+ function isNumericRule(rule) {
462
+ return getNumericRules().indexOf(rule) !== -1;
463
+ }
464
+ /**
465
+ * Determine if a comparison passes between the given values.
466
+ */
467
+ function compare(first, second, operator, strict = false) {
468
+ switch (operator) {
469
+ case "<": return first < second;
470
+ case ">": return first > second;
471
+ case "<=": return first <= second;
472
+ case ">=": return first >= second;
473
+ case "=":
474
+ if (strict === true) return first === second;
475
+ return first == second;
476
+ default: throw "Invalid operator parameter";
477
+ }
478
+ }
479
+ /**
480
+ * Convert the given values to boolean if they are string "true" / "false".
481
+ */
482
+ function convertValuesToBoolean(values) {
483
+ return values.map((value) => {
484
+ if (value === "true") return true;
485
+ else if (value === "false") return false;
486
+ return value;
487
+ });
488
+ }
489
+ /**
490
+ * Convert the given values to numbers if they are numbers in a string "1", "2"
491
+ */
492
+ function convertValuesToNumber(values) {
493
+ return values.map((value) => {
494
+ if (!isNaN(Number(value))) return Number(value);
495
+ return value;
496
+ });
497
+ }
498
+ /**
499
+ * Convert the given values to null if they have null values in a string "null", "NULL"
500
+ */
501
+ function convertValuesToNull(values) {
502
+ return values.map((value) => {
503
+ if (value.toLowerCase() === "null") return null;
504
+ return value;
505
+ });
506
+ }
507
+
508
+ //#endregion
509
+ //#region src/utilities/object.ts
510
+ /**
511
+ * Get value at path of object. If the resolved value is undifined, the returned result will be undefined
512
+ *
513
+ * @param obj
514
+ * @param path
515
+ * @returns
516
+ */
517
+ function deepFind(obj, path) {
518
+ const paths = path.split(".");
519
+ for (let i = 0; i < paths.length; i++) {
520
+ if (typeof obj[paths[i]] === "undefined") return;
521
+ obj = obj[paths[i]];
522
+ }
523
+ return obj;
524
+ }
525
+ /**
526
+ * Set value at path of object.
527
+ *
528
+ * @param target
529
+ * @param path
530
+ * @param value
531
+ */
532
+ function deepSet(target, path, value) {
533
+ const paths = typeof path === "string" ? path.split(".") : path;
534
+ const segment = paths.shift();
535
+ if (segment === "*") {
536
+ target = Array.isArray(target) ? target : [];
537
+ if (paths.length > 0) target.forEach((inner) => deepSet(inner, [...paths], value));
538
+ else for (let i = 0; i < target.length; i++) target[i] = value;
539
+ } else if (paths.length > 0 && typeof segment === "string") {
540
+ if (typeof target[segment] !== "object" || target[segment] === null) target[segment] = {};
541
+ deepSet(target[segment], paths, value);
542
+ } else {
543
+ if (typeof target !== "object" || target === null) target = {};
544
+ target[segment] = value;
545
+ }
546
+ }
547
+ /**
548
+ * Flatten a multi-dimensional associative array with dots.
549
+ *
550
+ * @param obj
551
+ * @param ignoreRulesArray
552
+ * @param withBaseObjectType
553
+ * @returns
554
+ */
555
+ function dotify(obj, ignoreRulesArray = false, withBaseObjectType = false) {
556
+ const res = {};
557
+ (function recurse(obj, current = "") {
558
+ for (const key in obj) {
559
+ const value = obj[key];
560
+ const newKey = current ? `${current}.${key}` : key;
561
+ if (value && typeof value === "object" && !isRule(value) && !(value instanceof Date)) if (ignoreRulesArray === true && Array.isArray(value) && isArrayOfRules(value)) res[newKey] = value;
562
+ else {
563
+ if (withBaseObjectType) res[newKey] = Array.isArray(value) ? "array" : "object";
564
+ recurse(value, newKey);
565
+ }
566
+ else res[newKey] = value;
567
+ }
568
+ })(obj);
569
+ return res;
570
+ }
571
+ /**
572
+ * Check if the value is an object
573
+ *
574
+ * @param value
575
+ * @returns
576
+ */
577
+ function isObject(value) {
578
+ return value && typeof value === "object" && !Array.isArray(value);
579
+ }
580
+ /**
581
+ * Deeply merge nested objects
582
+ *
583
+ * @param target
584
+ * @param source
585
+ * @returns
586
+ */
587
+ function mergeDeep(target, source) {
588
+ const output = Object.assign({}, target);
589
+ if (!isObject(target) || !isObject(source)) return output;
590
+ for (const key in source) if (isObject(source[key])) if (!target[key]) Object.assign(output, { [key]: source[key] });
591
+ else output[key] = mergeDeep(target[key], source[key]);
592
+ else Object.assign(output, { [key]: source[key] });
593
+ return output;
594
+ }
595
+ /**
596
+ * Check if objects are deep equal
597
+ *
598
+ * @param firstParam
599
+ * @param secondParam
600
+ * @returns
601
+ */
602
+ function deepEqual(firstParam, secondParam) {
603
+ const first = dotify(firstParam, false, true);
604
+ const second = dotify(secondParam, false, true);
605
+ if (Object.keys(first).length !== Object.keys(second).length) return false;
606
+ return Object.entries(first).every(([key, value]) => second[key] === value);
607
+ }
608
+
609
+ //#endregion
610
+ //#region src/utilities/formatMessages.ts
611
+ /**
612
+ * Get the message type based on the value. The message type is used essentially for size rules
613
+ */
614
+ function getMesageType(value, hasNumericRule = false) {
615
+ if (typeof value === "number" || typeof value === "undefined" || isNaN(value) === false && hasNumericRule === true) return "number";
616
+ if (Array.isArray(value)) return "array";
617
+ return typeof value;
618
+ }
619
+ /**
620
+ * Get the custom message for a rule if exists
621
+ */
622
+ function getCustomMessage(attributes, rule, customMessages, messageType, lang) {
623
+ const [attribute, primaryAttribute] = attributes;
624
+ const translatedMessages = dotify(Lang.get(lang)["custom"] || {});
625
+ const keys = getKeyCombinations(`${attribute}.${rule}`);
626
+ let allKeys = keys;
627
+ if (primaryAttribute) {
628
+ allKeys = [];
629
+ const primaryAttributeKeys = getKeyCombinations(`${primaryAttribute}.${rule}`);
630
+ for (let i = 0; i < keys.length; i++) {
631
+ allKeys.push(keys[i]);
632
+ if (keys[i] !== primaryAttributeKeys[i]) allKeys.push(primaryAttributeKeys[i]);
633
+ }
634
+ }
635
+ if (isSizeRule(rule)) {
636
+ allKeys.pop();
637
+ allKeys.push(`${rule}.${messageType}`);
638
+ allKeys.push(rule);
639
+ }
640
+ let key = "";
641
+ let message = "";
642
+ for (let i = 0; i < allKeys.length; i++) {
643
+ key = allKeys[i];
644
+ if (Object.prototype.hasOwnProperty.call(customMessages, key)) return customMessages[key];
645
+ message = translatedMessages[key];
646
+ if (typeof message === "string") return message;
647
+ }
648
+ return null;
649
+ }
650
+ /**
651
+ * Get the validation message for an attribute and rule.
652
+ */
653
+ function getMessage(attributes, rule, value, customMessages, hasNumericRule, lang) {
654
+ const inlineMessage = getCustomMessage(attributes, rule, customMessages, getMesageType(value, hasNumericRule), lang);
655
+ if (inlineMessage) return inlineMessage;
656
+ const validationMessages = Lang.get(lang);
657
+ if (isSizeRule(rule) === true) return validationMessages[rule][getMesageType(value, hasNumericRule)];
658
+ return validationMessages[rule] || "";
659
+ }
660
+ /**
661
+ * Convert a string to snake case.
662
+ */
663
+ function toSnakeCase(string) {
664
+ return string.split(/ |\B(?=[A-Z])/).map((word) => word.toLowerCase()).join("_");
665
+ }
666
+ /**
667
+ * Get the formatted name of the attribute
668
+ */
669
+ function getFormattedAttribute(attribute) {
670
+ return toSnakeCase(getPrimaryKeyFromPath(attribute)).replace(/_/g, " ").trim();
671
+ }
672
+ /**
673
+ * Get the combinations of keys from a main key. For example if the main key is 'user.info.name',
674
+ * the combination will be [user.info.name, info.name, name]
675
+ */
676
+ function getKeyCombinations(key) {
677
+ const combinations = [key];
678
+ const splittedKey = key.split(".");
679
+ while (splittedKey.length > 1) {
680
+ splittedKey.shift();
681
+ combinations.push(splittedKey.join("."));
682
+ }
683
+ return combinations;
684
+ }
685
+ /**
686
+ * The purpose of this method if to get the primary key associated with a path
687
+ * For example the primary key for path 'user.info.email' will be 'email'
688
+ */
689
+ function getPrimaryKeyFromPath(path) {
690
+ const splittedPath = path.split(".");
691
+ if (splittedPath.length <= 1) return path;
692
+ const key = splittedPath.pop();
693
+ if (isNaN(parseInt(key)) === false) return getPrimaryKeyFromPath(splittedPath.join("."));
694
+ return key;
695
+ }
696
+
697
+ //#endregion
698
+ //#region src/validators/errorBag.ts
699
+ var ErrorBag = class ErrorBag {
700
+ /**
701
+ * All of the registered messages.
702
+ */
703
+ errors = {};
704
+ /**
705
+ * All Messages
706
+ */
707
+ messages = {};
708
+ /**
709
+ * Stores the first error message
710
+ */
711
+ firstMessage = "";
712
+ /**
713
+ * Specify whether error types should be returned or no
714
+ */
715
+ withErrorTypes = false;
716
+ constructor(errors = {}, messages = {}, firstMessage = "", withErrorTypes = false) {
717
+ this.errors = errors;
718
+ this.messages = messages;
719
+ this.firstMessage = firstMessage;
720
+ this.withErrorTypes = withErrorTypes;
721
+ }
722
+ /**
723
+ * Set withErrorTypes attribute to true
724
+ */
725
+ addErrorTypes() {
726
+ this.withErrorTypes = true;
727
+ return this;
728
+ }
729
+ /**
730
+ * Add new recodrs to the errors and messages objects
731
+ */
732
+ add(key, error) {
733
+ if (Array.isArray(this.errors[key]) && Array.isArray(this.messages[key])) {
734
+ this.errors[key].push(error);
735
+ this.messages[key].push(error.message);
736
+ } else {
737
+ this.errors[key] = [error];
738
+ this.messages[key] = [error.message];
739
+ }
740
+ this.firstMessage = this.firstMessage || error.message;
741
+ }
742
+ /**
743
+ * Get the first error related to a specific key
744
+ */
745
+ first(key = null) {
746
+ if (!key) return this.firstMessage;
747
+ if (this.has(key)) return this.messages[key][0];
748
+ return "";
749
+ }
750
+ /**
751
+ * Get the error messages keys
752
+ */
753
+ keys() {
754
+ return Object.keys(this.messages);
755
+ }
756
+ /**
757
+ * Get all the messages related to a specific key
758
+ */
759
+ get(key, withErrorTypes = this.withErrorTypes) {
760
+ if (!this.has(key)) return [];
761
+ if (withErrorTypes) return this.errors[key];
762
+ return this.messages[key];
763
+ }
764
+ /**
765
+ * Check if key exists in messages
766
+ */
767
+ has(key) {
768
+ return this.messages[key] && this.messages[key].length > 0 ? true : false;
769
+ }
770
+ /**
771
+ * Get all error messages
772
+ */
773
+ all(allMessages = true, withErrorTypes = this.withErrorTypes) {
774
+ const messages = withErrorTypes ? { ...this.errors } : { ...this.messages };
775
+ if (!allMessages) Object.keys(messages).map((attribute) => messages[attribute] = messages[attribute][0]);
776
+ return messages;
777
+ }
778
+ /**
779
+ * Remove error messages
780
+ */
781
+ clear(keys) {
782
+ if (keys.length === 0) {
783
+ this.errors = {};
784
+ this.messages = {};
785
+ this.firstMessage = "";
786
+ return this;
787
+ }
788
+ keys.forEach((key) => {
789
+ if (Object.prototype.hasOwnProperty.call(this.messages, key)) {
790
+ delete this.messages[key];
791
+ delete this.errors[key];
792
+ }
793
+ });
794
+ this.firstMessage = "";
795
+ if (this.keys().length > 0) this.firstMessage = this.messages[Object.keys(this.messages)[0]][0];
796
+ return this;
797
+ }
798
+ /**
799
+ * Clone ErrorBag Instance
800
+ */
801
+ clone() {
802
+ return new ErrorBag({ ...this.errors }, { ...this.messages }, this.firstMessage, this.withErrorTypes);
803
+ }
804
+ };
805
+
806
+ //#endregion
807
+ //#region src/Rules/password.ts
808
+ var Password$1 = class Password$1 extends IRuleContract {
809
+ /**
810
+ * The validator performing the validation.
811
+ */
812
+ validator;
813
+ /**
814
+ * The minimum size of the password.
815
+ */
816
+ minLength = 8;
817
+ /**
818
+ * The min amount of lower case letters required in the password
819
+ */
820
+ minLowerCase = 0;
821
+ /**
822
+ * The min amount of uppercase letters required in the password
823
+ */
824
+ minUpperCase = 0;
825
+ /**
826
+ * The min amount of letters required in the password
827
+ */
828
+ minLetters = 0;
829
+ /**
830
+ * The min amount of letters required in the password
831
+ */
832
+ minNumbers = 0;
833
+ /**
834
+ * The min amount of symbols required in the password
835
+ */
836
+ minSymbols = 0;
837
+ /**
838
+ * Additional validation rules that should be merged into the default rules during validation.
839
+ */
840
+ customRules = [];
841
+ /**
842
+ * The callback that will generate the "default" version of the password rule.
843
+ */
844
+ static defaultCallback;
845
+ /**
846
+ * Create a new instance of the password class
847
+ */
848
+ static create() {
849
+ return new Password$1();
850
+ }
851
+ /**
852
+ * Set the minimum length of the password
853
+ */
854
+ min(min) {
855
+ this.minLength = min;
856
+ return this;
857
+ }
858
+ /**
859
+ * Set the min amount of letters required in the password
860
+ */
861
+ letters(letters = 1) {
862
+ this.minLetters = letters;
863
+ return this;
864
+ }
865
+ /**
866
+ * Set the min amount of upper and lower case letters required in the password
867
+ */
868
+ mixedCase(upperCase = 1, lowerCase = 1) {
869
+ this.minUpperCase = upperCase;
870
+ this.minLowerCase = lowerCase;
871
+ return this;
872
+ }
873
+ /**
874
+ * Set the min amount of numbers required in the password
875
+ */
876
+ numbers(numbers = 1) {
877
+ this.minNumbers = numbers;
878
+ return this;
879
+ }
880
+ /**
881
+ * Set the min amount of symbols required in the password
882
+ */
883
+ symbols(symbols = 1) {
884
+ this.minSymbols = symbols;
885
+ return this;
886
+ }
887
+ /**
888
+ * Determine if the validation rule passes.
889
+ */
890
+ passes(value, attribute) {
891
+ const validator = new BaseValidator(this.data, { [attribute]: [
892
+ "string",
893
+ `min:${this.minLength}`,
894
+ ...this.customRules
895
+ ] }, this.validator.customMessages, this.validator.customAttributes).setLang(this.lang);
896
+ if (!validator.validate()) {
897
+ const errors = validator.errors().addErrorTypes().get(attribute);
898
+ for (const key in errors) this.validator.errors().add(attribute, errors[key]);
899
+ }
900
+ if (typeof value !== "string") value = "";
901
+ let pattern;
902
+ const formattedAttribute = this.validator.getDisplayableAttribute(attribute);
903
+ if (this.minLowerCase) {
904
+ pattern = this.minLowerCase === 1 ? /\p{Ll}/u : new RegExp(`(.*\\p{Ll}){${this.minLowerCase}}.*`, "u");
905
+ if (!value || pattern.test(value) === false) this.validator.errors().add(attribute, {
906
+ error_type: "min_lower_case",
907
+ message: this.trans(`password.${this.minLowerCase === 1 ? "lower_case" : "lower_cases"}`, {
908
+ attribute: formattedAttribute,
909
+ amount: this.minLowerCase
910
+ })
911
+ });
912
+ }
913
+ if (this.minUpperCase) {
914
+ pattern = this.minUpperCase === 1 ? /\p{Lu}/u : new RegExp(`(.*\\p{Lu}){${this.minUpperCase}}.*`, "u");
915
+ if (!value || pattern.test(value) === false) this.validator.errors().add(attribute, {
916
+ error_type: "min_upper_case",
917
+ message: this.trans(`password.${this.minUpperCase === 1 ? "upper_case" : "upper_cases"}`, {
918
+ attribute: formattedAttribute,
919
+ amount: this.minUpperCase
920
+ })
921
+ });
922
+ }
923
+ if (this.minLetters) {
924
+ pattern = this.minLetters === 1 ? /\p{L}/u : new RegExp(`(.*\\p{L}){${this.minLetters}}.*`, "u");
925
+ if (!value || pattern.test(value) === false) this.validator.errors().add(attribute, {
926
+ error_type: "min_letters",
927
+ message: this.trans(`password.${this.minLetters === 1 ? "letter" : "letters"}`, {
928
+ attribute: formattedAttribute,
929
+ amount: this.minLetters
930
+ })
931
+ });
932
+ }
933
+ if (this.minNumbers) {
934
+ pattern = this.minNumbers === 1 ? /\p{N}/u : new RegExp(`(.*\\p{N}){${this.minNumbers}}.*`, "u");
935
+ if (!value || pattern.test(value) === false) this.validator.errors().add(attribute, {
936
+ error_type: "min_numbers",
937
+ message: this.trans(`password.${this.minNumbers === 1 ? "number" : "numbers"}`, {
938
+ attribute: formattedAttribute,
939
+ amount: this.minNumbers
940
+ })
941
+ });
942
+ }
943
+ if (this.minSymbols) {
944
+ pattern = this.minSymbols === 1 ? /\p{Z}|\p{S}|\p{P}/u : new RegExp(`(.*(\\p{Z}|\\p{S}|\\p{P})){${this.minSymbols}}.*`, "u");
945
+ if (!value || pattern.test(value) === false) this.validator.errors().add(attribute, {
946
+ error_type: "min_symbols",
947
+ message: this.trans(`password.${this.minSymbols === 1 ? "symbol" : "symbols"}`, {
948
+ attribute: formattedAttribute,
949
+ amount: this.minSymbols
950
+ })
951
+ });
952
+ }
953
+ if (this.validator.errors().has(attribute)) return false;
954
+ return true;
955
+ }
956
+ /**
957
+ * Specify additional validation rules that should be merged with the default rules during validation.
958
+ */
959
+ rules(rules) {
960
+ this.customRules = rules;
961
+ return this;
962
+ }
963
+ /**
964
+ * Get all the validation error messages related to the password
965
+ */
966
+ getMessage() {
967
+ return {};
968
+ }
969
+ /**
970
+ * Set the validator instance used to validate the password
971
+ */
972
+ setValidator(validator) {
973
+ this.validator = validator;
974
+ return this;
975
+ }
976
+ /**
977
+ * Set the default callback to be used for determining a password's default rules.
978
+ */
979
+ static setDefault(callback = null) {
980
+ if (callback instanceof Password$1) {
981
+ this.defaultCallback = callback;
982
+ return;
983
+ }
984
+ if (typeof callback !== "function") throw "The given callback should be callable";
985
+ this.defaultCallback = callback;
986
+ }
987
+ /**
988
+ * Get the default configuration of the password rule.
989
+ */
990
+ static default() {
991
+ const password = typeof this.defaultCallback === "function" ? this.defaultCallback() : this.defaultCallback;
992
+ return password instanceof IRuleContract ? password : Password$1.create().min(8);
993
+ }
994
+ };
995
+
996
+ //#endregion
997
+ //#region src/utilities/build.ts
998
+ function buildValidationMethodName(rule) {
999
+ if (!rule) return rule;
1000
+ return rule.split("_").map((rule) => `${rule[0].toUpperCase()}${rule.slice(1)}`).join("");
1001
+ }
1002
+
1003
+ //#endregion
1004
+ //#region src/payloads/replaceAttributePayload.ts
1005
+ var replaceAttributePayload = class {
1006
+ /**
1007
+ * Stores the data object
1008
+ */
1009
+ data;
1010
+ /**
1011
+ * The message in which attributes will be replaced
1012
+ */
1013
+ message;
1014
+ /**
1015
+ * Parameters that will be used to replace the attributes
1016
+ */
1017
+ parameters;
1018
+ /**
1019
+ * Flag that identifies wether the numeric rule exists or not
1020
+ */
1021
+ hasNumericRule;
1022
+ /**
1023
+ * The function that will be used to format attributes
1024
+ */
1025
+ getDisplayableAttribute;
1026
+ constructor(data, message, parameters, hasNumericRule, getDisplayableAttribute) {
1027
+ this.data = data;
1028
+ this.message = message;
1029
+ this.parameters = parameters;
1030
+ this.hasNumericRule = hasNumericRule;
1031
+ this.getDisplayableAttribute = getDisplayableAttribute;
1032
+ }
1033
+ };
1034
+
1035
+ //#endregion
1036
+ //#region src/utilities/date.ts
1037
+ /**
1038
+ * Convert value to date instance
1039
+ */
1040
+ function toDate(value) {
1041
+ const date = Date.parse(value);
1042
+ return !isNaN(date) ? new Date(date) : null;
1043
+ }
1044
+
1045
+ //#endregion
1046
+ //#region src/validators/replaceAttributes.ts
1047
+ const replaceAttributes = {
1048
+ replaceAcceptedIf: function({ data, message, parameters, getDisplayableAttribute }) {
1049
+ const [other] = parameters;
1050
+ const result = deepFind(data, other);
1051
+ const values = {
1052
+ ":other": getDisplayableAttribute(other),
1053
+ ":value": result
1054
+ };
1055
+ return message.replace(/:other|:value/gi, (matched) => values[matched]);
1056
+ },
1057
+ replaceAfter: function(payload) {
1058
+ return this.replaceBefore(payload);
1059
+ },
1060
+ replaceAfterOrEqual: function(payload) {
1061
+ return this.replaceBefore(payload);
1062
+ },
1063
+ replaceBefore: function({ message, parameters, getDisplayableAttribute }) {
1064
+ if (!toDate(parameters[0])) return message.replace(":date", getDisplayableAttribute(parameters[0]));
1065
+ return message.replace(":date", parameters[0]);
1066
+ },
1067
+ replaceBeforeOrEqual: function(payload) {
1068
+ return this.replaceBefore(payload);
1069
+ },
1070
+ replaceBetween: function({ message, parameters }) {
1071
+ const values = {
1072
+ ":min": parameters[0],
1073
+ ":max": parameters[1]
1074
+ };
1075
+ return message.replace(/:min|:max/gi, (matched) => values[matched]);
1076
+ },
1077
+ replaceDateEquals: function(payload) {
1078
+ return this.replaceBefore(payload);
1079
+ },
1080
+ replaceDeclinedIf: function({ message, parameters, data, getDisplayableAttribute }) {
1081
+ const [other] = parameters;
1082
+ const result = deepFind(data, other);
1083
+ const values = {
1084
+ ":other": getDisplayableAttribute(other),
1085
+ ":value": result
1086
+ };
1087
+ return message.replace(/:other|:value/gi, (matched) => values[matched]);
1088
+ },
1089
+ replaceDifferent: function(payload) {
1090
+ return this.replaceSame(payload);
1091
+ },
1092
+ replaceDigits: function({ message, parameters }) {
1093
+ return message.replace(":digits", parameters[0]);
1094
+ },
1095
+ replaceDigitsBetween: function(payload) {
1096
+ return this.replaceBetween(payload);
1097
+ },
1098
+ replaceEndsWith: function({ message, parameters }) {
1099
+ return message.replace(":values", parameters.join(", "));
1100
+ },
1101
+ replaceIn: function({ message, parameters }) {
1102
+ return message.replace(":values", parameters.join(", "));
1103
+ },
1104
+ replaceStartsWith: function({ message, parameters }) {
1105
+ return message.replace(":values", parameters.join(", "));
1106
+ },
1107
+ replaceMin: function({ message, parameters }) {
1108
+ return message.replace(":min", parameters[0]);
1109
+ },
1110
+ replaceMax: function({ message, parameters }) {
1111
+ return message.replace(":max", parameters[0]);
1112
+ },
1113
+ replaceRequiredWith: function({ message, parameters, getDisplayableAttribute }) {
1114
+ return message.replace(":values", parameters.map((attribute) => getDisplayableAttribute(attribute)).join(", "));
1115
+ },
1116
+ replaceRequiredWithAll: function(payload) {
1117
+ return this.replaceRequiredWith(payload);
1118
+ },
1119
+ replaceRequiredWithout: function(payload) {
1120
+ return this.replaceRequiredWith(payload);
1121
+ },
1122
+ replaceRequiredWithoutAll: function(payload) {
1123
+ return this.replaceRequiredWith(payload);
1124
+ },
1125
+ replaceGt: function({ message, parameters, data, hasNumericRule }) {
1126
+ const [value] = parameters;
1127
+ const result = deepFind(data, value);
1128
+ if (typeof result === "undefined") return message.replace(":value", value);
1129
+ return message.replace(":value", getSize(result, hasNumericRule).toString());
1130
+ },
1131
+ replaceLt: function(payload) {
1132
+ return this.replaceGt(payload);
1133
+ },
1134
+ replaceGte: function(payload) {
1135
+ return this.replaceGt(payload);
1136
+ },
1137
+ replaceLte: function(payload) {
1138
+ return this.replaceGt(payload);
1139
+ },
1140
+ replaceRequiredIf: function({ message, parameters, data, getDisplayableAttribute }) {
1141
+ const [other] = parameters;
1142
+ const result = deepFind(data, other);
1143
+ const values = {
1144
+ ":other": getDisplayableAttribute(other),
1145
+ ":value": result
1146
+ };
1147
+ return message.replace(/:other|:value/gi, (matched) => values[matched]);
1148
+ },
1149
+ replaceRequiredUnless: function({ message, parameters, getDisplayableAttribute }) {
1150
+ const [other] = parameters;
1151
+ const values = {
1152
+ ":other": getDisplayableAttribute(other),
1153
+ ":values": parameters.slice(1).join(", ")
1154
+ };
1155
+ return message.replace(/:other|:values/gi, (matched) => values[matched]);
1156
+ },
1157
+ replaceSame: function({ message, parameters, getDisplayableAttribute }) {
1158
+ return message.replace(":other", getDisplayableAttribute(parameters[0]));
1159
+ },
1160
+ replaceSize: function({ message, parameters }) {
1161
+ return message.replace(":size", parameters[0]);
1162
+ }
1163
+ };
1164
+
1165
+ //#endregion
1166
+ //#region src/Rules/closureValidationRule.ts
1167
+ var ClosureValidationRule = class extends IRuleContract {
1168
+ /**
1169
+ * The callback that validates the attribute
1170
+ */
1171
+ callback;
1172
+ /**
1173
+ * Indicates if the validation callback failed.
1174
+ */
1175
+ failed = false;
1176
+ constructor(callback) {
1177
+ super();
1178
+ this.callback = callback;
1179
+ }
1180
+ /**
1181
+ * Determine if the validation rule passes.
1182
+ */
1183
+ passes(value, attribute) {
1184
+ this.failed = false;
1185
+ const result = this.callback(value, (message) => {
1186
+ this.failed = true;
1187
+ this.message = message;
1188
+ }, attribute);
1189
+ if (result instanceof Promise) return result.then(() => !this.failed);
1190
+ return !this.failed;
1191
+ }
1192
+ };
1193
+
1194
+ //#endregion
1195
+ //#region src/validators/validationData.ts
1196
+ const validationData = {
1197
+ initializeAndGatherData: function(attribute, masterData) {
1198
+ const data = dotify(this.initializeAttributeOnData(attribute, masterData));
1199
+ return {
1200
+ ...data,
1201
+ ...this.extractValuesFromWildCards(masterData, data, attribute)
1202
+ };
1203
+ },
1204
+ initializeAttributeOnData: function(attribute, masterData) {
1205
+ const explicitPath = this.getLeadingExplicitAttributePath(attribute);
1206
+ const data = this.extractDataFromPath(explicitPath, JSON.parse(JSON.stringify(masterData)));
1207
+ if (attribute.indexOf("*") === -1 || attribute.indexOf("*") === attribute.length - 1) return data;
1208
+ deepSet(data, attribute, null);
1209
+ return data;
1210
+ },
1211
+ extractValuesFromWildCards(masterData, data, attribute) {
1212
+ const keys = [];
1213
+ const pattern = new RegExp("^" + attribute.replace(/\*/g, "[^\\.]*"));
1214
+ let result = null;
1215
+ for (const key in data) {
1216
+ result = key.match(pattern);
1217
+ if (result) keys.push(result[0]);
1218
+ }
1219
+ data = {};
1220
+ keys.forEach((key) => data[key] = deepFind(masterData, key));
1221
+ return data;
1222
+ },
1223
+ getLeadingExplicitAttributePath: function(attribute) {
1224
+ return attribute.split("*")[0].replace(/\.$/, "");
1225
+ },
1226
+ extractDataFromPath(path, masterData) {
1227
+ const results = {};
1228
+ const value = deepFind(masterData, path);
1229
+ if (value !== void 0) deepSet(results, path, value);
1230
+ return results;
1231
+ }
1232
+ };
1233
+
1234
+ //#endregion
1235
+ //#region src/validators/validationRuleParser.ts
1236
+ const validationRuleParser = {
1237
+ explodeRules: function(rules, data = {}) {
1238
+ const implicitAttributes = {};
1239
+ for (const key in rules) if (key.indexOf("*") !== -1) {
1240
+ rules = this.explodeWildCardRules(rules, key, data, implicitAttributes);
1241
+ delete rules[key];
1242
+ } else if (Object.prototype.hasOwnProperty.call(rules, key) && Array.isArray(rules)) rules[Number(key)] = this.explodeExplicitRules(rules[Number(key)]);
1243
+ else if (Object.prototype.hasOwnProperty.call(rules, key) && !Array.isArray(rules)) rules[key] = this.explodeExplicitRules(rules[key]);
1244
+ return {
1245
+ rules,
1246
+ implicitAttributes
1247
+ };
1248
+ },
1249
+ explodeWildCardRules: function(results, attribute, masterData, implicitAttributes) {
1250
+ const pattern = new RegExp("^" + attribute.replace(/\*/g, "[^.]*") + "$");
1251
+ const data = validationData.initializeAndGatherData(attribute, masterData);
1252
+ const rule = results[attribute];
1253
+ for (const key in data) if (key.slice(0, attribute.length) === attribute || key.match(pattern) !== null) {
1254
+ if (Array.isArray(implicitAttributes[attribute])) implicitAttributes[attribute].push(key);
1255
+ else implicitAttributes[attribute] = [key];
1256
+ results = this.mergeRulesForAttribute(results, key, rule);
1257
+ }
1258
+ return results;
1259
+ },
1260
+ mergeRulesForAttribute(results, attribute, rules) {
1261
+ const merge = this.explodeRules([rules]).rules[0];
1262
+ results[attribute] = [...results[attribute] ? this.explodeExplicitRules(results[attribute]) : [], ...merge];
1263
+ return results;
1264
+ },
1265
+ explodeExplicitRules: function(rules) {
1266
+ if (typeof rules === "string") return rules.split("|");
1267
+ if (!Array.isArray(rules)) return [this.prepareRule(rules)];
1268
+ return rules.map((rule) => this.prepareRule(rule));
1269
+ },
1270
+ prepareRule(rule) {
1271
+ if (rule instanceof IRuleContract) return rule;
1272
+ if (typeof rule === "function") return new ClosureValidationRule(rule);
1273
+ return rule.toString();
1274
+ },
1275
+ parse(rule) {
1276
+ if (rule instanceof IRuleContract) return [rule, []];
1277
+ return this.parseStringRule(rule);
1278
+ },
1279
+ parseStringRule: function(rule) {
1280
+ let parameters = [];
1281
+ let parameter;
1282
+ if (rule.indexOf(":") !== -1) {
1283
+ [rule, parameter] = rule.split(/:(.+)/);
1284
+ parameters = parameter.split(",");
1285
+ }
1286
+ return [rule, parameters];
1287
+ },
1288
+ getRule: function(attribute, searchRules, availableRules) {
1289
+ if (!availableRules[attribute]) return [];
1290
+ searchRules = Array.isArray(searchRules) ? searchRules : [searchRules];
1291
+ for (let i = 0; i < availableRules[attribute].length; i++) {
1292
+ const [rule, parameters] = this.parse(availableRules[attribute][i]);
1293
+ if (searchRules.indexOf(rule) !== -1) return [rule, parameters];
1294
+ }
1295
+ return [];
1296
+ },
1297
+ hasRule: function(attribute, searchRules, availableRules) {
1298
+ return this.getRule(attribute, searchRules, availableRules).length > 0;
1299
+ }
1300
+ };
1301
+
1302
+ //#endregion
1303
+ //#region src/validators/validateAttributes.ts
1304
+ var validateAttributes = class {
1305
+ /**
1306
+ * Stores the data object
1307
+ */
1308
+ data;
1309
+ /**
1310
+ * Stores the rules object
1311
+ */
1312
+ rules;
1313
+ constructor(data = {}, rules = {}) {
1314
+ this.data = data;
1315
+ this.rules = rules;
1316
+ }
1317
+ /**
1318
+ * Validate that an attribute was "accepted".
1319
+ *
1320
+ * This validation rule implies the attribute is "required".
1321
+ */
1322
+ validateAccepted(value) {
1323
+ return this.validateRequired(value) && [
1324
+ "yes",
1325
+ "on",
1326
+ "1",
1327
+ 1,
1328
+ true,
1329
+ "true"
1330
+ ].indexOf(value) !== -1;
1331
+ }
1332
+ /**
1333
+ * Validate that an attribute was "accepted" when another attribute has a given value.
1334
+ */
1335
+ validateAcceptedIf(value, parameters) {
1336
+ this.requireParameterCount(2, parameters, "accepted_if");
1337
+ const other = deepFind(this.data, parameters[0]);
1338
+ if (!other) return true;
1339
+ if (parameters.slice(1).indexOf(other) !== -1) return this.validateAccepted(value);
1340
+ return true;
1341
+ }
1342
+ /**
1343
+ * Validate the date is after a given date.
1344
+ */
1345
+ validateAfter(value, parameters) {
1346
+ this.requireParameterCount(1, parameters, "after");
1347
+ return this.compareDates(value, parameters[0], ">", "after");
1348
+ }
1349
+ /**
1350
+ * Validate the date is after or equal a given date.
1351
+ */
1352
+ validateAfterOrEqual(value, parameters) {
1353
+ this.requireParameterCount(1, parameters, "after_or_equal");
1354
+ return this.compareDates(value, parameters[0], ">=", "after_or_equal");
1355
+ }
1356
+ /**
1357
+ * Validate that an attribute contains only alphabetic characters.
1358
+ */
1359
+ validateAlpha(value) {
1360
+ return typeof value === "string" && /^[a-zA-Z]+$/.test(value);
1361
+ }
1362
+ /**
1363
+ * Validate that an attribute contains only alpha-numeric characters, dashes, and underscores.
1364
+ */
1365
+ validateAlphaDash(value) {
1366
+ if (typeof value != "string" && typeof value != "number") return false;
1367
+ return /^(?=.*[a-zA-Z0-9])[a-zA-Z0-9-_]+$/.test(value.toString());
1368
+ }
1369
+ /**
1370
+ * Validate that an attribute contains only alpha-numeric characters.
1371
+ */
1372
+ validateAlphaNum(value) {
1373
+ if (typeof value != "string" && typeof value != "number") return false;
1374
+ return /^[a-zA-Z0-9]+$/.test(value.toString());
1375
+ }
1376
+ /**
1377
+ * Validate that an attribute is an array
1378
+ */
1379
+ validateArray(value) {
1380
+ return Array.isArray(value);
1381
+ }
1382
+ /**
1383
+ * Validate that an attribute is an array and that his values are unique
1384
+ */
1385
+ validateArrayUnique(value) {
1386
+ if (!Array.isArray(value)) return false;
1387
+ return new Set(value).size === value.length;
1388
+ }
1389
+ /**
1390
+ * Always returns true - this method will be used in conbination with other rules and will be used to stop validation of first failure
1391
+ */
1392
+ validateBail() {
1393
+ return true;
1394
+ }
1395
+ /**
1396
+ * Validate the date is before a given date.
1397
+ */
1398
+ validateBefore(value, parameters) {
1399
+ this.requireParameterCount(1, parameters, "before");
1400
+ return this.compareDates(value, parameters[0], "<", "before");
1401
+ }
1402
+ /**
1403
+ * Validate the date is before or equal a given date.
1404
+ */
1405
+ validateBeforeOrEqual(value, parameters) {
1406
+ this.requireParameterCount(1, parameters, "before_or_equal");
1407
+ return this.compareDates(value, parameters[0], "<=", "before_or_equal");
1408
+ }
1409
+ /**
1410
+ * Validate the size of an attribute is between a set of values
1411
+ */
1412
+ validateBetween(value, parameters, attribute) {
1413
+ if (typeof value !== "string" && typeof value !== "number" && typeof value !== "object") throw "Validation rule between requires the field under validation to be a number, string, array, or object.";
1414
+ this.requireParameterCount(2, parameters, "between");
1415
+ let [min, max] = parameters;
1416
+ if (isNaN(min) || isNaN(max)) throw "Validation rule between requires both parameters to be numbers.";
1417
+ min = Number(min);
1418
+ max = Number(max);
1419
+ if (min >= max) throw "Validation rule between requires that the first parameter be greater than the second one.";
1420
+ const size = getSize(value, validationRuleParser.hasRule(attribute, getNumericRules(), this.rules));
1421
+ return size >= min && size <= max;
1422
+ }
1423
+ /**
1424
+ * Validate that an attribute is boolean
1425
+ */
1426
+ validateBoolean(value, parameters, attribute) {
1427
+ if (validationRuleParser.hasRule(attribute, "strict", this.rules)) return typeof value === "boolean";
1428
+ return [
1429
+ true,
1430
+ false,
1431
+ 0,
1432
+ 1,
1433
+ "0",
1434
+ "1"
1435
+ ].indexOf(value) !== -1;
1436
+ }
1437
+ /**
1438
+ * Validate that an attribute has matching confirmation.
1439
+ */
1440
+ validateConfirmed(value, parameters, attribute) {
1441
+ return this.validateSame(value, [`${attribute}_confirmation`]) || this.validateSame(value, [`${attribute}Confirmation`]);
1442
+ }
1443
+ /**
1444
+ * Validate that an attribute is a valid date.
1445
+ */
1446
+ validateDate(value) {
1447
+ return toDate(value) ? true : false;
1448
+ }
1449
+ /**
1450
+ * Validate that an attribute is equal to another date.
1451
+ */
1452
+ validateDateEquals(value, paramters) {
1453
+ this.requireParameterCount(1, paramters, "date_equals");
1454
+ return this.compareDates(value, paramters[0], "=", "date_equals");
1455
+ }
1456
+ /**
1457
+ * Validate that an attribute was "declined".
1458
+ *
1459
+ * This validation rule implies the attribute is "required".
1460
+ */
1461
+ validateDeclined(value) {
1462
+ return this.validateRequired(value) && [
1463
+ "no",
1464
+ "off",
1465
+ "0",
1466
+ 0,
1467
+ false,
1468
+ "false"
1469
+ ].indexOf(value) !== -1;
1470
+ }
1471
+ /**
1472
+ * Validate that an attribute was "declined" when another attribute has a given value.
1473
+ */
1474
+ validateDeclinedIf(value, parameters) {
1475
+ this.requireParameterCount(2, parameters, "declined_if");
1476
+ const other = deepFind(this.data, parameters[0]);
1477
+ if (!other) return true;
1478
+ if (parameters.slice(1).indexOf(other) !== -1) return this.validateDeclined(value);
1479
+ return true;
1480
+ }
1481
+ /**
1482
+ * Validate that an attribute is different from another attribute.
1483
+ */
1484
+ validateDifferent(value, parameters) {
1485
+ this.requireParameterCount(1, parameters, "different");
1486
+ const other = deepFind(this.data, parameters[0]);
1487
+ if (!sameType(value, other)) return true;
1488
+ if (value !== null && typeof value === "object") return !deepEqual(value, other);
1489
+ return value !== other;
1490
+ }
1491
+ /**
1492
+ * Validate that an attribute has a given number of digits.
1493
+ */
1494
+ validateDigits(value, parameters) {
1495
+ this.requireParameterCount(1, parameters, "digits");
1496
+ if (isInteger(parameters[0]) === false) throw "Validation rule digits requires the parameter to be an integer.";
1497
+ if (parameters[0] <= 0) throw "Validation rule digits requires the parameter to be an integer greater than 0.";
1498
+ if (typeof value !== "string" && typeof value !== "number") return false;
1499
+ value = value.toString();
1500
+ return /^\d+$/.test(value) && value.length === parseInt(parameters[0]);
1501
+ }
1502
+ /**
1503
+ * Validate that an attribute is between a given number of digits.
1504
+ */
1505
+ validateDigitsBetween(value, parameters) {
1506
+ this.requireParameterCount(2, parameters, "digits_between");
1507
+ let [min, max] = parameters;
1508
+ if (isInteger(min) === false || isInteger(max) === false) throw "Validation rule digits_between requires both parameters to be integers.";
1509
+ min = parseInt(min);
1510
+ max = parseInt(max);
1511
+ if (min <= 0 || max <= 0) throw "Validation rule digits_between requires the parameters to be an integer greater than 0.";
1512
+ if (min >= max) throw "Validation rule digits_between requires the max param to be greater than the min param.";
1513
+ if (typeof value !== "string" && typeof value !== "number") return false;
1514
+ value = value.toString();
1515
+ const valueLength = value.length;
1516
+ return /^\d+$/.test(value) && valueLength >= min && valueLength <= max;
1517
+ }
1518
+ /**
1519
+ * Validate that an attribute is a valid email address.
1520
+ */
1521
+ validateEmail(value) {
1522
+ if (typeof value !== "string") return false;
1523
+ /**
1524
+ * Max allowed length for a top-level-domain is 24 characters.
1525
+ * reference to list of top-level-domains: https://data.iana.org/TLD/tlds-alpha-by-domain.txt
1526
+ */
1527
+ return value.toLowerCase().match(/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,24})+$/) !== null;
1528
+ }
1529
+ /**
1530
+ * Validate the attribute ends with a given substring.
1531
+ */
1532
+ validateEndsWith(value, parameters) {
1533
+ this.requireParameterCount(1, parameters, "ends_with");
1534
+ if (typeof value !== "string") throw "The field under validation must be a string";
1535
+ const valueLength = value.length;
1536
+ for (let i = 0; i < parameters.length; i++) if (typeof parameters[i] === "string" && value.indexOf(parameters[i], valueLength - parameters[i].length) !== -1) return true;
1537
+ return false;
1538
+ }
1539
+ /**
1540
+ * Validate that two attributes match.
1541
+ */
1542
+ validateSame(value, paramaters) {
1543
+ this.requireParameterCount(1, paramaters, "same");
1544
+ const other = deepFind(this.data, paramaters[0]);
1545
+ if (!sameType(value, other)) return false;
1546
+ if (value !== null && typeof value === "object") return deepEqual(value, other);
1547
+ return value === other;
1548
+ }
1549
+ /**
1550
+ * Validate the size of an attribute.
1551
+ */
1552
+ validateSize(value, parameters, attribute) {
1553
+ this.requireParameterCount(1, parameters, "size");
1554
+ return getSize(value, validationRuleParser.hasRule(attribute, getNumericRules(), this.rules)) === Number(parameters[0]);
1555
+ }
1556
+ /**
1557
+ * Validate Optinial attributes. Always return true, just lets us put sometimes in rule.
1558
+ */
1559
+ validateSometimes() {
1560
+ return true;
1561
+ }
1562
+ /**
1563
+ * Validate the attribute starts with a given substring.
1564
+ */
1565
+ validateStartsWith(value, parameters) {
1566
+ this.requireParameterCount(1, parameters, "starts_with");
1567
+ if (typeof value !== "string") throw "The field under validation must be a string";
1568
+ for (let i = 0; i < parameters.length; i++) if (typeof parameters[i] === "string" && value.substr(0, parameters[i].length) === parameters[i]) return true;
1569
+ return false;
1570
+ }
1571
+ /**
1572
+ * Validate that a required attribute exists
1573
+ */
1574
+ validateRequired(value) {
1575
+ if (value === null || typeof value === "undefined") return false;
1576
+ else if (typeof value === "string" && value.trim() === "") return false;
1577
+ else if (Array.isArray(value) && value.length < 1) return false;
1578
+ else if (typeof value === "object" && Object.keys(value).length < 1) return false;
1579
+ return true;
1580
+ }
1581
+ /**
1582
+ * Validate that an attribute exists when another atteribute has a given value
1583
+ */
1584
+ validateRequiredIf(value, parameters) {
1585
+ this.requireParameterCount(2, parameters, "required_if");
1586
+ const other = deepFind(this.data, parameters[0]);
1587
+ if (typeof other === "undefined") return true;
1588
+ if (this.parseDependentRuleParameters(other, parameters).indexOf(other) !== -1) return this.validateRequired(value);
1589
+ return true;
1590
+ }
1591
+ /**
1592
+ * Validate that an attribute exists when another attribute does not have a given value.
1593
+ */
1594
+ validateRequiredUnless(value, parameters) {
1595
+ this.requireParameterCount(2, parameters, "required_unless");
1596
+ let other = deepFind(this.data, parameters[0]);
1597
+ other = typeof other === "undefined" ? null : other;
1598
+ if (this.parseDependentRuleParameters(other, parameters).indexOf(other) === -1) return this.validateRequired(value);
1599
+ return true;
1600
+ }
1601
+ /**
1602
+ * Validate that an attribute exists when any other attribute exists.
1603
+ */
1604
+ validateRequiredWith(value, parameters) {
1605
+ if (!this.allFailingRequired(parameters)) return this.validateRequired(value);
1606
+ return true;
1607
+ }
1608
+ /**
1609
+ * Validate that an attribute exists when all other attributes exist.
1610
+ */
1611
+ validateRequiredWithAll(value, parameters) {
1612
+ if (!this.anyFailingRequired(parameters)) return this.validateRequired(value);
1613
+ return true;
1614
+ }
1615
+ /**
1616
+ * Validate that an attribute exists when another attribute does not.
1617
+ */
1618
+ validateRequiredWithout(value, parameters) {
1619
+ if (this.anyFailingRequired(parameters)) return this.validateRequired(value);
1620
+ return true;
1621
+ }
1622
+ /**
1623
+ * Validate that an attribute exists when all other attributes do not.
1624
+ */
1625
+ validateRequiredWithoutAll(value, parameters) {
1626
+ if (this.allFailingRequired(parameters)) return this.validateRequired(value);
1627
+ return true;
1628
+ }
1629
+ /**
1630
+ * Determine if any of the given attributes fail the required test.
1631
+ */
1632
+ anyFailingRequired(attributes) {
1633
+ for (let i = 0; i < attributes.length; i++) if (!this.validateRequired(deepFind(this.data, attributes[i]))) return true;
1634
+ return false;
1635
+ }
1636
+ /**
1637
+ * Determine if all of the given attributes fail the required test.
1638
+ */
1639
+ allFailingRequired(attributes) {
1640
+ for (let i = 0; i < attributes.length; i++) if (this.validateRequired(deepFind(this.data, attributes[i]))) return false;
1641
+ return true;
1642
+ }
1643
+ /**
1644
+ * Validate that an attribute is a string.
1645
+ */
1646
+ validateString(value) {
1647
+ return typeof value === "string";
1648
+ }
1649
+ /**
1650
+ * Validate the size of an attribute is less than a maximum value.
1651
+ */
1652
+ validateMax(value, parameters, attribute) {
1653
+ this.requireParameterCount(1, parameters, "max");
1654
+ if (isNaN(parameters[0])) throw "Validation rule max requires parameter to be a number.";
1655
+ return getSize(value, validationRuleParser.hasRule(attribute, getNumericRules(), this.rules)) <= Number(parameters[0]);
1656
+ }
1657
+ /**
1658
+ * Validate the size of an attribute is greater than a minimum value.
1659
+ */
1660
+ validateMin(value, parameters, attribute) {
1661
+ this.requireParameterCount(1, parameters, "min");
1662
+ if (isNaN(parameters[0])) throw "Validation rule min requires parameter to be a number.";
1663
+ return getSize(value, validationRuleParser.hasRule(attribute, getNumericRules(), this.rules)) >= Number(parameters[0]);
1664
+ }
1665
+ /**
1666
+ * Validate that an attribute is numeric.
1667
+ */
1668
+ validateNumeric(value, parameters, attribute) {
1669
+ if (validationRuleParser.hasRule(attribute, "strict", this.rules) && typeof value !== "number") return false;
1670
+ return value !== null && isNaN(value) === false;
1671
+ }
1672
+ /**
1673
+ * Validate that an attribute is an object
1674
+ */
1675
+ validateObject(value) {
1676
+ return isObject(value);
1677
+ }
1678
+ /**
1679
+ * Validate that an attribute exists even if not filled.
1680
+ */
1681
+ validatePresent(value, parameters, attribute) {
1682
+ return typeof deepFind(this.data, attribute) !== "undefined";
1683
+ }
1684
+ /**
1685
+ * Validate that an attribute is an integer.
1686
+ */
1687
+ validateInteger(value, parameters, attribute) {
1688
+ if (validationRuleParser.hasRule(attribute, "strict", this.rules) && typeof value !== "number") return false;
1689
+ return isInteger(value);
1690
+ }
1691
+ /**
1692
+ * Validate that the attribute is a valid JSON string
1693
+ */
1694
+ validateJson(value) {
1695
+ if (!value || typeof value !== "string") return false;
1696
+ try {
1697
+ JSON.parse(value);
1698
+ } catch {
1699
+ return false;
1700
+ }
1701
+ return true;
1702
+ }
1703
+ /**
1704
+ * Validate that an attribute is greater than another attribute.
1705
+ */
1706
+ validateGt(value, parameters, attribute) {
1707
+ this.requireParameterCount(1, parameters, "gt");
1708
+ if (typeof value !== "number" && typeof value !== "string" && typeof value !== "object") throw "The field under validation must be a number, string, array or object";
1709
+ const compartedToValue = deepFind(this.data, parameters[0]) || parameters[0];
1710
+ if (!Array.isArray(compartedToValue) && isNaN(compartedToValue) === false) return getSize(value, validationRuleParser.hasRule(attribute, getNumericRules(), this.rules)) > compartedToValue;
1711
+ if (sameType(value, compartedToValue) === false) throw "The fields under validation must be of the same type";
1712
+ return getSize(value) > getSize(compartedToValue);
1713
+ }
1714
+ /**
1715
+ * Validate that an attribute is greater than or equal another attribute.
1716
+ */
1717
+ validateGte(value, parameters, attribute) {
1718
+ this.requireParameterCount(1, parameters, "gte");
1719
+ if (typeof value !== "number" && typeof value !== "string" && typeof value !== "object") throw "The field under validation must be a number, string, array or object";
1720
+ const compartedToValue = deepFind(this.data, parameters[0]) || parameters[0];
1721
+ if (!Array.isArray(compartedToValue) && isNaN(compartedToValue) === false) return getSize(value, validationRuleParser.hasRule(attribute, getNumericRules(), this.rules)) >= compartedToValue;
1722
+ if (sameType(value, compartedToValue) === false) throw "The fields under validation must be of the same type";
1723
+ return getSize(value) >= getSize(compartedToValue);
1724
+ }
1725
+ /**
1726
+ * Validate that an attribute is less than another attribute.
1727
+ */
1728
+ validateLt(value, parameters, attribute) {
1729
+ this.requireParameterCount(1, parameters, "lt");
1730
+ if (typeof value !== "number" && typeof value !== "string" && typeof value !== "object") throw "The field under validation must be a number, string, array or object";
1731
+ const compartedToValue = deepFind(this.data, parameters[0]) || parameters[0];
1732
+ if (!Array.isArray(compartedToValue) && isNaN(compartedToValue) === false) return getSize(value, validationRuleParser.hasRule(attribute, getNumericRules(), this.rules)) < compartedToValue;
1733
+ if (sameType(value, compartedToValue) === false) throw "The fields under validation must be of the same type";
1734
+ return getSize(value) < getSize(compartedToValue);
1735
+ }
1736
+ /**
1737
+ * Validate that an attribute is less than or equal another attribute.
1738
+ */
1739
+ validateLte(value, parameters, attribute) {
1740
+ this.requireParameterCount(1, parameters, "lte");
1741
+ if (typeof value !== "number" && typeof value !== "string" && typeof value !== "object") throw "The field under validation must be a number, string, array or object";
1742
+ const compartedToValue = deepFind(this.data, parameters[0]) || parameters[0];
1743
+ if (!Array.isArray(compartedToValue) && isNaN(compartedToValue) === false) return getSize(value, validationRuleParser.hasRule(attribute, getNumericRules(), this.rules)) <= compartedToValue;
1744
+ if (sameType(value, compartedToValue) === false) throw "The fields under validation must be of the same type";
1745
+ return getSize(value) <= getSize(compartedToValue);
1746
+ }
1747
+ /**
1748
+ * Validate an attribute is contained within a list of values.
1749
+ */
1750
+ validateIn(value, parameters) {
1751
+ this.requireParameterCount(1, parameters, "in");
1752
+ if (Array.isArray(value)) {
1753
+ for (let index = 0; index < value.length; index++) if (typeof value[index] !== "number" && typeof value[index] !== "string") return false;
1754
+ return value.filter((element) => parameters.indexOf(element.toString()) === -1).length === 0;
1755
+ }
1756
+ if (typeof value !== "number" && typeof value !== "string") return false;
1757
+ return parameters.indexOf(value.toString()) !== -1;
1758
+ }
1759
+ /**
1760
+ * "Indicate" validation should pass if value is null
1761
+ *
1762
+ * Always returns true, just lets us put "nullable" in rules.
1763
+ */
1764
+ validateNullable() {
1765
+ return true;
1766
+ }
1767
+ /**
1768
+ * Validate an attribute is not contained within a list of values.
1769
+ */
1770
+ validateNotIn(value, parameters) {
1771
+ this.requireParameterCount(1, parameters, "not_in");
1772
+ const valuesToCheck = [];
1773
+ if (Array.isArray(value)) {
1774
+ for (let index = 0; index < value.length; index++) if (typeof value[index] === "number" || typeof value[index] === "string") valuesToCheck.push(value[index]);
1775
+ if (valuesToCheck.length === 0) return true;
1776
+ return valuesToCheck.filter((element) => parameters.indexOf(element.toString()) !== -1).length === 0;
1777
+ }
1778
+ if (typeof value !== "number" && typeof value !== "string") return true;
1779
+ return parameters.indexOf(value.toString()) === -1;
1780
+ }
1781
+ /**
1782
+ * Always returns true - this method will be used in conbination with other rules
1783
+ */
1784
+ validateStrict() {
1785
+ return true;
1786
+ }
1787
+ /**
1788
+ * Validate that an attribute is a valid URL.
1789
+ */
1790
+ validateUrl(value) {
1791
+ if (typeof value !== "string") return false;
1792
+ return new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|localhost|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$", "i").test(value);
1793
+ }
1794
+ /**
1795
+ * Determine if a comparison passes between the given values.
1796
+ */
1797
+ compareDates(value, parameter, operator, rule) {
1798
+ value = toDate(value);
1799
+ if (!value) throw `Validation rule ${rule} requires the field under valation to be a date.`;
1800
+ const compartedToValue = toDate(deepFind(this.data, parameter) || parameter);
1801
+ if (!compartedToValue) throw `Validation rule ${rule} requires the parameter to be a date.`;
1802
+ return compare(value.getTime(), compartedToValue.getTime(), operator);
1803
+ }
1804
+ /**
1805
+ * Require a certain number of parameters to be present
1806
+ */
1807
+ requireParameterCount(count, parameters, rule) {
1808
+ if (parameters.length < count) throw `Validation rule ${rule} requires at least ${count} parameters.`;
1809
+ }
1810
+ /**
1811
+ * Prepare the values for validation
1812
+ */
1813
+ parseDependentRuleParameters(other, parameters) {
1814
+ let values = parameters.slice(1);
1815
+ if (other === null) values = convertValuesToNull(values);
1816
+ if (typeof other === "number") values = convertValuesToNumber(values);
1817
+ if (typeof other === "boolean") values = convertValuesToBoolean(values);
1818
+ return values;
1819
+ }
1820
+ };
1821
+
1822
+ //#endregion
1823
+ //#region src/BaseValidator.ts
1824
+ var BaseValidator = class {
1825
+ /**
1826
+ * The lang used to return error messages
1827
+ */
1828
+ lang;
1829
+ /**
1830
+ * The data object that will be validated
1831
+ */
1832
+ data;
1833
+ /**
1834
+ * The rules that will be used to check the validity of the data
1835
+ */
1836
+ rules;
1837
+ /**
1838
+ * This is an unchanged version of the inital rules before being changed for wildcard validations
1839
+ */
1840
+ initalRules;
1841
+ /**
1842
+ * The array of wildcard attributes with their asterisks expanded.
1843
+ */
1844
+ implicitAttributes;
1845
+ /**
1846
+ * Hold the error messages
1847
+ */
1848
+ messages;
1849
+ /**
1850
+ * Stores an instance of the validateAttributes class
1851
+ */
1852
+ validateAttributes;
1853
+ /**
1854
+ * Flag that defines wether or not validation should stop on first failure
1855
+ */
1856
+ stopOnFirstFailureFlag;
1857
+ /**
1858
+ * Custom messages returned based on the error
1859
+ */
1860
+ customMessages;
1861
+ /**
1862
+ * Object of custom attribute name;
1863
+ */
1864
+ customAttributes;
1865
+ constructor(data, rules, customMessages = {}, customAttributes = {}) {
1866
+ this.data = data;
1867
+ this.customMessages = dotify(customMessages);
1868
+ this.customAttributes = dotify(customAttributes);
1869
+ this.initalRules = rules;
1870
+ this.lang = Lang.getDefaultLang();
1871
+ this.addRules(rules);
1872
+ this.messages = new ErrorBag();
1873
+ }
1874
+ setData(data) {
1875
+ this.data = data;
1876
+ this.addRules(this.initalRules);
1877
+ return this;
1878
+ }
1879
+ setRules(rules) {
1880
+ this.addRules(rules);
1881
+ this.initalRules = rules;
1882
+ return this;
1883
+ }
1884
+ setLang(lang) {
1885
+ this.lang = lang;
1886
+ return this;
1887
+ }
1888
+ getLang() {
1889
+ return this.lang;
1890
+ }
1891
+ setCustomMessages(customMessages = {}) {
1892
+ this.customMessages = dotify(customMessages);
1893
+ return this;
1894
+ }
1895
+ setCustomAttributes(customAttributes = {}) {
1896
+ this.customAttributes = dotify(customAttributes);
1897
+ return this;
1898
+ }
1899
+ stopOnFirstFailure(stopOnFirstFailure = true) {
1900
+ this.stopOnFirstFailureFlag = stopOnFirstFailure;
1901
+ return this;
1902
+ }
1903
+ errors() {
1904
+ return this.messages;
1905
+ }
1906
+ clearErrors(keys = []) {
1907
+ this.messages = this.messages.clear(keys).clone();
1908
+ return this.messages;
1909
+ }
1910
+ /**
1911
+ * Create a new ErrorBag instance and set the custom errors, thus removing previous error messages
1912
+ */
1913
+ setErrors(errors) {
1914
+ this.messages = new ErrorBag();
1915
+ this.addCustomErrors(errors);
1916
+ return this.messages;
1917
+ }
1918
+ /**
1919
+ * Append the error messages to the existing ErrorBag instance, thus preserving the old error messages if any
1920
+ */
1921
+ appendErrors(errors) {
1922
+ this.addCustomErrors(errors, true);
1923
+ return this.messages.clone();
1924
+ }
1925
+ /**
1926
+ * Run the validator's rules against its data.
1927
+ */
1928
+ validate(key = "", value = void 0) {
1929
+ if (!isObject(this.data)) throw "The data attribute must be an object";
1930
+ this.validateAttributes = new validateAttributes(this.data, this.rules);
1931
+ if (!key) {
1932
+ this.runAllValidations();
1933
+ return this.messages.keys().length === 0;
1934
+ } else {
1935
+ this.runSingleValidation(key, value);
1936
+ return !this.messages.has(key);
1937
+ }
1938
+ }
1939
+ /**
1940
+ * Run the validator's rules against its data asynchronously.
1941
+ */
1942
+ async validateAsync(key = "", value = void 0) {
1943
+ if (!isObject(this.data)) throw "The data attribute must be an object";
1944
+ this.validateAttributes = new validateAttributes(this.data, this.rules);
1945
+ if (!key) {
1946
+ await this.runAllValidationsAsync();
1947
+ return this.messages.keys().length === 0;
1948
+ } else {
1949
+ await this.runSingleValidationAsync(key, value);
1950
+ return !this.messages.has(key);
1951
+ }
1952
+ }
1953
+ /**
1954
+ * Get the displayable name of the attribute.
1955
+ */
1956
+ getDisplayableAttribute(attribute) {
1957
+ const primaryAttribute = this.getPrimaryAttribute(attribute);
1958
+ const attributeCombinations = getKeyCombinations(attribute);
1959
+ const translatedAttributes = dotify(Lang.get(this.lang)["attributes"] || {});
1960
+ let expectedAttributes = attributeCombinations;
1961
+ if (attribute !== primaryAttribute) {
1962
+ expectedAttributes = [];
1963
+ const primaryAttributeCombinations = getKeyCombinations(primaryAttribute);
1964
+ for (let i = 0; i < attributeCombinations.length; i++) {
1965
+ expectedAttributes.push(attributeCombinations[i]);
1966
+ if (attributeCombinations[i] !== primaryAttributeCombinations[i]) expectedAttributes.push(primaryAttributeCombinations[i]);
1967
+ }
1968
+ }
1969
+ let name = "";
1970
+ let line = "";
1971
+ for (let i = 0; i < expectedAttributes.length; i++) {
1972
+ name = expectedAttributes[i];
1973
+ if (Object.prototype.hasOwnProperty.call(this.customAttributes, name)) return this.customAttributes[name];
1974
+ line = translatedAttributes[name];
1975
+ if (typeof line === "string") return line;
1976
+ }
1977
+ return getFormattedAttribute(attribute);
1978
+ }
1979
+ addCustomErrors(errors, shouldClearErrors = false) {
1980
+ let newErrors;
1981
+ if (shouldClearErrors) this.messages.clear(Object.keys(errors));
1982
+ for (const key in errors) {
1983
+ newErrors = typeof errors[key] === "string" ? [errors[key]] : errors[key];
1984
+ newErrors.forEach((error) => {
1985
+ this.messages.add(key, {
1986
+ message: error,
1987
+ error_type: "custom"
1988
+ });
1989
+ });
1990
+ }
1991
+ }
1992
+ /**
1993
+ * Replace all error message place-holders with actual values.
1994
+ */
1995
+ makeReplacements(message, attribute, rule, parameters = [], hasNumericRule = false) {
1996
+ message = message.replace(":attribute", attribute);
1997
+ const methodName = `replace${buildValidationMethodName(rule)}`;
1998
+ if (typeof replaceAttributes[methodName] === "function") {
1999
+ const payload = new replaceAttributePayload(this.data, message, parameters, hasNumericRule, ((attribute) => {
2000
+ return this.getDisplayableAttribute(attribute);
2001
+ }).bind(this));
2002
+ message = replaceAttributes[methodName](payload);
2003
+ }
2004
+ return message;
2005
+ }
2006
+ /**
2007
+ * Loop through all rules and run validation against each one of them
2008
+ */
2009
+ runAllValidations() {
2010
+ this.messages = new ErrorBag();
2011
+ this.validateAttributes = new validateAttributes(this.data, this.rules);
2012
+ for (const property in this.rules) if (this.runValidation(property) === false) break;
2013
+ }
2014
+ /**
2015
+ * Loop through all rules and run validation against each one of them asynchronously.
2016
+ */
2017
+ async runAllValidationsAsync() {
2018
+ this.messages = new ErrorBag();
2019
+ this.validateAttributes = new validateAttributes(this.data, this.rules);
2020
+ for (const property in this.rules) if (await this.runValidationAsync(property) === false) break;
2021
+ }
2022
+ /**
2023
+ * Run validation for one specific attribute
2024
+ */
2025
+ runSingleValidation(key, value = void 0) {
2026
+ this.clearErrors([key]);
2027
+ if (typeof value !== "undefined") deepSet(this.data, key, value);
2028
+ this.runValidation(key);
2029
+ }
2030
+ /**
2031
+ * Run validation for one specific attribute asynchronously.
2032
+ */
2033
+ async runSingleValidationAsync(key, value = void 0) {
2034
+ this.clearErrors([key]);
2035
+ if (typeof value !== "undefined") deepSet(this.data, key, value);
2036
+ await this.runValidationAsync(key);
2037
+ }
2038
+ /**
2039
+ * Run validation rules for the specified property and stop validation if needed
2040
+ */
2041
+ runValidation(property) {
2042
+ if (Object.prototype.hasOwnProperty.call(this.rules, property) && Array.isArray(this.rules[property])) for (let i = 0; i < this.rules[property].length; i++) {
2043
+ this.validateAttribute(property, this.rules[property][i]);
2044
+ if (this.messages.keys().length > 0 && this.stopOnFirstFailureFlag === true) return false;
2045
+ if (this.shouldStopValidating(property)) break;
2046
+ }
2047
+ }
2048
+ /**
2049
+ * Run validation rules for the specified property asynchronously and stop validation if needed
2050
+ */
2051
+ async runValidationAsync(property) {
2052
+ if (Object.prototype.hasOwnProperty.call(this.rules, property) && Array.isArray(this.rules[property])) for (let i = 0; i < this.rules[property].length; i++) {
2053
+ await this.validateAttribute(property, this.rules[property][i]);
2054
+ if (this.messages.keys().length > 0 && this.stopOnFirstFailureFlag === true) return false;
2055
+ if (this.shouldStopValidating(property)) break;
2056
+ }
2057
+ }
2058
+ /**
2059
+ * Check if we should stop further validations on a given attribute.
2060
+ */
2061
+ shouldStopValidating(attribute) {
2062
+ return this.messages.has(attribute) && validationRuleParser.hasRule(attribute, ["bail"], this.rules);
2063
+ }
2064
+ /**
2065
+ * Parse the given rules add assign them to the current rules
2066
+ */
2067
+ addRules(rules) {
2068
+ const response = validationRuleParser.explodeRules(dotify(rules, true), this.data);
2069
+ this.rules = response.rules;
2070
+ this.implicitAttributes = response.implicitAttributes;
2071
+ }
2072
+ /**
2073
+ * validate a given attribute against a rule.
2074
+ */
2075
+ validateAttribute(attribute, rule) {
2076
+ let parameters = [];
2077
+ [rule, parameters] = validationRuleParser.parse(rule);
2078
+ const keys = this.getExplicitKeys(attribute);
2079
+ if (keys.length > 0 && parameters.length > 0) parameters = this.replaceAsterisksInParameters(parameters, keys);
2080
+ const value = deepFind(this.data, attribute);
2081
+ const validatable = this.isValidatable(attribute, value, rule);
2082
+ if (rule instanceof IRuleContract) return validatable ? this.validateUsingCustomRule(attribute, value, rule) : void 0;
2083
+ const method = `validate${buildValidationMethodName(rule)}`;
2084
+ if (rule !== "" && typeof this.validateAttributes[method] === "undefined") throw `Rule ${rule} is not valid`;
2085
+ if (!validatable) return;
2086
+ const validation = this.validateAttributes[method](value, parameters, attribute);
2087
+ if (validation instanceof Promise) return validation.then((result) => {
2088
+ if (!result) this.addFailure(attribute, rule, value, parameters);
2089
+ });
2090
+ else if (!validation) this.addFailure(attribute, rule, value, parameters);
2091
+ }
2092
+ /**
2093
+ * Validate an attribute using a custom rule object
2094
+ */
2095
+ validateUsingCustomRule(attribute, value, rule) {
2096
+ rule.setData(this.data).setLang(this.lang);
2097
+ if (rule instanceof Password$1) rule.setValidator(this);
2098
+ const result = rule.passes(value, attribute);
2099
+ if (result instanceof Promise) return result.then((validationResult) => {
2100
+ if (!validationResult) this.setCustomRuleErrorMessages(attribute, rule);
2101
+ });
2102
+ if (!result) return this.setCustomRuleErrorMessages(attribute, rule);
2103
+ }
2104
+ /**
2105
+ * Set the error message linked to a custom validation rule
2106
+ */
2107
+ setCustomRuleErrorMessages(attribute, rule) {
2108
+ const result = rule.getMessage();
2109
+ const messages = typeof result === "string" ? [result] : result;
2110
+ for (const key in messages) this.messages.add(attribute, {
2111
+ error_type: rule.constructor.name,
2112
+ message: this.makeReplacements(messages[key], this.getDisplayableAttribute(attribute), rule.constructor.name)
2113
+ });
2114
+ }
2115
+ /**
2116
+ * Add a new error message to the messages object
2117
+ */
2118
+ addFailure(attribute, rule, value, parameters) {
2119
+ const hasNumericRule = validationRuleParser.hasRule(attribute, getNumericRules(), this.rules);
2120
+ const primaryAttribute = this.getPrimaryAttribute(attribute);
2121
+ const attributes = attribute !== primaryAttribute ? [attribute, primaryAttribute] : [attribute];
2122
+ const error = {
2123
+ error_type: rule,
2124
+ message: this.makeReplacements(getMessage(attributes, rule, value, this.customMessages, hasNumericRule, this.lang), this.getDisplayableAttribute(attribute), rule, parameters, hasNumericRule)
2125
+ };
2126
+ this.messages.add(attribute, error);
2127
+ }
2128
+ /**
2129
+ * Replace each field parameter which has asterisks with the given keys.
2130
+ *
2131
+ * Example: parameters = [name.*.first] and keys = [1], then the result will be name.1.first
2132
+ */
2133
+ replaceAsterisksInParameters(parameters, keys) {
2134
+ return parameters.map((parameter) => {
2135
+ let result = "";
2136
+ if (parameter.indexOf("*") !== -1) {
2137
+ const parameterArray = parameter.split("*");
2138
+ result = parameterArray[0];
2139
+ for (let i = 1; i < parameterArray.length; i++) result = result.concat((keys[i - 1] || "*") + parameterArray[i]);
2140
+ }
2141
+ return result || parameter;
2142
+ });
2143
+ }
2144
+ /**
2145
+ * Determine if the attribute is validatable.
2146
+ */
2147
+ isValidatable(attribute, value, rule) {
2148
+ return this.presentOrRuleIsImplicit(attribute, value, rule) && this.passesOptionalCheck(attribute) && this.isNotNullIfMarkedAsNullable(attribute, rule);
2149
+ }
2150
+ /**
2151
+ * Determine if the field is present, or the rule implies required.
2152
+ */
2153
+ presentOrRuleIsImplicit(attribute, value, rule) {
2154
+ if (typeof value === "string" && value.trim() === "") return isImplicitRule(rule);
2155
+ return typeof deepFind(this.data, attribute) !== "undefined" || isImplicitRule(rule);
2156
+ }
2157
+ /**
2158
+ * Determine if the attribute passes any optional check.
2159
+ */
2160
+ passesOptionalCheck(attribute) {
2161
+ if (!validationRuleParser.hasRule(attribute, ["sometimes"], this.rules)) return true;
2162
+ const data = validationData.initializeAndGatherData(attribute, this.data);
2163
+ return Object.prototype.hasOwnProperty.call(data, attribute) || Object.prototype.hasOwnProperty.call(this.data, attribute);
2164
+ }
2165
+ /**
2166
+ * Determine if the attribute fails the nullable check.
2167
+ */
2168
+ isNotNullIfMarkedAsNullable(attribute, rule) {
2169
+ if (isImplicitRule(rule) || !validationRuleParser.hasRule(attribute, ["nullable"], this.rules)) return true;
2170
+ return deepFind(this.data, attribute) !== null;
2171
+ }
2172
+ /**
2173
+ * Get the primary attribute name
2174
+ *
2175
+ * Example: if "name.0" is given, "name.*" will be returned
2176
+ */
2177
+ getPrimaryAttribute(attribute) {
2178
+ for (const unparsed in this.implicitAttributes) if (this.implicitAttributes[unparsed].indexOf(attribute) !== -1) return unparsed;
2179
+ return attribute;
2180
+ }
2181
+ /**
2182
+ * Get the explicit keys from an attribute flattened with dot notation.
2183
+ *
2184
+ * Example: 'foo.1.bar.spark.baz' -> [1, 'spark'] for 'foo.*.bar.*.baz'
2185
+ */
2186
+ getExplicitKeys(attribute) {
2187
+ const pattern = new RegExp("^" + this.getPrimaryAttribute(attribute).replace(/\*/g, "([^.]*)"));
2188
+ const keys = attribute.match(pattern);
2189
+ if (keys) {
2190
+ keys.shift();
2191
+ return keys;
2192
+ }
2193
+ return [];
2194
+ }
2195
+ };
2196
+
2197
+ //#endregion
2198
+ //#region src/Contracts/IDatabaseDriver.ts
2199
+ var IDatabaseDriver = class {};
2200
+
2201
+ //#endregion
2202
+ //#region src/Rules/registerRule.ts
2203
+ function register(rule, validate, replaceMessage) {
2204
+ const method = buildValidationMethodName(rule);
2205
+ if (new validateAttributes()[`validate${method}`]) return false;
2206
+ validateAttributes.prototype[`validate${method}`] = validate;
2207
+ if (typeof replaceMessage === "function") replaceAttributes[`replace${method}`] = ({ message, parameters, data, getDisplayableAttribute }) => replaceMessage(message, parameters, data, getDisplayableAttribute);
2208
+ return true;
2209
+ }
2210
+ function registerImplicit(rule, validate, replaceMessage) {
2211
+ if (register(rule, validate, replaceMessage) === true) addImplicitRule(rule);
2212
+ }
2213
+
2214
+ //#endregion
2215
+ //#region src/Rules/in.ts
2216
+ var In = class extends BaseRule {
2217
+ /**
2218
+ * The name of the rule.
2219
+ */
2220
+ rule = "in";
2221
+ /**
2222
+ * The accepted values.
2223
+ */
2224
+ values = [];
2225
+ /**
2226
+ * Create a new In rule instance.
2227
+ */
2228
+ constructor(values) {
2229
+ super();
2230
+ this.values = values;
2231
+ }
2232
+ /**
2233
+ * Convert the rule to a validation string.
2234
+ */
2235
+ toString() {
2236
+ return `${this.rule}:${this.values.join(",")}`;
2237
+ }
2238
+ };
2239
+
2240
+ //#endregion
2241
+ //#region src/Rules/notIn.ts
2242
+ var NotIn = class extends BaseRule {
2243
+ /**
2244
+ * The name of the rule.
2245
+ */
2246
+ rule = "not_in";
2247
+ /**
2248
+ * The accepted values.
2249
+ */
2250
+ values = [];
2251
+ /**
2252
+ * Create a new NotIn rule instance.
2253
+ */
2254
+ constructor(values) {
2255
+ super();
2256
+ this.values = values;
2257
+ }
2258
+ /**
2259
+ * Convert the rule to a validation string.
2260
+ */
2261
+ toString() {
2262
+ return `${this.rule}:${this.values.join(",")}`;
2263
+ }
2264
+ };
2265
+
2266
+ //#endregion
2267
+ //#region src/Rules/regex.ts
2268
+ var Regex = class extends IRuleContract {
2269
+ /**
2270
+ * The Regular expression to validate
2271
+ */
2272
+ regex;
2273
+ /**
2274
+ * Flag that decides whether the value should match the regular expression or not
2275
+ */
2276
+ shouldMatch;
2277
+ constructor(regex, shouldMatch = true) {
2278
+ super();
2279
+ this.regex = regex;
2280
+ this.shouldMatch = shouldMatch;
2281
+ }
2282
+ passes(value) {
2283
+ if (this.shouldMatch) return this.regex.test(value);
2284
+ return !this.regex.test(value);
2285
+ }
2286
+ getMessage() {
2287
+ if (this.shouldMatch) return this.trans("regex");
2288
+ return this.trans("not_regex");
2289
+ }
2290
+ };
2291
+
2292
+ //#endregion
2293
+ //#region src/Rules/requiredIf.ts
2294
+ var RequiredIf = class extends BaseRule {
2295
+ /**
2296
+ * The condition that validates the attribute
2297
+ */
2298
+ condition;
2299
+ /**
2300
+ * Create a new required validation rule based on a condition.
2301
+ */
2302
+ constructor(condition) {
2303
+ super();
2304
+ this.condition = condition;
2305
+ }
2306
+ /**
2307
+ * Convert the rule to a validation string.
2308
+ */
2309
+ toString() {
2310
+ if (typeof this.condition === "function") return this.condition() ? "required" : "";
2311
+ return this.condition ? "required" : "";
2312
+ }
2313
+ };
2314
+
2315
+ //#endregion
2316
+ //#region src/rule.ts
2317
+ function requiredIf(callback) {
2318
+ return new RequiredIf(callback);
2319
+ }
2320
+ function ruleIn(values) {
2321
+ return new In(values);
2322
+ }
2323
+ function ruleNotIn(values) {
2324
+ return new NotIn(values);
2325
+ }
2326
+ function regex(value) {
2327
+ return new Regex(value);
2328
+ }
2329
+ function notRegex(value) {
2330
+ return new Regex(value, false);
2331
+ }
2332
+
2333
+ //#endregion
2334
+ //#region src/Core.ts
2335
+ var Password = class extends Password$1 {};
2336
+ function make(data = {}, rules = {}, customMessages = {}, customAttributes = {}) {
2337
+ return new BaseValidator(data, rules, customMessages, customAttributes);
2338
+ }
2339
+
2340
+ //#endregion
2341
+ //#region src/Rules/IImplicitRule.ts
2342
+ var IImplicitRule = class extends IRuleContract {
2343
+ __isImplicitRule = true;
2344
+ };
2345
+
2346
+ //#endregion
2347
+ //#region src/ImplicitRule.ts
2348
+ var ImplicitRule = class extends IImplicitRule {
2349
+ rules = [];
2350
+ };
2351
+
2352
+ //#endregion
2353
+ //#region src/Providers/ValidationServiceProvider.ts
2354
+ /**
2355
+ * Service provider for Validation utilities
2356
+ */
2357
+ var ValidationServiceProvider = class {
2358
+ registeredCommands;
2359
+ static priority = 895;
2360
+ constructor(app) {
2361
+ this.app = app;
2362
+ }
2363
+ /**
2364
+ * Register URL services in the container
2365
+ */
2366
+ register() {}
2367
+ /**
2368
+ * Boot URL services
2369
+ */
2370
+ boot() {}
2371
+ };
2372
+
2373
+ //#endregion
2374
+ //#region src/ValidationRule.ts
2375
+ var ValidationRule = class extends IRuleContract {
2376
+ rules = [];
2377
+ passing = false;
2378
+ /**
2379
+ * Set the data under validation.
2380
+ */
2381
+ setData(_data) {
2382
+ return this;
2383
+ }
2384
+ passes(value, attribute) {
2385
+ this.passing = true;
2386
+ this.validate(attribute, value, (message) => {
2387
+ this.message = message;
2388
+ this.passing = false;
2389
+ });
2390
+ return this.passing;
2391
+ }
2392
+ };
2393
+
2394
+ //#endregion
2395
+ //#region src/Rules/ExtendedRules.ts
2396
+ var ExtendedRules = class extends ValidationRule {
2397
+ /**
2398
+ * The validator instance.
2399
+ */
2400
+ validator;
2401
+ setValidator(validator) {
2402
+ this.validator = validator;
2403
+ return this;
2404
+ }
2405
+ resolveTarget(tableRef, attribute, parameters = []) {
2406
+ if (!tableRef) return null;
2407
+ const [connection, table] = tableRef.includes(".") ? tableRef.split(".", 2) : [void 0, tableRef];
2408
+ const [column] = parameters;
2409
+ const attributeColumn = attribute.includes(".") ? attribute.split(".").pop() : attribute;
2410
+ return {
2411
+ table,
2412
+ connection,
2413
+ column: column || attributeColumn
2414
+ };
2415
+ }
2416
+ rules = [
2417
+ {
2418
+ name: "hex",
2419
+ validator: (value) => {
2420
+ if (typeof value !== "string") return false;
2421
+ return /^[0-9a-fA-F]+$/.test(value.replace("#", ""));
2422
+ },
2423
+ message: "The :attribute must be a valid hexadecimal string."
2424
+ },
2425
+ {
2426
+ name: "includes",
2427
+ validator: (value, parameters = []) => {
2428
+ if (value == null) return false;
2429
+ if (Array.isArray(value)) return parameters.some((param) => value.includes(param));
2430
+ if (typeof value === "string") return parameters.some((param) => value.includes(param));
2431
+ return false;
2432
+ },
2433
+ message: "The :attribute must include one of the following values: :values."
2434
+ },
2435
+ {
2436
+ name: "not_includes",
2437
+ validator: (value, parameters = []) => {
2438
+ if (value == null) return true;
2439
+ if (Array.isArray(value)) return parameters.every((param) => !value.includes(param));
2440
+ if (typeof value === "string") return parameters.every((param) => !value.includes(param));
2441
+ return true;
2442
+ },
2443
+ message: "The :attribute must not include any of the following values: :values."
2444
+ },
2445
+ {
2446
+ name: "datetime",
2447
+ validator: (value, parameters = [], _attribute) => {
2448
+ if (typeof value !== "string") return false;
2449
+ const [format] = parameters;
2450
+ if (!format) return !isNaN(Date.parse(value));
2451
+ try {
2452
+ return new Date(value).toISOString() === new Date(format).toISOString();
2453
+ } catch {
2454
+ return !isNaN(Date.parse(value));
2455
+ }
2456
+ },
2457
+ message: "The :attribute must be a valid date matching the format :format."
2458
+ },
2459
+ {
2460
+ name: "exists",
2461
+ validator: async (value, parameters = [], attribute = "") => {
2462
+ const [tableRef, column, ignore] = parameters;
2463
+ const driver = this.validator?.getDatabaseDriver();
2464
+ if (!driver || !tableRef) return false;
2465
+ const target = this.resolveTarget(tableRef, attribute, [column]);
2466
+ if (!target?.column) return false;
2467
+ return await driver.exists({
2468
+ table: target.table,
2469
+ connection: target.connection,
2470
+ column: target.column,
2471
+ value,
2472
+ ignore,
2473
+ attribute,
2474
+ data: this.validator.getData()
2475
+ });
2476
+ },
2477
+ message: "The :attribute does not exist."
2478
+ },
2479
+ {
2480
+ name: "unique",
2481
+ validator: async (value, parameters = [], attribute = "") => {
2482
+ const [tableRef, column, ignore] = parameters;
2483
+ const driver = this.validator?.getDatabaseDriver();
2484
+ if (!driver || !tableRef) return false;
2485
+ const target = this.resolveTarget(tableRef, attribute, [column]);
2486
+ if (!target?.column) return false;
2487
+ return !await driver.exists({
2488
+ table: target.table,
2489
+ connection: target.connection,
2490
+ column: target.column,
2491
+ value,
2492
+ ignore,
2493
+ attribute,
2494
+ data: this.validator.getData()
2495
+ });
2496
+ },
2497
+ message: "The :attribute has already been taken."
2498
+ }
2499
+ ];
2500
+ validate() {}
2501
+ };
2502
+
2503
+ //#endregion
2504
+ //#region src/utilities/helpers.ts
2505
+ /**
2506
+ * Pluralizes a word based on the count.
2507
+ *
2508
+ * @param word
2509
+ * @param count
2510
+ * @returns
2511
+ */
2512
+ const plural = (word, count) => {
2513
+ return count === 1 ? word : `${word}s`;
2514
+ };
2515
+
2516
+ //#endregion
2517
+ //#region src/utilities/MessageBag.ts
2518
+ var MessageBag = class {
2519
+ /**
2520
+ * All of the registered messages.
2521
+ */
2522
+ messages = {};
2523
+ /**
2524
+ * Default format for message output.
2525
+ */
2526
+ format = ":message";
2527
+ /**
2528
+ * Create a new message bag instance.
2529
+ */
2530
+ constructor(messages = {}) {
2531
+ for (const [key, value] of Object.entries(messages)) {
2532
+ const arr = Array.isArray(value) ? value : [value];
2533
+ this.messages[key] = Array.from(new Set(arr));
2534
+ }
2535
+ }
2536
+ /**
2537
+ * Get all message keys.
2538
+ */
2539
+ keys() {
2540
+ return Object.keys(this.messages);
2541
+ }
2542
+ /**
2543
+ * Add a message.
2544
+ */
2545
+ add(key, message) {
2546
+ if (this.isUnique(key, message)) {
2547
+ if (!this.messages[key]) this.messages[key] = [];
2548
+ this.messages[key].push(message);
2549
+ }
2550
+ return this;
2551
+ }
2552
+ /**
2553
+ * Add a message conditionally.
2554
+ */
2555
+ addIf(condition, key, message) {
2556
+ return condition ? this.add(key, message) : this;
2557
+ }
2558
+ /**
2559
+ * Check uniqueness of key/message pair.
2560
+ */
2561
+ isUnique(key, message) {
2562
+ return !this.messages[key] || !this.messages[key].includes(message);
2563
+ }
2564
+ /**
2565
+ * Merge another message source into this one.
2566
+ */
2567
+ merge(messages) {
2568
+ const incoming = messages.getMessageBag?.()?.getMessages?.() ?? messages;
2569
+ for (const [key, list] of Object.entries(incoming)) {
2570
+ if (!this.messages[key]) this.messages[key] = [];
2571
+ this.messages[key].push(...list);
2572
+ this.messages[key] = Array.from(new Set(this.messages[key]));
2573
+ }
2574
+ return this;
2575
+ }
2576
+ /**
2577
+ * Determine if messages exist for all given keys.
2578
+ */
2579
+ has(key) {
2580
+ if (this.isEmpty()) return false;
2581
+ if (key == null) return this.any();
2582
+ return (Array.isArray(key) ? key : [key]).every((k) => this.first(k) !== "");
2583
+ }
2584
+ /**
2585
+ * Determine if messages exist for any given key.
2586
+ */
2587
+ hasAny(keys = []) {
2588
+ if (this.isEmpty()) return false;
2589
+ return (Array.isArray(keys) ? keys : [keys]).some((k) => this.has(k));
2590
+ }
2591
+ /**
2592
+ * Determine if messages don't exist for given keys.
2593
+ */
2594
+ missing(key) {
2595
+ const keys = Array.isArray(key) ? key : [key];
2596
+ return !this.hasAny(keys);
2597
+ }
2598
+ /**
2599
+ * Get the first message for a given key.
2600
+ */
2601
+ first(key = null, format = null) {
2602
+ const messages = key == null ? this.all(format) : this.get(key, format);
2603
+ const firstMessage = Array.isArray(messages) ? messages[0] ?? "" : "";
2604
+ return Array.isArray(firstMessage) ? firstMessage[0] ?? "" : firstMessage;
2605
+ }
2606
+ /**
2607
+ * Get all messages for a given key.
2608
+ */
2609
+ get(key, format = null) {
2610
+ if (this.messages[key]) return this.transform(this.messages[key], this.checkFormat(format), key);
2611
+ if (key.includes("*")) return this.getMessagesForWildcardKey(key, format);
2612
+ return [];
2613
+ }
2614
+ /**
2615
+ * Wildcard key match.
2616
+ */
2617
+ getMessagesForWildcardKey(key, format) {
2618
+ const regex = new RegExp("^" + key.replace(/\*/g, ".*") + "$");
2619
+ const result = {};
2620
+ for (const [messageKey, messages] of Object.entries(this.messages)) if (regex.test(messageKey)) result[messageKey] = this.transform(messages, this.checkFormat(format), messageKey);
2621
+ return result;
2622
+ }
2623
+ /**
2624
+ * Get all messages.
2625
+ */
2626
+ all(format = null) {
2627
+ const fmt = this.checkFormat(format);
2628
+ const all = [];
2629
+ for (const [key, messages] of Object.entries(this.messages)) all.push(...this.transform(messages, fmt, key));
2630
+ return all;
2631
+ }
2632
+ /**
2633
+ * Get unique messages.
2634
+ */
2635
+ unique(format = null) {
2636
+ return Array.from(new Set(this.all(format)));
2637
+ }
2638
+ /**
2639
+ * Remove messages for a key.
2640
+ */
2641
+ forget(key) {
2642
+ delete this.messages[key];
2643
+ return this;
2644
+ }
2645
+ /**
2646
+ * Format an array of messages.
2647
+ */
2648
+ transform(messages, format, messageKey) {
2649
+ if (format === ":message") return messages;
2650
+ return messages.map((m) => format.replace(":message", m).replace(":key", messageKey));
2651
+ }
2652
+ /**
2653
+ * Get proper format string.
2654
+ */
2655
+ checkFormat(format) {
2656
+ return format || this.format;
2657
+ }
2658
+ /**
2659
+ * Get raw messages.
2660
+ */
2661
+ messagesRaw() {
2662
+ return this.messages;
2663
+ }
2664
+ /**
2665
+ * Alias for messagesRaw().
2666
+ */
2667
+ getMessages() {
2668
+ return this.messagesRaw();
2669
+ }
2670
+ /**
2671
+ * Return message bag instance.
2672
+ */
2673
+ getMessageBag() {
2674
+ return this;
2675
+ }
2676
+ /**
2677
+ * Get format string.
2678
+ */
2679
+ getFormat() {
2680
+ return this.format;
2681
+ }
2682
+ /**
2683
+ * Set default message format.
2684
+ */
2685
+ setFormat(format = ":message") {
2686
+ this.format = format;
2687
+ return this;
2688
+ }
2689
+ /**
2690
+ * Empty checks.
2691
+ */
2692
+ isEmpty() {
2693
+ return !this.any();
2694
+ }
2695
+ isNotEmpty() {
2696
+ return this.any();
2697
+ }
2698
+ any() {
2699
+ return this.count() > 0;
2700
+ }
2701
+ /**
2702
+ * Count total messages.
2703
+ */
2704
+ count() {
2705
+ return Object.values(this.messages).reduce((sum, list) => sum + list.length, 0);
2706
+ }
2707
+ /**
2708
+ * Array & JSON conversions.
2709
+ */
2710
+ toArray() {
2711
+ return this.getMessages();
2712
+ }
2713
+ jsonSerialize() {
2714
+ return this.toArray();
2715
+ }
2716
+ toJson(options = 0) {
2717
+ return JSON.stringify(this.jsonSerialize(), null, options ? 2 : void 0);
2718
+ }
2719
+ toPrettyJson() {
2720
+ return JSON.stringify(this.jsonSerialize(), null, 2);
2721
+ }
2722
+ /**
2723
+ * String representation.
2724
+ */
2725
+ toString() {
2726
+ return this.toJson();
2727
+ }
2728
+ };
2729
+
2730
+ //#endregion
2731
+ //#region src/Validator.ts
2732
+ var Validator = class Validator {
2733
+ static defaultDatabaseDriver;
2734
+ #messages;
2735
+ #after = [];
2736
+ data;
2737
+ rules;
2738
+ _errors;
2739
+ passing = false;
2740
+ executed = false;
2741
+ instance;
2742
+ databaseDriver;
2743
+ errorBagName = "default";
2744
+ registeredCustomRules = [new ExtendedRules()];
2745
+ shouldStopOnFirstFailure = false;
2746
+ constructor(data, rules, messages = {}) {
2747
+ register("telephone", function(value) {
2748
+ return /^\d{3}-\d{3}-\d{4}$/.test(value);
2749
+ });
2750
+ this.data = data;
2751
+ this.rules = rules;
2752
+ this.#messages = messages;
2753
+ this._errors = new MessageBag();
2754
+ this.bindServices();
2755
+ }
2756
+ /**
2757
+ * Validate the data and return the instance
2758
+ */
2759
+ static make(data, rules, messages = {}) {
2760
+ return new Validator(data, rules, messages);
2761
+ }
2762
+ static useDatabase(driver) {
2763
+ Validator.defaultDatabaseDriver = driver;
2764
+ return Validator;
2765
+ }
2766
+ /**
2767
+ * Run the validator and store results.
2768
+ */
2769
+ async passes() {
2770
+ if (this.executed) return this._errors.isEmpty();
2771
+ const exec = await this.execute();
2772
+ for (const after of this.#after) after();
2773
+ return exec.passing;
2774
+ }
2775
+ /**
2776
+ * Opposite of passes()
2777
+ */
2778
+ async fails() {
2779
+ return !await this.passes();
2780
+ }
2781
+ /**
2782
+ * Throw if validation fails, else return executed data
2783
+ *
2784
+ * @throws ValidationException if validation fails
2785
+ */
2786
+ async validate() {
2787
+ if (!await this.passes()) throw new ValidationException(this, JSON.stringify(this._errors.toArray()));
2788
+ return this.validatedData();
2789
+ }
2790
+ /**
2791
+ * Run the validator's rules against its data.
2792
+ * @param bagName
2793
+ * @returns
2794
+ */
2795
+ async validateWithBag(bagName) {
2796
+ this.errorBagName = bagName;
2797
+ return this.validate();
2798
+ }
2799
+ /**
2800
+ * Stop validation on first failure.
2801
+ */
2802
+ stopOnFirstFailure() {
2803
+ this.shouldStopOnFirstFailure = true;
2804
+ return this;
2805
+ }
2806
+ /**
2807
+ * Get the data that passed validation.
2808
+ */
2809
+ validatedData() {
2810
+ const validKeys = Object.keys(this.rules);
2811
+ const clean = {};
2812
+ for (const key of validKeys) if (this.data[key] !== void 0) clean[key] = this.data[key];
2813
+ return clean;
2814
+ }
2815
+ /**
2816
+ * Return all validated input.
2817
+ */
2818
+ validated() {
2819
+ return Object.fromEntries(Object.entries(this.data).filter(([key]) => key in this.rules));
2820
+ }
2821
+ /**
2822
+ * Return a portion of validated input
2823
+ */
2824
+ safe() {
2825
+ const validated = this.validated();
2826
+ return {
2827
+ only: (keys) => Object.fromEntries(Object.entries(validated).filter(([key]) => keys.includes(key))),
2828
+ except: (keys) => Object.fromEntries(Object.entries(validated).filter(([key]) => !keys.includes(key)))
2829
+ };
2830
+ }
2831
+ /**
2832
+ * Get the message container for the validator.
2833
+ */
2834
+ async messages() {
2835
+ if (!this.#messages) await this.passes();
2836
+ return this.#messages;
2837
+ }
2838
+ /**
2839
+ * Add an after validation callback.
2840
+ *
2841
+ * @param callback
2842
+ */
2843
+ after(callback) {
2844
+ if (Array.isArray(callback)) for (const rule of callback) this.#after.push(() => rule.toString().startsWith("class") ? new rule(this) : rule(this));
2845
+ else if (typeof callback === "function") this.#after.push(() => callback(this));
2846
+ return this;
2847
+ }
2848
+ /**
2849
+ * Get all errors.
2850
+ */
2851
+ errors() {
2852
+ return this._errors;
2853
+ }
2854
+ errorBag() {
2855
+ return this.errorBagName;
2856
+ }
2857
+ /**
2858
+ * Reset validator with new data.
2859
+ */
2860
+ setData(data) {
2861
+ this.data = data;
2862
+ this.executed = false;
2863
+ return this;
2864
+ }
2865
+ /**
2866
+ * Set validation rules.
2867
+ */
2868
+ setRules(rules) {
2869
+ this.rules = rules;
2870
+ this.executed = false;
2871
+ return this;
2872
+ }
2873
+ /**
2874
+ * Add a single rule to existing rules.
2875
+ */
2876
+ addRule(key, rule) {
2877
+ this.rules[key] = rule;
2878
+ return this;
2879
+ }
2880
+ /**
2881
+ * Merge additional rules.
2882
+ */
2883
+ mergeRules(rules) {
2884
+ this.rules = {
2885
+ ...this.rules,
2886
+ ...rules
2887
+ };
2888
+ return this;
2889
+ }
2890
+ /**
2891
+ * Get current data.
2892
+ */
2893
+ getData() {
2894
+ return this.data;
2895
+ }
2896
+ /**
2897
+ * Get current rules.
2898
+ */
2899
+ getRules() {
2900
+ return this.rules;
2901
+ }
2902
+ database(driver) {
2903
+ this.databaseDriver = driver;
2904
+ Validator.defaultDatabaseDriver = driver;
2905
+ return this;
2906
+ }
2907
+ getDatabaseDriver() {
2908
+ return this.databaseDriver ?? Validator.defaultDatabaseDriver;
2909
+ }
2910
+ /**
2911
+ * Bind all required services here.
2912
+ */
2913
+ bindServices() {
2914
+ /**
2915
+ * Register all custom rules
2916
+ */
2917
+ for (const reged of this.registeredCustomRules) if (reged instanceof ValidationRule) {
2918
+ if (reged.setData) reged.setData(this.data);
2919
+ if (reged.setValidator) reged.setValidator(this);
2920
+ for (const rule of reged.rules) {
2921
+ register(rule.name, rule.validator);
2922
+ if (rule.message) Lang.setTranslationObject({ en: { [rule.name]: rule.message } });
2923
+ }
2924
+ }
2925
+ return this;
2926
+ }
2927
+ async execute() {
2928
+ const instance = make().setData(this.data).setRules(this.rules).setCustomMessages(this.#messages).stopOnFirstFailure(this.shouldStopOnFirstFailure);
2929
+ this.passing = await instance.validateAsync();
2930
+ this.executed = true;
2931
+ this.instance = instance;
2932
+ if (!this.passing) this._errors = new MessageBag(instance.errors().all());
2933
+ return this;
2934
+ }
2935
+ };
2936
+
2937
+ //#endregion
2938
+ //#region src/ValidationException.ts
2939
+ var ValidationException = class ValidationException extends Error {
2940
+ validator;
2941
+ response;
2942
+ status = 422;
2943
+ errorBag = "default";
2944
+ redirectTo;
2945
+ name = "ValidationException";
2946
+ constructor(validator, response = null, errorBag = "default") {
2947
+ super(ValidationException.summarize(validator));
2948
+ this.validator = validator;
2949
+ this.response = response;
2950
+ this.errorBag = errorBag;
2951
+ Object.setPrototypeOf(this, ValidationException.prototype);
2952
+ }
2953
+ /**
2954
+ * Send a custom response body for this exception
2955
+ *
2956
+ * @param request
2957
+ * @returns
2958
+ */
2959
+ toResponse() {
2960
+ return {
2961
+ message: this.message,
2962
+ errors: this.errors()
2963
+ };
2964
+ }
2965
+ /**
2966
+ * Create a new validation exception from a plain array of messages.
2967
+ */
2968
+ static withMessages(messages) {
2969
+ const validator = new Validator({}, {});
2970
+ const bag = new MessageBag();
2971
+ for (const [key, value] of Object.entries(messages)) {
2972
+ const list = Array.isArray(value) ? value : [value];
2973
+ for (const message of list) bag.add(key, message);
2974
+ }
2975
+ validator._errors = bag;
2976
+ return new ValidationException(validator);
2977
+ }
2978
+ /**
2979
+ * Create a readable summary message from the validation errors.
2980
+ */
2981
+ static summarize(validator) {
2982
+ const messages = validator.errors().all();
2983
+ if (!messages.length || typeof messages[0] !== "string") return "The given data was invalid.";
2984
+ let message = messages.shift();
2985
+ const count = messages.length;
2986
+ if (count > 0) message += ` (and ${count} more ${plural("error", count)})`;
2987
+ return message;
2988
+ }
2989
+ /**
2990
+ * Get all of the validation error messages.
2991
+ */
2992
+ errors() {
2993
+ return this.validator.errors().getMessages();
2994
+ }
2995
+ /**
2996
+ * Set the HTTP status code to be used for the response.
2997
+ */
2998
+ setStatus(status) {
2999
+ this.status = status;
3000
+ return this;
3001
+ }
3002
+ /**
3003
+ * Set the error bag on the exception.
3004
+ */
3005
+ setErrorBag(errorBag) {
3006
+ this.errorBag = errorBag;
3007
+ return this;
3008
+ }
3009
+ /**
3010
+ * Set the URL to redirect to on a validation error.
3011
+ */
3012
+ setRedirectTo(url) {
3013
+ this.redirectTo = url;
3014
+ return this;
3015
+ }
3016
+ /**
3017
+ * Get the underlying response instance.
3018
+ */
3019
+ getResponse() {
3020
+ return this.response;
3021
+ }
3022
+ };
3023
+
3024
+ //#endregion
3025
+ exports.BaseValidator = BaseValidator;
3026
+ exports.ErrorBag = ErrorBag;
3027
+ exports.ExtendedRules = ExtendedRules;
3028
+ exports.IDatabaseDriver = IDatabaseDriver;
3029
+ exports.ImplicitRule = ImplicitRule;
3030
+ exports.Lang = Lang;
3031
+ exports.MessageBag = MessageBag;
3032
+ exports.Password = Password;
3033
+ exports.ValidationException = ValidationException;
3034
+ exports.ValidationRule = ValidationRule;
3035
+ exports.ValidationServiceProvider = ValidationServiceProvider;
3036
+ exports.Validator = Validator;
3037
+ exports.addImplicitRule = addImplicitRule;
3038
+ exports.buildValidationMethodName = buildValidationMethodName;
3039
+ exports.compare = compare;
3040
+ exports.convertValuesToBoolean = convertValuesToBoolean;
3041
+ exports.convertValuesToNull = convertValuesToNull;
3042
+ exports.convertValuesToNumber = convertValuesToNumber;
3043
+ exports.deepEqual = deepEqual;
3044
+ exports.deepFind = deepFind;
3045
+ exports.deepSet = deepSet;
3046
+ exports.dotify = dotify;
3047
+ exports.getFormattedAttribute = getFormattedAttribute;
3048
+ exports.getKeyCombinations = getKeyCombinations;
3049
+ exports.getMessage = getMessage;
3050
+ exports.getNumericRules = getNumericRules;
3051
+ exports.getSize = getSize;
3052
+ exports.isArrayOfRules = isArrayOfRules;
3053
+ exports.isImplicitRule = isImplicitRule;
3054
+ exports.isInteger = isInteger;
3055
+ exports.isNumericRule = isNumericRule;
3056
+ exports.isObject = isObject;
3057
+ exports.isRule = isRule;
3058
+ exports.isSizeRule = isSizeRule;
3059
+ exports.make = make;
3060
+ exports.mergeDeep = mergeDeep;
3061
+ exports.notRegex = notRegex;
3062
+ exports.plural = plural;
3063
+ exports.regex = regex;
3064
+ exports.register = register;
3065
+ exports.registerImplicit = registerImplicit;
3066
+ exports.requiredIf = requiredIf;
3067
+ exports.ruleIn = ruleIn;
3068
+ exports.ruleNotIn = ruleNotIn;
3069
+ exports.sameType = sameType;
3070
+ exports.toDate = toDate;
3071
+ exports.toSnakeCase = toSnakeCase;