@impelsys/validatorjs 3.22.2

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.
Files changed (109) hide show
  1. package/.eslintrc.js +27 -0
  2. package/CONTRIBUTE.md +34 -0
  3. package/LICENSE +20 -0
  4. package/README.md +607 -0
  5. package/dist/lang/ar.js +66 -0
  6. package/dist/lang/az.js +104 -0
  7. package/dist/lang/be.js +105 -0
  8. package/dist/lang/bg.js +105 -0
  9. package/dist/lang/bs.js +106 -0
  10. package/dist/lang/ca.js +40 -0
  11. package/dist/lang/cs.js +107 -0
  12. package/dist/lang/cy.js +106 -0
  13. package/dist/lang/da.js +51 -0
  14. package/dist/lang/de.js +46 -0
  15. package/dist/lang/el.js +43 -0
  16. package/dist/lang/en.js +54 -0
  17. package/dist/lang/es.js +40 -0
  18. package/dist/lang/et.js +106 -0
  19. package/dist/lang/eu.js +106 -0
  20. package/dist/lang/fa.js +42 -0
  21. package/dist/lang/fi.js +51 -0
  22. package/dist/lang/fr.js +40 -0
  23. package/dist/lang/hr.js +106 -0
  24. package/dist/lang/hu.js +106 -0
  25. package/dist/lang/id.js +51 -0
  26. package/dist/lang/it.js +41 -0
  27. package/dist/lang/ja.js +54 -0
  28. package/dist/lang/ka.js +106 -0
  29. package/dist/lang/ko.js +106 -0
  30. package/dist/lang/lt.js +106 -0
  31. package/dist/lang/lv.js +106 -0
  32. package/dist/lang/mk.js +106 -0
  33. package/dist/lang/mn.js +106 -0
  34. package/dist/lang/ms.js +106 -0
  35. package/dist/lang/nb_NO.js +42 -0
  36. package/dist/lang/nl.js +51 -0
  37. package/dist/lang/pl.js +42 -0
  38. package/dist/lang/pt.js +110 -0
  39. package/dist/lang/pt_BR.js +105 -0
  40. package/dist/lang/ro.js +51 -0
  41. package/dist/lang/ru.js +40 -0
  42. package/dist/lang/se.js +106 -0
  43. package/dist/lang/sl.js +106 -0
  44. package/dist/lang/sq.js +106 -0
  45. package/dist/lang/sr.js +106 -0
  46. package/dist/lang/sv.js +105 -0
  47. package/dist/lang/tr.js +51 -0
  48. package/dist/lang/ua.js +40 -0
  49. package/dist/lang/uk.js +106 -0
  50. package/dist/lang/vi.js +42 -0
  51. package/dist/lang/zh.js +42 -0
  52. package/dist/lang/zh_TW.js +42 -0
  53. package/dist/validator.js +2183 -0
  54. package/package.json +78 -0
  55. package/src/async.js +81 -0
  56. package/src/attributes.js +199 -0
  57. package/src/errors.js +77 -0
  58. package/src/lang/ar.js +63 -0
  59. package/src/lang/az.js +101 -0
  60. package/src/lang/be.js +102 -0
  61. package/src/lang/bg.js +102 -0
  62. package/src/lang/bs.js +103 -0
  63. package/src/lang/ca.js +37 -0
  64. package/src/lang/cs.js +104 -0
  65. package/src/lang/cy.js +103 -0
  66. package/src/lang/da.js +48 -0
  67. package/src/lang/de.js +43 -0
  68. package/src/lang/el.js +40 -0
  69. package/src/lang/en.js +51 -0
  70. package/src/lang/es.js +37 -0
  71. package/src/lang/et.js +103 -0
  72. package/src/lang/eu.js +103 -0
  73. package/src/lang/fa.js +39 -0
  74. package/src/lang/fi.js +48 -0
  75. package/src/lang/fr.js +37 -0
  76. package/src/lang/hr.js +103 -0
  77. package/src/lang/hu.js +103 -0
  78. package/src/lang/id.js +48 -0
  79. package/src/lang/it.js +38 -0
  80. package/src/lang/ja.js +51 -0
  81. package/src/lang/ka.js +103 -0
  82. package/src/lang/ko.js +103 -0
  83. package/src/lang/lt.js +103 -0
  84. package/src/lang/lv.js +103 -0
  85. package/src/lang/mk.js +103 -0
  86. package/src/lang/mn.js +103 -0
  87. package/src/lang/ms.js +103 -0
  88. package/src/lang/nb_NO.js +39 -0
  89. package/src/lang/nl.js +48 -0
  90. package/src/lang/pl.js +39 -0
  91. package/src/lang/pt.js +107 -0
  92. package/src/lang/pt_BR.js +102 -0
  93. package/src/lang/ro.js +48 -0
  94. package/src/lang/ru.js +37 -0
  95. package/src/lang/se.js +47 -0
  96. package/src/lang/sl.js +103 -0
  97. package/src/lang/sq.js +103 -0
  98. package/src/lang/sr.js +103 -0
  99. package/src/lang/sv.js +102 -0
  100. package/src/lang/tr.js +48 -0
  101. package/src/lang/ua.js +37 -0
  102. package/src/lang/uk.js +103 -0
  103. package/src/lang/vi.js +39 -0
  104. package/src/lang/zh.js +39 -0
  105. package/src/lang/zh_TW.js +39 -0
  106. package/src/lang.js +78 -0
  107. package/src/messages.js +152 -0
  108. package/src/rules.js +864 -0
  109. package/src/validator.js +662 -0
package/src/rules.js ADDED
@@ -0,0 +1,864 @@
1
+
2
+ // https://docs.microsoft.com/en-us/office/troubleshoot/excel/determine-a-leap-year
3
+ function leapYear(year) {
4
+ return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
5
+ }
6
+
7
+ function checkFalsePositiveDates(dateString = '') {
8
+
9
+ if (dateString.length === 10) {
10
+
11
+ // massage input to use yyyy-mm-dd format
12
+ // we support yyyy/mm/dd or yyyy.mm.dd
13
+ let normalizedDate = dateString.replace('.', '-').replace('/', '-');
14
+ let parts = normalizedDate.split('-');
15
+ if (parts.length === 3) {
16
+ if (parts[0].length === 4) {
17
+ // yyyy-mm-dd format
18
+ let y = parseInt(parts[0]);
19
+ let m = parseInt(parts[1]);
20
+ let d = parseInt(parts[2]);
21
+ if (m === 2) {
22
+ // return leapYear(y) ? d <= 29 : d <= 28;
23
+ if (leapYear(y)) {
24
+ if (d > 29) {
25
+ return false;
26
+ }
27
+ } else {
28
+ if (d > 28) {
29
+ return false;
30
+ }
31
+ }
32
+ }
33
+ if (m === 4 || m === 6 || m === 9 || m === 11) {
34
+ if (d > 30) {
35
+ return false;
36
+ }
37
+ }
38
+ }
39
+ }
40
+ return true; // we are not in feburary, proceed
41
+ }
42
+ return true; // we are not testing formatted date, proceed to rest of validation
43
+ }
44
+
45
+ function isValidDate(dateString) {
46
+ let testDate;
47
+ if (typeof dateString === 'number') {
48
+ testDate = new Date(dateString);
49
+ if (typeof testDate === 'object') {
50
+ return true;
51
+ }
52
+ }
53
+ // first convert incoming string to date object and see if it correct date and format
54
+ testDate = new Date(dateString);
55
+ if (typeof testDate === 'object') {
56
+ if (testDate.toString() === 'Invalid Date') {
57
+ return false;
58
+ }
59
+
60
+ /**
61
+ * Check for false positive dates
62
+ * perform special check on february as JS `new Date` incorrectly returns valid date
63
+ * Eg. let newDate = new Date('2020-02-29') // returns as March 02 2020
64
+ * Eg. let newDate = new Date('2019-02-29') // returns as March 01 2020
65
+ * Eg. let newDate = new Date('2019-04-31') // returns as April 30 2020
66
+ */
67
+ if (!checkFalsePositiveDates(dateString)) {
68
+ return false;
69
+ }
70
+
71
+ // valid date object and not a february date
72
+ return true;
73
+ }
74
+
75
+ // First check for the pattern
76
+ var regex_date = /^\d{4}\-\d{1,2}\-\d{1,2}$/;
77
+
78
+ if (!regex_date.test(dateString)) {
79
+ return false;
80
+ }
81
+
82
+ // Parse the date parts to integers
83
+ var parts = dateString.split("-");
84
+ var day = parseInt(parts[2], 10);
85
+ var month = parseInt(parts[1], 10);
86
+ var year = parseInt(parts[0], 10);
87
+
88
+ // Check the ranges of month and year
89
+ if (year < 1000 || year > 3000 || month == 0 || month > 12) {
90
+ return false;
91
+ }
92
+
93
+ var monthLength = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
94
+
95
+ // Adjust for leap years
96
+ if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
97
+ monthLength[1] = 29;
98
+ }
99
+
100
+ // Check the range of the day
101
+ return day > 0 && day <= monthLength[month - 1];
102
+ }
103
+
104
+ var rules = {
105
+ required: function (val) {
106
+ var str;
107
+
108
+ if (val === undefined || val === null) {
109
+ return false;
110
+ }
111
+
112
+ str = String(val).replace(/\s/g, "");
113
+ return str.length > 0 ? true : false;
114
+ },
115
+
116
+ required_if: function (val, req, attribute) {
117
+ req = this.getParameters();
118
+ if (this.validator._objectPath(this.validator.input, req[0]) === req[1]) {
119
+ return this.validator.getRule("required").validate(val);
120
+ }
121
+
122
+ return true;
123
+ },
124
+
125
+ required_unless: function (val, req, attribute) {
126
+ req = this.getParameters();
127
+ if (this.validator._objectPath(this.validator.input, req[0]) !== req[1]) {
128
+ return this.validator.getRule("required").validate(val);
129
+ }
130
+
131
+ return true;
132
+ },
133
+
134
+ required_with: function (val, req, attribute) {
135
+ if (this.validator._objectPath(this.validator.input, req)) {
136
+ return this.validator.getRule("required").validate(val);
137
+ }
138
+
139
+ return true;
140
+ },
141
+
142
+ required_with_all: function (val, req, attribute) {
143
+ req = this.getParameters();
144
+
145
+ for (var i = 0; i < req.length; i++) {
146
+ if (!this.validator._objectPath(this.validator.input, req[i])) {
147
+ return true;
148
+ }
149
+ }
150
+
151
+ return this.validator.getRule("required").validate(val);
152
+ },
153
+
154
+ required_without: function (val, req, attribute) {
155
+ if (this.validator._objectPath(this.validator.input, req)) {
156
+ return true;
157
+ }
158
+
159
+ return this.validator.getRule("required").validate(val);
160
+ },
161
+
162
+ required_without_all: function (val, req, attribute) {
163
+ req = this.getParameters();
164
+
165
+ for (var i = 0; i < req.length; i++) {
166
+ if (this.validator._objectPath(this.validator.input, req[i])) {
167
+ return true;
168
+ }
169
+ }
170
+
171
+ return this.validator.getRule("required").validate(val);
172
+ },
173
+
174
+ boolean: function (val) {
175
+ return (
176
+ val === true ||
177
+ val === false ||
178
+ val === 0 ||
179
+ val === 1 ||
180
+ val === "0" ||
181
+ val === "1" ||
182
+ val === "true" ||
183
+ val === "false"
184
+ );
185
+ },
186
+
187
+ // compares the size of strings
188
+ // with numbers, compares the value
189
+ size: function (val, req, attribute) {
190
+ if (val) {
191
+ req = parseFloat(req);
192
+
193
+ var size = this.getSize();
194
+
195
+ return size === req;
196
+ }
197
+
198
+ return true;
199
+ },
200
+
201
+ string: function (val, req, attribute) {
202
+ return typeof val === "string";
203
+ },
204
+
205
+ sometimes: function (val) {
206
+ return true;
207
+ },
208
+
209
+ /**
210
+ * Compares the size of strings or the value of numbers if there is a truthy value
211
+ */
212
+ min: function (val, req, attribute) {
213
+ var size = this.getSize();
214
+ return size >= req;
215
+ },
216
+
217
+ /**
218
+ * Compares the size of strings or the value of numbers if there is a truthy value
219
+ */
220
+ max: function (val, req, attribute) {
221
+ var size = this.getSize();
222
+ return size <= req;
223
+ },
224
+
225
+ between: function (val, req, attribute) {
226
+ req = this.getParameters();
227
+ var size = this.getSize();
228
+ var min = parseFloat(req[0], 10);
229
+ var max = parseFloat(req[1], 10);
230
+ return size >= min && size <= max;
231
+ },
232
+
233
+ email: function (val) {
234
+ // Added umlaut support https://github.com/skaterdav85/validatorjs/issues/308
235
+ var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
236
+ if (!re.test(val)) {
237
+ // added support domain 3-n level https://github.com/skaterdav85/validatorjs/issues/384
238
+ re = /^((?:[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]|[^\u0000-\u007F])+@(?:[a-zA-Z0-9]|[^\u0000-\u007F])(?:(?:[a-zA-Z0-9-]|[^\u0000-\u007F]){0,61}(?:[a-zA-Z0-9]|[^\u0000-\u007F]))?(?:\.(?:[a-zA-Z0-9]|[^\u0000-\u007F])(?:(?:[a-zA-Z0-9-]|[^\u0000-\u007F]){0,61}(?:[a-zA-Z0-9]|[^\u0000-\u007F]))?)+)*$/;
239
+ }
240
+ return re.test(val);
241
+ },
242
+
243
+ numeric: function (val) {
244
+ var num;
245
+
246
+ num = Number(val); // tries to convert value to a number. useful if value is coming from form element
247
+
248
+ if (typeof num === "number" && !isNaN(num) && typeof val !== "boolean") {
249
+ return true;
250
+ } else {
251
+ return false;
252
+ }
253
+ },
254
+
255
+ array: function (val) {
256
+ return val instanceof Array;
257
+ },
258
+
259
+ url: function (url) {
260
+ return /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-z]{2,63}\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)/i.test(url);
261
+ },
262
+
263
+ alpha: function (val) {
264
+ return /^[a-zA-Z]+$/.test(val);
265
+ },
266
+
267
+ alpha_dash: function (val) {
268
+ return /^[a-zA-Z0-9_\-]+$/.test(val);
269
+ },
270
+
271
+ alpha_num: function (val) {
272
+ return /^[a-zA-Z0-9]+$/.test(val);
273
+ },
274
+
275
+ same: function (val, req) {
276
+ var val1 = this.validator._flattenObject(this.validator.input)[req];
277
+ var val2 = val;
278
+
279
+ if (val1 === val2) {
280
+ return true;
281
+ }
282
+
283
+ return false;
284
+ },
285
+
286
+ different: function (val, req) {
287
+ var val1 = this.validator._flattenObject(this.validator.input)[req];
288
+ var val2 = val;
289
+
290
+ if (val1 !== val2) {
291
+ return true;
292
+ }
293
+
294
+ return false;
295
+ },
296
+
297
+ in: function (val, req) {
298
+ var list, i;
299
+
300
+ if (val) {
301
+ list = this.getParameters();
302
+ }
303
+
304
+ if (val && !(val instanceof Array)) {
305
+ var localValue = val;
306
+
307
+ for (i = 0; i < list.length; i++) {
308
+ if (typeof list[i] === "string") {
309
+ localValue = String(val);
310
+ }
311
+
312
+ if (localValue === list[i]) {
313
+ return true;
314
+ }
315
+ }
316
+
317
+ return false;
318
+ }
319
+
320
+ if (val && val instanceof Array) {
321
+ for (i = 0; i < val.length; i++) {
322
+ if (list.indexOf(val[i]) < 0) {
323
+ return false;
324
+ }
325
+ }
326
+ }
327
+
328
+ return true;
329
+ },
330
+
331
+ not_in: function (val, req) {
332
+ var list = this.getParameters();
333
+ var len = list.length;
334
+ var returnVal = true;
335
+
336
+ for (var i = 0; i < len; i++) {
337
+ var localValue = val;
338
+
339
+ if (typeof list[i] === "string") {
340
+ localValue = String(val);
341
+ }
342
+
343
+ if (localValue === list[i]) {
344
+ returnVal = false;
345
+ break;
346
+ }
347
+ }
348
+
349
+ return returnVal;
350
+ },
351
+
352
+ accepted: function (val) {
353
+ if (val === "on" || val === "yes" || val === 1 || val === "1" || val === true) {
354
+ return true;
355
+ }
356
+
357
+ return false;
358
+ },
359
+
360
+ confirmed: function (val, req, key) {
361
+ var confirmedKey = key + "_confirmation";
362
+
363
+ if (this.validator.input[confirmedKey] === val) {
364
+ return true;
365
+ }
366
+
367
+ return false;
368
+ },
369
+
370
+ integer: function (val) {
371
+ return String(parseInt(val, 10)) === String(val);
372
+ },
373
+
374
+ digits: function (val, req) {
375
+ var numericRule = this.validator.getRule('numeric');
376
+ if (numericRule.validate(val) && String(val.trim()).length === parseInt(req)) {
377
+ return true;
378
+ }
379
+
380
+ return false;
381
+ },
382
+
383
+ digits_between: function (val) {
384
+ var numericRule = this.validator.getRule("numeric");
385
+ var req = this.getParameters();
386
+ var valueDigitsCount = String(val).length;
387
+ var min = parseFloat(req[0], 10);
388
+ var max = parseFloat(req[1], 10);
389
+
390
+ if (numericRule.validate(val) && valueDigitsCount >= min && valueDigitsCount <= max) {
391
+ return true;
392
+ }
393
+
394
+ return false;
395
+ },
396
+
397
+ regex: function (val, req) {
398
+ let reqPattern = req;
399
+ var mod = /[g|i|m]{1,3}$/;
400
+ var flag = req.match(mod);
401
+ flag = flag ? flag[0] : "";
402
+
403
+ req = req.replace(mod, "").slice(1, -1);
404
+ req = new RegExp(req, flag);
405
+ return !!req.test(val);
406
+ },
407
+
408
+ date: function (val, format) {
409
+ return isValidDate(val);
410
+ },
411
+
412
+ present: function (val) {
413
+ return typeof val !== "undefined";
414
+ },
415
+
416
+ after: function (val, req) {
417
+ var val1 = this.validator.input[req];
418
+ var val2 = val;
419
+
420
+ if (!isValidDate(val1)) {
421
+ return false;
422
+ }
423
+ if (!isValidDate(val2)) {
424
+ return false;
425
+ }
426
+
427
+ if (new Date(val1).getTime() < new Date(val2).getTime()) {
428
+ return true;
429
+ }
430
+
431
+ return false;
432
+ },
433
+
434
+ after_or_equal: function (val, req) {
435
+ var val1 = this.validator.input[req];
436
+ var val2 = val;
437
+
438
+ if (!isValidDate(val1)) {
439
+ return false;
440
+ }
441
+ if (!isValidDate(val2)) {
442
+ return false;
443
+ }
444
+
445
+ if (new Date(val1).getTime() <= new Date(val2).getTime()) {
446
+ return true;
447
+ }
448
+
449
+ return false;
450
+ },
451
+
452
+ before: function (val, req) {
453
+ var val1 = this.validator.input[req];
454
+ var val2 = val;
455
+
456
+ if (!isValidDate(val1)) {
457
+ return false;
458
+ }
459
+ if (!isValidDate(val2)) {
460
+ return false;
461
+ }
462
+
463
+ if (new Date(val1).getTime() > new Date(val2).getTime()) {
464
+ return true;
465
+ }
466
+
467
+ return false;
468
+ },
469
+
470
+ before_or_equal: function (val, req) {
471
+ var val1 = this.validator.input[req];
472
+ var val2 = val;
473
+
474
+ if (!isValidDate(val1)) {
475
+ return false;
476
+ }
477
+ if (!isValidDate(val2)) {
478
+ return false;
479
+ }
480
+
481
+ if (new Date(val1).getTime() >= new Date(val2).getTime()) {
482
+ return true;
483
+ }
484
+
485
+ return false;
486
+ },
487
+
488
+ hex: function (val) {
489
+ return /^[0-9a-f]+$/i.test(val);
490
+ },
491
+
492
+ ipv4: function (val, req, attribute) {
493
+ if (typeof val != 'string')
494
+ return false;
495
+
496
+ // regex to check that each octet is valid
497
+ var er = /^[0-9]+$/;
498
+ // ipv4 octets are delimited by dot
499
+ octets = val.split('.');
500
+ // check 1: ipv4 address should contains 4 octets
501
+ if (octets.length != 4)
502
+ return false;
503
+
504
+ for (let i = 0; i < octets.length; i++) {
505
+ const element = octets[i];
506
+ // check 2: each octet should be integer bigger than 0
507
+ if (!er.test(element))
508
+ return false;
509
+
510
+ // check 3: each octet value should be less than 256
511
+ var octetValue = parseInt(element);
512
+ if (octetValue >= 256)
513
+ return false;
514
+ }
515
+
516
+ // if all checks passed, we know it's valid IPv4 address!
517
+ return true;
518
+ },
519
+
520
+ ipv6: function (val, req, attribute) {
521
+ if (typeof val != 'string')
522
+ return false;
523
+
524
+ // regex to check that each hextet is valid
525
+ var er = /^[0-9a-f]+$/;
526
+ // ipv6 hextets are delimited by colon
527
+ hextets = val.split(':');
528
+
529
+ // check 1: ipv6 should contain only one consecutive colons
530
+ colons = val.match(/::/);
531
+ if (colons != null && val.match(/::/g).length > 1)
532
+ return false;
533
+
534
+ // check 2: ipv6 should not be ending or starting with colon
535
+ // edge case: not with consecutive colons
536
+ if (val[0] == ':' && (colons == null || (colons != null && colons.index != 0)))
537
+ return false;
538
+ if (val[val.length - 1] == ':' && (colons == null || (colons != null && colons.index != val.length - 2)))
539
+ return false;
540
+
541
+ // check 3: ipv6 should contain no less than 3 sector
542
+ // minimum ipv6 addres - ::1
543
+ if (3 > hextets.length)
544
+ return false;
545
+
546
+ // check 4: ipv6 should contain no more than 8 sectors
547
+ // only 1 edge case: when first or last sector is ommited
548
+ var isEdgeCase = (hextets.length == 9 && colons != null && (colons.index == 0 || colons.index == val.length - 2));
549
+ if (hextets.length > 8 && !isEdgeCase)
550
+ return false;
551
+
552
+ // check 5: ipv6 should contain exactly one consecutive colons if it has less than 8 sectors
553
+ if (hextets.length != 8 && colons == null)
554
+ return false;
555
+
556
+ for (let i = 0; i < hextets.length; i++) {
557
+ const element = hextets[i];
558
+
559
+ if (element.length == 0)
560
+ continue;
561
+
562
+ // check 6: all of hextets should contain numbers from 0 to f (in hexadecimal)
563
+ if (!er.test(element))
564
+ return false;
565
+
566
+ // check 7: all of hextet values should be less then ffff (in hexadeimal)
567
+ // checking using length of hextet. lowest invalid value's length is 5.
568
+ // so all valid hextets are length of 4 or less
569
+ if (element.length > 4)
570
+ return false;
571
+ }
572
+ return true;
573
+ },
574
+
575
+ ip: function (val, req, attribute) {
576
+ return rules['ipv4'](val, req, attribute) || rules['ipv6'](val, req, attribute);
577
+ }
578
+
579
+ };
580
+
581
+ var missedRuleValidator = function () {
582
+ throw new Error("Validator `" + this.name + "` is not defined!");
583
+ };
584
+ var missedRuleMessage;
585
+
586
+ function Rule(name, fn, async) {
587
+ this.name = name;
588
+ this.fn = fn;
589
+ this.passes = null;
590
+ this._customMessage = undefined;
591
+ this.async = async;
592
+ }
593
+
594
+ Rule.prototype = {
595
+ /**
596
+ * Validate rule
597
+ *
598
+ * @param {mixed} inputValue
599
+ * @param {mixed} ruleValue
600
+ * @param {string} attribute
601
+ * @param {function} callback
602
+ * @return {boolean|undefined}
603
+ */
604
+ validate: function (inputValue, ruleValue, attribute, callback) {
605
+ var _this = this;
606
+ this._setValidatingData(attribute, inputValue, ruleValue);
607
+ if (typeof callback === "function") {
608
+ this.callback = callback;
609
+ var handleResponse = function (passes, message) {
610
+ _this.response(passes, message);
611
+ };
612
+
613
+ if (this.async) {
614
+ return this._apply(inputValue, ruleValue, attribute, handleResponse);
615
+ } else {
616
+ return handleResponse(this._apply(inputValue, ruleValue, attribute));
617
+ }
618
+ }
619
+ return this._apply(inputValue, ruleValue, attribute);
620
+ },
621
+
622
+ /**
623
+ * Apply validation function
624
+ *
625
+ * @param {mixed} inputValue
626
+ * @param {mixed} ruleValue
627
+ * @param {string} attribute
628
+ * @param {function} callback
629
+ * @return {boolean|undefined}
630
+ */
631
+ _apply: function (inputValue, ruleValue, attribute, callback) {
632
+ var fn = this.isMissed() ? missedRuleValidator : this.fn;
633
+
634
+ return fn.apply(this, [inputValue, ruleValue, attribute, callback]);
635
+ },
636
+
637
+ /**
638
+ * Set validating data
639
+ *
640
+ * @param {string} attribute
641
+ * @param {mixed} inputValue
642
+ * @param {mixed} ruleValue
643
+ * @return {void}
644
+ */
645
+ _setValidatingData: function (attribute, inputValue, ruleValue) {
646
+ this.attribute = attribute;
647
+ this.inputValue = inputValue;
648
+ this.ruleValue = ruleValue;
649
+ },
650
+
651
+ /**
652
+ * Get parameters
653
+ *
654
+ * @return {array}
655
+ */
656
+ getParameters: function () {
657
+ var value = [];
658
+
659
+ if (typeof this.ruleValue === "string") {
660
+ value = this.ruleValue.split(",");
661
+ }
662
+
663
+ if (typeof this.ruleValue === "number") {
664
+ value.push(this.ruleValue);
665
+ }
666
+
667
+ if (this.ruleValue instanceof Array) {
668
+ value = this.ruleValue;
669
+ }
670
+
671
+ return value;
672
+ },
673
+
674
+ /**
675
+ * Get true size of value
676
+ *
677
+ * @return {integer|float}
678
+ */
679
+ getSize: function () {
680
+ var value = this.inputValue;
681
+
682
+ if (value instanceof Array) {
683
+ return value.length;
684
+ }
685
+
686
+ if (typeof value === "number") {
687
+ return value;
688
+ }
689
+
690
+ if (this.validator._hasNumericRule(this.attribute)) {
691
+ return parseFloat(value, 10);
692
+ }
693
+
694
+ return value.length;
695
+ },
696
+
697
+ /**
698
+ * Get the type of value being checked; numeric or string.
699
+ *
700
+ * @return {string}
701
+ */
702
+ _getValueType: function () {
703
+ if (typeof this.inputValue === "number" || this.validator._hasNumericRule(this.attribute)) {
704
+ return "numeric";
705
+ }
706
+
707
+ return "string";
708
+ },
709
+
710
+ /**
711
+ * Set the async callback response
712
+ *
713
+ * @param {boolean|undefined} passes Whether validation passed
714
+ * @param {string|undefined} message Custom error message
715
+ * @return {void}
716
+ */
717
+ response: function (passes, message) {
718
+ this.passes = passes === undefined || passes === true;
719
+ this._customMessage = message;
720
+ this.callback(this.passes, message);
721
+ },
722
+
723
+ /**
724
+ * Set validator instance
725
+ *
726
+ * @param {Validator} validator
727
+ * @return {void}
728
+ */
729
+ setValidator: function (validator) {
730
+ this.validator = validator;
731
+ },
732
+
733
+ /**
734
+ * Check if rule is missed
735
+ *
736
+ * @return {boolean}
737
+ */
738
+ isMissed: function () {
739
+ return typeof this.fn !== "function";
740
+ },
741
+
742
+ get customMessage() {
743
+ return this.isMissed() ? missedRuleMessage : this._customMessage;
744
+ }
745
+ };
746
+
747
+ var manager = {
748
+ /**
749
+ * List of async rule names
750
+ *
751
+ * @type {Array}
752
+ */
753
+ asyncRules: [],
754
+
755
+ /**
756
+ * Implicit rules (rules to always validate)
757
+ *
758
+ * @type {Array}
759
+ */
760
+ implicitRules: [
761
+ "required",
762
+ "required_if",
763
+ "required_unless",
764
+ "required_with",
765
+ "required_with_all",
766
+ "required_without",
767
+ "required_without_all",
768
+ "accepted",
769
+ "present"
770
+ ],
771
+
772
+ /**
773
+ * Get rule by name
774
+ *
775
+ * @param {string} name
776
+ * @param {Validator}
777
+ * @return {Rule}
778
+ */
779
+ make: function (name, validator) {
780
+ var async = this.isAsync(name);
781
+ var rule = new Rule(name, rules[name], async);
782
+ rule.setValidator(validator);
783
+ return rule;
784
+ },
785
+
786
+ /**
787
+ * Determine if given rule is async
788
+ *
789
+ * @param {string} name
790
+ * @return {boolean}
791
+ */
792
+ isAsync: function (name) {
793
+ for (var i = 0, len = this.asyncRules.length; i < len; i++) {
794
+ if (this.asyncRules[i] === name) {
795
+ return true;
796
+ }
797
+ }
798
+ return false;
799
+ },
800
+
801
+ /**
802
+ * Determine if rule is implicit (should always validate)
803
+ *
804
+ * @param {string} name
805
+ * @return {boolean}
806
+ */
807
+ isImplicit: function (name) {
808
+ return this.implicitRules.indexOf(name) > -1;
809
+ },
810
+
811
+ /**
812
+ * Register new rule
813
+ *
814
+ * @param {string} name
815
+ * @param {function} fn
816
+ * @return {void}
817
+ */
818
+ register: function (name, fn) {
819
+ rules[name] = fn;
820
+ },
821
+
822
+ /**
823
+ * Register new implicit rule
824
+ *
825
+ * @param {string} name
826
+ * @param {function} fn
827
+ * @return {void}
828
+ */
829
+ registerImplicit: function (name, fn) {
830
+ this.register(name, fn);
831
+ this.implicitRules.push(name);
832
+ },
833
+
834
+ /**
835
+ * Register async rule
836
+ *
837
+ * @param {string} name
838
+ * @param {function} fn
839
+ * @return {void}
840
+ */
841
+ registerAsync: function (name, fn) {
842
+ this.register(name, fn);
843
+ this.asyncRules.push(name);
844
+ },
845
+
846
+ /**
847
+ * Register implicit async rule
848
+ *
849
+ * @param {string} name
850
+ * @param {function} fn
851
+ * @return {void}
852
+ */
853
+ registerAsyncImplicit: function (name, fn) {
854
+ this.registerImplicit(name, fn);
855
+ this.asyncRules.push(name);
856
+ },
857
+
858
+ registerMissedRuleValidator: function (fn, message) {
859
+ missedRuleValidator = fn;
860
+ missedRuleMessage = message;
861
+ }
862
+ };
863
+
864
+ module.exports = manager;