quival 0.3.3 → 0.4.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/README.md CHANGED
@@ -29,7 +29,7 @@ There are 2 ways to start using `quival` in your project.
29
29
  Get the script from [jsDelivr CDN page](https://www.jsdelivr.com/package/npm/quival) and include it in your HTML page.
30
30
 
31
31
  ```html
32
- <script src="https://cdn.jsdelivr.net/npm/quival@0.3.x/dist/quival.min.js"></script>
32
+ <script src="https://cdn.jsdelivr.net/npm/quival@0.4.x/dist/quival.min.js"></script>
33
33
  ```
34
34
 
35
35
  Extract `Validator` class from `quival` global variable, and you are good to go.
@@ -83,6 +83,7 @@ Validator.addChecker(
83
83
 
84
84
  // Prepare arguments
85
85
  const data = {
86
+ refcode: '1bc',
86
87
  username: 'idea💡',
87
88
  name: '',
88
89
  email: 'test',
@@ -98,6 +99,15 @@ const data = {
98
99
  };
99
100
 
100
101
  const rules = {
102
+ refcode: [
103
+ 'required',
104
+ function (attribute, value) { // Closure rule
105
+ return {
106
+ success: /^[a-z]/i.test(value),
107
+ message: 'The :attribute field must start with a letter.',
108
+ };
109
+ },
110
+ ],
101
111
  username: ['required', 'ascii', 'min:3'],
102
112
  name: ['required', 'min:3'],
103
113
  email: ['required', 'email'],
@@ -138,6 +148,9 @@ The produced error messages for the code snippet above.
138
148
 
139
149
  ```json
140
150
  {
151
+ "refcode": [
152
+ "The refcode field must start with a letter."
153
+ ],
141
154
  "username": [
142
155
  "The username field must only contain single-byte alphanumeric characters and symbols."
143
156
  ],
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * quival v0.3.3 (https://github.com/apih/quival)
2
+ * quival v0.4.0 (https://github.com/apih/quival)
3
3
  * (c) 2023 Mohd Hafizuddin M Marzuki <hafizuddin_83@yahoo.com>
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * quival v0.3.3 (https://github.com/apih/quival)
2
+ * quival v0.4.0 (https://github.com/apih/quival)
3
3
  * (c) 2023 Mohd Hafizuddin M Marzuki <hafizuddin_83@yahoo.com>
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * quival v0.3.3 (https://github.com/apih/quival)
2
+ * quival v0.4.0 (https://github.com/apih/quival)
3
3
  * (c) 2023 Mohd Hafizuddin M Marzuki <hafizuddin_83@yahoo.com>
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * quival v0.3.3 (https://github.com/apih/quival)
2
+ * quival v0.4.0 (https://github.com/apih/quival)
3
3
  * (c) 2023 Mohd Hafizuddin M Marzuki <hafizuddin_83@yahoo.com>
4
4
  * Released under the MIT License.
5
5
  */
package/dist/quival.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * quival v0.3.3 (https://github.com/apih/quival)
2
+ * quival v0.4.0 (https://github.com/apih/quival)
3
3
  * (c) 2023 Mohd Hafizuddin M Marzuki <hafizuddin_83@yahoo.com>
4
4
  * Released under the MIT License.
5
5
  */
@@ -736,10 +736,16 @@ var quival = (function (exports) {
736
736
  return false;
737
737
  }
738
738
  checkMimes(attribute, value, parameters) {
739
- if (this.checkFile(attribute, value)) {
740
- return parameters.includes(value.name.split('.').pop().toLowerCase());
739
+ if (!this.checkFile(attribute, value)) {
740
+ return false;
741
741
  }
742
- return false;
742
+ if (parameters.includes('jpg') && !parameters.includes('jpeg')) {
743
+ parameters.push('jpeg');
744
+ }
745
+ if (parameters.includes('jpeg') && !parameters.includes('jpg')) {
746
+ parameters.push('jpg');
747
+ }
748
+ return parameters.includes(value.name.split('.').pop().toLowerCase());
743
749
  }
744
750
  checkExtensions(attribute, value, parameters) {
745
751
  return this.checkMimes(attribute, value, parameters);
@@ -1362,10 +1368,9 @@ var quival = (function (exports) {
1362
1368
  for (const [attribute, attributeRules] of Object.entries(rules)) {
1363
1369
  const attributes = attribute.includes('*') ? this.parseWildcardAttribute(attribute) : [attribute];
1364
1370
  for (const attribute of attributes) {
1365
- const parsedAttributeRules = {};
1371
+ const parsedAttributeRules = [];
1366
1372
  for (const attributeRule of this.parseAttributeRules(attributeRules)) {
1367
- const [rule, parameters] = this.parseAttributeRule(attributeRule);
1368
- parsedAttributeRules[rule] = parameters;
1373
+ parsedAttributeRules.push(this.parseAttributeRule(attributeRule));
1369
1374
  }
1370
1375
  parsedRules[attribute] = parsedAttributeRules;
1371
1376
  }
@@ -1392,13 +1397,17 @@ var quival = (function (exports) {
1392
1397
  parseAttributeRules(rules) {
1393
1398
  if (Array.isArray(rules)) {
1394
1399
  return rules;
1400
+ } else if (typeof rules === 'function') {
1401
+ return [rules];
1395
1402
  } else {
1396
1403
  return String(rules).split('|');
1397
1404
  }
1398
1405
  }
1399
1406
  parseAttributeRule(rule) {
1400
1407
  if (Array.isArray(rule)) {
1401
- return [rule.shift() ?? '', rule];
1408
+ return [rule[0] ?? '', rule.slice(1)];
1409
+ } else if (typeof rule === 'function') {
1410
+ return [rule, []];
1402
1411
  }
1403
1412
  const index = rule.indexOf(':');
1404
1413
  if (index === -1) {
@@ -1412,39 +1421,61 @@ var quival = (function (exports) {
1412
1421
  this.#errors = new ErrorBag();
1413
1422
  const tasks = [];
1414
1423
  const skippedAttributes = [];
1424
+ for (const [attribute, rules] of Object.entries(this.#rules)) {
1425
+ for (const [rule] of rules) {
1426
+ if (
1427
+ rule === '' ||
1428
+ typeof rule === 'function' ||
1429
+ typeof this.#checkers[toCamelCase('check_' + rule)] === 'function' ||
1430
+ Validator.#dummyRules.includes(rule)
1431
+ )
1432
+ continue;
1433
+ throw new Error(`Invalid validation rule: ${rule}`);
1434
+ }
1435
+ }
1415
1436
  for (const [attribute, rules] of Object.entries(this.#rules)) {
1416
1437
  let value = this.getValue(attribute);
1417
- if (Object.hasOwn(rules, 'sometimes') && typeof value === 'undefined') {
1438
+ const hasRule = (ruleName) => rules.some((rule) => rule[0] === ruleName);
1439
+ if (hasRule('sometimes') && typeof value === 'undefined') {
1418
1440
  skippedAttributes.push(attribute);
1419
1441
  continue;
1420
1442
  }
1421
1443
  tasks.push(async () => {
1422
- const doBail = this.#alwaysBail || Object.hasOwn(rules, 'bail');
1423
- const isNullable = Object.hasOwn(rules, 'nullable');
1444
+ const doBail = this.#alwaysBail || hasRule('bail');
1445
+ const isNullable = hasRule('nullable');
1424
1446
  let noError = true;
1425
- for (const [rule, parameters] of Object.entries(rules)) {
1447
+ for (const [rule, parameters] of rules) {
1426
1448
  if (
1427
1449
  rule === '' ||
1428
- (!Validator.#implicitRules.includes(rule) &&
1450
+ (typeof rule !== 'function' &&
1451
+ !Validator.#implicitRules.includes(rule) &&
1429
1452
  (typeof value === 'undefined' || (typeof value === 'string' && value.trim() === '') || (isNullable && value === null)))
1430
1453
  ) {
1431
1454
  skippedAttributes.push(attribute);
1432
1455
  continue;
1433
1456
  }
1434
1457
  let result, success, message;
1435
- const camelRule = toCamelCase('check_' + rule);
1436
- if (typeof this.#checkers[camelRule] === 'function') {
1437
- result = await this.#checkers[camelRule](attribute, value, parameters);
1438
- } else if (Validator.#dummyRules.includes(rule)) {
1439
- result = true;
1440
- } else {
1458
+ const checker = (() => {
1459
+ if (typeof rule === 'function') {
1460
+ return rule;
1461
+ } else {
1462
+ const checker = this.#checkers[toCamelCase('check_' + rule)] ?? null;
1463
+ if (checker === null && Validator.#dummyRules.includes(rule)) {
1464
+ return () => true;
1465
+ }
1466
+ return checker;
1467
+ }
1468
+ })();
1469
+ if (checker === null) {
1441
1470
  throw new Error(`Invalid validation rule: ${rule}`);
1442
1471
  }
1472
+ result = await checker.call(this.#checkers, attribute, value, parameters);
1443
1473
  if (typeof result === 'boolean') {
1444
- success = result;
1445
- } else {
1446
- ({ success, message } = result);
1474
+ result = {
1475
+ success: result,
1476
+ };
1447
1477
  }
1478
+ ({ success, message = '' } = result);
1448
1479
  if (!success) {
1449
1480
  noError = false;
1450
1481
  message = isEmpty(message) ? this.getMessage(attribute, rule) : message;
@@ -1463,7 +1494,13 @@ var quival = (function (exports) {
1463
1494
  if (!(await task())) break;
1464
1495
  }
1465
1496
  } else {
1466
- await Promise.allSettled(tasks.map((task) => task()));
1497
+ await Promise.allSettled(tasks.map((task) => task())).then((results) => {
1498
+ for (const result of results) {
1499
+ if (result.status === 'rejected') {
1500
+ throw result.reason;
1501
+ }
1502
+ }
1503
+ });
1467
1504
  this.#errors.sortByKeys(Object.keys(this.#rules));
1468
1505
  }
1469
1506
  this.#skippedAttributes = skippedAttributes.filter((value, index, array) => array.indexOf(value) === index);
@@ -1480,6 +1517,9 @@ var quival = (function (exports) {
1480
1517
  return !(await this.passes());
1481
1518
  }
1482
1519
  getMessage(attribute, rule) {
1520
+ if (typeof rule === 'function') {
1521
+ return '';
1522
+ }
1483
1523
  const value = this.getValue(attribute);
1484
1524
  attribute = this.getPrimaryAttribute(attribute);
1485
1525
  let message;
@@ -1523,9 +1563,11 @@ var quival = (function (exports) {
1523
1563
  if (index !== -1) {
1524
1564
  message = message.replaceAll(':index', index).replaceAll(':position', index + 1);
1525
1565
  }
1526
- const camelRule = toCamelCase('replace_' + rule);
1527
- if (typeof this.#replacers[camelRule] === 'function') {
1528
- message = this.#replacers[camelRule](message, attribute, rule, parameters);
1566
+ if (typeof rule === 'string') {
1567
+ const replacer = this.#replacers[toCamelCase('replace_' + rule)] ?? null;
1568
+ if (replacer) {
1569
+ message = replacer.call(this.#replacers, message, attribute, rule, parameters);
1570
+ }
1529
1571
  }
1530
1572
  return message;
1531
1573
  }
@@ -1582,7 +1624,7 @@ var quival = (function (exports) {
1582
1624
  return false;
1583
1625
  }
1584
1626
  for (const rule of rules) {
1585
- if (this.#rules[attribute].hasOwnProperty(rule)) {
1627
+ if (this.#rules[attribute].some((attributeRule) => attributeRule[0] === rule)) {
1586
1628
  return true;
1587
1629
  }
1588
1630
  }
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * quival v0.3.3 (https://github.com/apih/quival)
2
+ * quival v0.4.0 (https://github.com/apih/quival)
3
3
  * (c) 2023 Mohd Hafizuddin M Marzuki <hafizuddin_83@yahoo.com>
4
4
  * Released under the MIT License.
5
5
  */
6
- var quival=function(e){"use strict";function t(e){return e.replace(/[-_]/g," ").replace(/\s+/," ").trim().replace(/(\s\w)/g,(e=>e[1].toUpperCase()))}function r(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function s(e,t=""){return Object.keys(e).reduce(((r,i)=>{const c=t?`${t}.${i}`:i;return"object"==typeof e[i]&&null!==e[i]?Object.assign(r,s(e[i],c)):r[c]=e[i],r}),{})}function i(e){const t=[];let r="",s=!1;for(let i=0;i<e.length;i++){const c=e[i];'"'===c?s&&'"'===e[i+1]?(r+='"',i++):(s=!s,s&&(r=r.trim())):","!==c||s?r+=c:(t.push(r),r="")}return t.push(r),t}function c(e){if(n(e)||"string"!=typeof e)return new Date("");if(e instanceof Date)return e;let t,r,s,i,c,a,u,h;const l=e=>e&&/^\d*$/.test(e)?parseInt(e):e;if(null!==(t=e.match(/^(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{2,4})\s?((\d{1,2}):(\d{1,2})(:(\d{1,2}))?\s?(am|pm)?)?/i)))[,i,s,r,,c=0,a=0,,u=0,h="am"]=t.map(l);else if(null!==(t=e.match(/^(\d{2,4})[.\/-](\d{1,2})[.\/-](\d{1,2})\s?((\d{1,2}):(\d{1,2})(:(\d{1,2}))?\s?(am|pm)?)?/i))||null!==(t=e.match(/^(\d{4})(\d{2})(\d{2})\s?((\d{2})(\d{2})((\d{2}))?\s?(am|pm)?)?/i)))[,r,s,i,,c=0,a=0,,u=0,h="am"]=t.map(l);else if(t=e.match(/(\d{1,2}):(\d{1,2})(:(\d{1,2}))?\s?(am|pm)?\s?(\d{4})[.\/-](\d{2})[.\/-](\d{2})/i))[,c,a,,u,h="am",r,s,i]=t.map(l);else if(t=e.match(/(\d{1,2}):(\d{1,2})(:(\d{1,2}))?\s?(am|pm)?\s?(\d{2})[.\/-](\d{2})[.\/-](\d{4})/i))[,c,a,,u,h="am",i,s,r]=t.map(l);else{if(!(t=e.match(/(\d{1,2}):(\d{1,2})(:(\d{1,2}))?\s?(am|pm)?/i)))return new Date(e);{const e=new Date;r=e.getFullYear(),s=e.getMonth()+1,i=e.getDate(),[,c=0,a=0,,u=0,h="am"]=t.map(l)}}return r>=10&&r<100&&(r+=2e3),"pm"===h.toLowerCase()&&c<12&&(c+=12),new Date(`${r}-${s}-${i} ${c}:${a}:${u}`)}function a(e,t){if(n(e))return new Date("");t=t.split("");const r={Y:"(\\d{4})",y:"(\\d{2})",m:"(\\d{2})",n:"([1-9]\\d?)",d:"(\\d{2})",j:"([1-9]\\d?)",G:"([1-9]\\d?)",g:"([1-9]\\d?)",H:"(\\d{2})",h:"(\\d{2})",i:"(\\d{2})",s:"(\\d{2})",A:"(AM|PM)",a:"(am|pm)"};let s="^",i={years:-1,months:-1,days:-1,hours:-1,minutes:-1,seconds:-1,meridiem:-1},c=1;for(const e of t)Object.hasOwn(r,e)?(s+=r[e],-1!==["Y","y"].indexOf(e)?i.years=c++:-1!==["m","n"].indexOf(e)?i.months=c++:-1!==["d","j"].indexOf(e)?i.days=c++:-1!==["G","g","H","h"].indexOf(e)?i.hours=c++:"i"===e?i.minutes=c++:"s"===e?i.seconds=c++:-1!==["A","a"].indexOf(e)&&(i.meridiem=c++)):s+="\\"+e;s+="$";let a=e.match(new RegExp(s));if(null===a)return new Date("");a=a.map((e=>e&&/^\d*$/.test(e)?parseInt(e):e));const u=new Date;let h=a[i.years],l=a[i.months],o=a[i.days],d=a[i.hours]??0,p=a[i.minutes]??0,f=a[i.seconds]??0,g=a[i.meridiem]??"am";return h||l||o?!h||l||o?h||!l||o?h||l||!o||(h=u.getFullYear(),l=u.getMonth()+1):(h=u.getFullYear(),o=1):(l=1,o=1):(h=u.getFullYear(),l=u.getMonth()+1,o=u.getDate()),h>=10&&h<100&&(h+=2e3),"pm"===g.toLowerCase()&&d<12&&(d+=12),new Date(`${h}-${l}-${o} ${d}:${p}:${f}`)}function n(e){return""===e||null==e}function u(e){const t=Number(e);return null!==e&&"boolean"!=typeof e&&"number"==typeof t&&!isNaN(t)}function h(e){return"[object Object]"===Object.prototype.toString.call(e)}function l(e){return e instanceof Date&&"Invalid Date"!==e.toDateString()}class o{#e;#t;constructor(e){this.#e={},this.#t={},this.validator=e}clearCaches(){this.#e={},this.#t={}}isDependent(e){const t=this.validator.getValue(e[0]);return e.slice(1).some((e=>e==t))}collectRequiredsThenTest(e,t,r,s){let i=[];for(const e of r)i.push(this.checkRequired(e,this.validator.getValue(e)));return!s(i)||this.checkRequired(e,t)}collectMissingsThenTest(e,t,r,s){let i=[];for(const e of r)i.push(this.checkMissing(e));return!s(i)||this.checkMissing(e)}testStringUsingRegex(e,t,r,s,i=!1){return("string"==typeof t||"number"==typeof t)&&(t=String(t),i||this.validator.hasRule(e,"ascii")?r.test(t):s.test(t))}compareValues(e,t,r,s){if(n(t))return!1;const i=r[0]??"";let c=this.validator.getValue(i);return c=void 0===c?u(i)?parseFloat(i,10):null:this.validator.getSize(i,c),!n(c)&&s(this.validator.getSize(e,t),c)}compareDates(e,t,r,s){const i=this.validator.getRule(e);if(!l(t=Object.hasOwn(i,"date_format")?a(t,i.date_format[0]):c(t)))return!1;const n=r[0]??"";let u=this.validator.getValue(n);if(void 0===u)u=c(n);else{const e=this.validator.getRule(n);u=Object.hasOwn(e,"date_format")?a(u,e.date_format[0]):c(u)}return!!l(u)&&s(t.getTime(),u.getTime())}checkArray(e,t,r){if(!Array.isArray(t)&&!h(t))return!1;if(r&&r.length>0)for(const e of Object.keys(t))if(!r.includes(e))return!1;return!0}checkList(e,t,r){return Array.isArray(t)}checkBoolean(e,t,r){return[!0,!1,0,1,"0","1"].includes(t)}checkDate(e,t,r){return l(c(t))}checkFile(e,t,r){return t instanceof File}checkInteger(e,t,r){return String(parseInt(t,10))===String(t)}checkNumeric(e,t,r){return u(t)}checkString(e,t,r){return"string"==typeof t}checkDecimal(e,t,r){if(!this.checkNumeric(e,t))return!1;const s=(String(t).split(".")[1]??"").length;return 1===r.length?s==r[0]:s>=r[0]&&s<=r[1]}checkMultipleOf(e,t,r){if(!u(t)||!u(r[0]))return!1;const s=parseInt(t,10),i=parseInt(r[0],10);return(0!==s||0!==i)&&(0===s||0!==i&&s%i==0)}checkAccepted(e,t,r){return["yes","on","1",1,!0,"true"].includes(t)}checkAcceptedIf(e,t,r){return!this.isDependent(r)||this.checkAccepted(e,t,r)}checkDeclined(e,t,r){return["no","off","0",0,!1,"false"].includes(t)}checkDeclinedIf(e,t,r){return!this.isDependent(r)||this.checkDeclined(e,t,r)}checkRequired(e,t,r){return!n(t)&&(Array.isArray(t)?t.length>0:t instanceof File?t.size>0:(t=String(t).replace(/\s/g,"")).length>0)}checkRequiredArrayKeys(e,t,r){if(!this.checkArray(e,t))return!1;const s=Object.keys(t);for(const e of r)if(!s.includes(e))return!1;return!0}checkRequiredIf(e,t,r){return!this.isDependent(r)||this.checkRequired(e,t)}checkRequiredIfAccepted(e,t,r){return!this.checkAccepted(r[0],this.validator.getValue(r[0]))||this.checkRequired(e,t)}checkRequiredIfDeclined(e,t,r){return!this.checkDeclined(r[0],this.validator.getValue(r[0]))||this.checkRequired(e,t)}checkRequiredUnless(e,t,r){return!!this.isDependent(r)||this.checkRequired(e,t)}checkRequiredWith(e,t,r){return this.collectRequiredsThenTest(e,t,r,(e=>e.includes(!0)))}checkRequiredWithAll(e,t,r){return this.collectRequiredsThenTest(e,t,r,(e=>!e.includes(!1)))}checkRequiredWithout(e,t,r){return this.collectRequiredsThenTest(e,t,r,(e=>e.includes(!1)))}checkRequiredWithoutAll(e,t,r){return this.collectRequiredsThenTest(e,t,r,(e=>!e.includes(!0)))}checkFilled(e,t,r){return void 0===t||this.checkRequired(e,t)}checkPresent(e,t,r){return void 0!==t}checkMissing(e,t,r){return!this.validator.hasAttribute(e)}checkMissingIf(e,t,r){return!this.isDependent(r)||this.checkMissing(e)}checkMissingUnless(e,t,r){return!!this.isDependent(r)||this.checkMissing(e)}checkMissingWith(e,t,r){return this.collectMissingsThenTest(e,t,r,(e=>e.includes(!1)))}checkMissingWithAll(e,t,r){return this.collectMissingsThenTest(e,t,r,(e=>!e.includes(!0)))}checkProhibited(e,t,r){return!this.checkRequired(e,t)}checkProhibitedIf(e,t,r){return!this.isDependent(r)||!this.checkRequired(e,t)}checkProhibitedUnless(e,t,r){return!!this.isDependent(r)||!this.checkRequired(e,t)}checkProhibits(e,t,r){if(this.checkRequired(e,t))for(const e of r)if(this.checkRequired(e,this.validator.getValue(e)))return!1;return!0}checkSize(e,t,r){return this.validator.getSize(e,t)===parseFloat(r[0])}checkMin(e,t,r){return this.validator.getSize(e,t)>=parseFloat(r[0])}checkMax(e,t,r){return this.validator.getSize(e,t)<=parseFloat(r[0])}checkBetween(e,t,r){return this.checkMin(e,t,[r[0]])&&this.checkMax(e,t,[r[1]])}checkDigits(e,t,r,s=(e,t)=>e===t){return!!function(e){return-1===String(e).search(/[^0-9]/)}(t=String(t??""))&&s(t.length,parseInt(r[0],10),parseInt(r[1]??0,10))}checkMinDigits(e,t,r){return this.checkDigits(e,t,r,((e,t)=>e>=t))}checkMaxDigits(e,t,r){return this.checkDigits(e,t,r,((e,t)=>e<=t))}checkDigitsBetween(e,t,r){return this.checkDigits(e,t,r,((e,t,r)=>e>=t&&e<=r))}checkAlpha(e,t,r){return this.testStringUsingRegex(e,t,/^[a-z]+$/i,/^[\p{L}\p{M}]+$/u,r.includes("ascii"))}checkAlphaDash(e,t,r){return this.testStringUsingRegex(e,t,/^[a-z0-9_-]+$/i,/^[\p{L}\p{M}\p{N}_-]+$/u,r.includes("ascii"))}checkAlphaNum(e,t,r){return this.testStringUsingRegex(e,t,/^[a-z0-9]+$/i,/^[\p{L}\p{M}\p{N}]+$/u,r.includes("ascii"))}checkAscii(e,t,r){return!/[^\x09\x10\x13\x0A\x0D\x20-\x7E]/.test(t)}checkRegex(e,t,r,s=!1){if("string"!=typeof t&&!u(t))return!1;const i=r.join(",");let[c,a,h]=i.match(/^\/(.*)\/([gimu]*)$/)??[];if(n(c))throw new Error(`Invalid regular expression pattern: ${i}`);h.includes("u")&&(a=a.replace(/\\A/g,"^").replace(/\\z/gi,"$").replace(/\\([pP])([CLMNPSZ])/g,"\\$1{$2}").replace(/\\\x\{([0-9a-f]+)\}/g,"\\u{$1}"));const l=new RegExp(a,h).test(t);return s?!l:l}checkNotRegex(e,t,r){return this.checkRegex(e,t,r,!0)}checkLowercase(e,t,r){return t===String(t).toLocaleLowerCase()}checkUppercase(e,t,r){return t===String(t).toLocaleUpperCase()}checkStartsWith(e,t,r){t=String(t);for(const e of r)if(t.startsWith(e))return!0;return!1}checkDoesntStartWith(e,t,r){return!this.checkStartsWith(e,t,r)}checkEndsWith(e,t,r){t=String(t);for(const e of r)if(t.endsWith(e))return!0;return!1}checkDoesntEndWith(e,t,r){return!this.checkEndsWith(e,t,r)}checkSame(e,t,r){return t===this.validator.getValue(r[0])}checkDifferent(e,t,r){for(const e of r){const r=this.validator.getValue(e);if(void 0!==r&&t===r)return!1}return!0}checkConfirmed(e,t,r){return this.checkSame(e,t,[e+"_confirmation"])}checkGt(e,t,r){return this.compareValues(e,t,r,((e,t)=>e>t))}checkGte(e,t,r){return this.compareValues(e,t,r,((e,t)=>e>=t))}checkLt(e,t,r){return this.compareValues(e,t,r,((e,t)=>e<t))}checkLte(e,t,r){return this.compareValues(e,t,r,((e,t)=>e<=t))}checkAfter(e,t,r){return this.compareDates(e,t,r,((e,t)=>e>t))}checkAfterOrEqual(e,t,r){return this.compareDates(e,t,r,((e,t)=>e>=t))}checkBefore(e,t,r){return this.compareDates(e,t,r,((e,t)=>e<t))}checkBeforeOrEqual(e,t,r){return this.compareDates(e,t,r,((e,t)=>e<=t))}checkDateEquals(e,t,r){return this.compareDates(e,t,r,((e,t)=>e===t))}checkDateFormat(e,t,r){const s=r[0].split(""),i={Y:"(\\d{4})",y:"(\\d{2})",m:"(\\d{2})",n:"([1-9]\\d?)",d:"(\\d{2})",j:"([1-9]\\d?)",G:"([1-9]\\d?)",g:"([1-9]\\d?)",H:"(\\d{2})",h:"(\\d{2})",i:"(\\d{2})",s:"(\\d{2})",A:"(AM|PM)",a:"(am|pm)"};let c="^";for(const e of s)Object.hasOwn(i,e)?c+=i[e]:c+="\\"+e;return c+="$",new RegExp(c).test(t)}checkContains(e,t,r){if(!this.checkArray(e,t))return!1;for(const e of r)if(!t.includes(e))return!1;return!0}checkDistinct(e,t,i){const c=this.validator.getPrimaryAttribute(e);if(!c.includes("*"))return!0;const a=c.indexOf("*"),n=c.substring(0,a-1);let u;Object.hasOwn(this.#e,n)?u=this.#e[n]:(u=JSON.stringify(s(this.validator.getValue(n)??{})),this.#e[n]=u);const h=i.includes("ignore_case"),l=!h&&i.includes("strict"),o=r(String(t));let d=`"${r(c.substring(a)).replaceAll("\\*",'[^."]+')}":`,p=0;return d+=l?"string"==typeof t?`"${o}"`:`${o}`:`(${o}|"${o}")`,d+="[,}]+",p+=u.match(new RegExp(d,"g"+(h?"i":"")))?.length??0,1===p}checkInArray(e,t,r){const i=this.validator.getPrimaryAttribute(r[0]);if(!i.includes("*"))return!1;const c=this.validator.getValue(i.split(".*")[0])??{};return Object.values(s(c)).some((e=>e==t))}checkIn(e,t,r){if(!this.checkArray(e,t)||!this.validator.hasRule(e,"array"))return r.some((e=>e==t));for(const e of Object.values(t))if(!r.some((t=>t==e)))return!1;return!0}checkNotIn(e,t,r){return!this.checkIn(e,t,r)}checkMimetypes(e,t,r){return!!this.checkFile(e,t)&&r.includes(t.type)}checkMimes(e,t,r){return!!this.checkFile(e,t)&&r.includes(t.name.split(".").pop().toLowerCase())}checkExtensions(e,t,r){return this.checkMimes(e,t,r)}async checkImage(e,t,r){let s=this.checkMimes(e,t,["jpg","jpeg","png","gif","bmp","svg","webp"]);return s&&"undefined"!=typeof FileReader?(await new Promise(((e,r)=>{const s=new FileReader;s.onload=t=>e(t.target.result),s.onerror=r,s.readAsDataURL(t)})).then((async t=>{const r=new Image;r.src=t,await r.decode(),this.#t[e]=r})).catch((()=>{s=!1})),s):s}async checkDimensions(e,t,r){if(!this.checkImage(e,t)||!Object.hasOwn(this.#t,e))return!1;const s={};for(const e of r){const[t,r]=e.split("=",2);if("ratio"===t&&r.includes("/")){const[e,i]=r.split("/",2).map((e=>parseFloat(e,10)));s[t]=e/i}else s[t]=parseFloat(r,10)}const i=this.#t[e],c=i.naturalWidth,a=i.naturalHeight;return!(Object.hasOwn(s,"width")&&s.width!==c||Object.hasOwn(s,"height")&&s.height!==a||Object.hasOwn(s,"min_width")&&s.min_width>c||Object.hasOwn(s,"min_height")&&s.min_height>a||Object.hasOwn(s,"max_width")&&s.max_width<c||Object.hasOwn(s,"max_height")&&s.max_height<a)&&(!Object.hasOwn(s,"ratio")||Math.abs(s.ratio-c/a)<=1/(Math.max(c,a)+1))}checkEmail(e,t,r){if(!/^(([^<>()[\]\\.,;:\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,}))$/.test(t)){return/^((?:[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]))?)+)*$/.test(t)}return!0}checkJson(e,t,r){try{JSON.parse(t)}catch(e){return!1}return!0}checkHexColor(e,t,r){return/^#(?:(?:[0-9a-f]{3}){1,2}|(?:[0-9a-f]{4}){1,2})$/i.test(t)}checkMacAddress(e,t,r){t=String(t);const s={"-":2,":":2,".":4};let i,c;for([i,c]of Object.entries(s))if(t.includes(i))break;const a=t.split(i);if(a.length!==12/c)return!1;for(const e of a)if(!new RegExp("^[0-9a-f]{"+c+"}$","i").test(e))return!1;return!0}checkIpv4(e,t,r){if(/[^\d.]/.test(t))return!1;const s=String(t).split(".");if(4!==s.length)return!1;for(const e of s)if(e<0||e>255)return!1;return!0}checkIpv6(e,t,r){if((t=String(t)).includes(":::")||t.split("::").length>2)return!1;const s=t.split(":");if(s.length<3||s.length>8)return!1;for(const e of s)if(""!==e&&!/^[0-9a-f]{1,4}$/i.test(e))return!1;return!0}checkIp(e,t,r){return this.checkIpv4(e,t,r)||this.checkIpv6(e,t,r)}checkTimezone(e,t,r){try{Intl.DateTimeFormat(void 0,{timeZone:t})}catch(e){if(String(e).toLowerCase().includes("invalid time zone"))return!1}return!0}checkUrl(e,t,r){try{new URL(t)}catch(e){return!1}return!0}checkUlid(e,t,r){return/[0-7][0-9A-HJKMNP-TV-Z]{25}/.test(t)}checkUuid(e,t,r){return/[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}/.test(t)}}class d{#r;keys(){return Object.keys(this.#r)}values(){return Object.values(this.#r)}entries(){return Object.entries(this.#r)}add(e,t){Object.hasOwn(this.#r,e)?this.#r[e].push(t):this.#r[e]=[t]}get(e){if(!e.includes("*"))return Object.hasOwn(this.#r,e)?this.#r[e]:{};const t=new RegExp("^"+e.replaceAll("*",".*?")+"$"),r={};for(const[e,s]of this.entries())t.test(e)&&(r[e]=s);return r}first(e){for(const t of Object.values(this.get(e)))return Array.isArray(t)?t[0]:t;return""}has(e){return""!==this.first(e)}remove(e){delete this.#r[e]}messages(){return this.#r}all(){const e=[];return this.values().forEach((t=>e.push(...t))),e}count(){let e=0;return this.values().forEach((t=>e+=t.length)),e}isEmpty(){return 0===this.keys().length}isNotEmpty(){return!this.isEmpty()}sortByKeys(e){const t={};for(const r of e)Object.hasOwn(this.#r,r)&&(t[r]=this.#r[r]);this.#r=t}constructor(){this.#r={}}}class p{static#s;static#i={};static locale(e){this.#s=e}static setMessages(e,t){this.#i[e]=s(t)}static get(e){if(this.#i[this.#s]&&this.#i[this.#s][e])return this.#i[this.#s][e]}static has(e){return void 0!==this.get(e)}static set(e,t){h(t)?Object.assign(this.#i[this.#s],s(t,e)):"string"==typeof t&&(this.#i[this.#s][e]=t)}}class f{constructor(e){this.validator=e}replace(e,t){return Object.entries(t).forEach((([t,r])=>e=e.replaceAll(":"+t,r))),e}replaceDecimal(e,t,r,s){return this.replace(e,{decimal:s.join("-")})}replaceMultipleOf(e,t,r,s){return this.replace(e,{value:s[0]})}replaceAcceptedIf(e,t,r,s){return this.replace(e,{other:this.validator.getDisplayableAttribute(s[0]),value:this.validator.getDisplayableValue(s[0],this.validator.getValue(s[0]))})}replaceDeclinedIf(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceRequiredArrayKeys(e,t,r,s){return this.replace(e,{values:s.map((e=>this.validator.getDisplayableValue(t,e))).join(", ")})}replaceRequiredIf(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceRequiredIfAccepted(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceRequiredIfDeclined(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceRequiredUnless(e,t,r,s){return this.replace(e,{other:this.validator.getDisplayableAttribute(s[0]),values:s.slice(1).map((e=>this.validator.getDisplayableValue(s[0],e))).join(", ")})}replaceRequiredWith(e,t,r,s){return this.replace(e,{values:s.map((e=>this.validator.getDisplayableAttribute(e))).join(" / ")})}replaceRequiredWithAll(e,t,r,s){return this.replaceRequiredWith(e,t,r,s)}replaceRequiredWithout(e,t,r,s){return this.replaceRequiredWith(e,t,r,s)}replaceRequiredWithoutAll(e,t,r,s){return this.replaceRequiredWith(e,t,r,s)}replaceMissingIf(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceMissingUnless(e,t,r,s){return this.replace(this.replaceRequiredUnless(e,t,r,s),{value:this.validator.getDisplayableValue(s[0],s[1])})}replaceMissingWith(e,t,r,s){return this.replaceRequiredWith(e,t,r,s)}replaceMissingWithAll(e,t,r,s){return this.replaceRequiredWith(e,t,r,s)}replaceProhibitedIf(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceProhibitedUnless(e,t,r,s){return this.replaceRequiredUnless(e,t,r,s)}replaceProhibits(e,t,r,s){return this.replace(e,{other:s.map((e=>this.validator.getDisplayableAttribute(e))).join(" / ")})}replaceSize(e,t,r,s){return this.replace(e,{size:s[0]})}replaceMin(e,t,r,s){return this.replace(e,{min:s[0]})}replaceMax(e,t,r,s){return this.replace(e,{max:s[0]})}replaceBetween(e,t,r,s){return this.replace(e,{min:s[0],max:s[1]})}replaceDigits(e,t,r,s){return this.replace(e,{digits:s[0]})}replaceMinDigits(e,t,r,s){return this.replaceMin(e,t,r,s)}replaceMaxDigits(e,t,r,s){return this.replaceMax(e,t,r,s)}replaceDigitsBetween(e,t,r,s){return this.replaceBetween(e,t,r,s)}replaceStartsWith(e,t,r,s){return this.replaceRequiredArrayKeys(e,t,r,s)}replaceDoesntStartWith(e,t,r,s){return this.replaceRequiredArrayKeys(e,t,r,s)}replaceEndsWith(e,t,r,s){return this.replaceRequiredArrayKeys(e,t,r,s)}replaceDoesntEndWith(e,t,r,s){return this.replaceRequiredArrayKeys(e,t,r,s)}replaceSame(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceDifferent(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceGt(e,t,r,s){const i=this.validator.getValue(s[0]);return this.replace(e,{value:i?this.validator.getSize(s[0],i):this.validator.getDisplayableAttribute(s[0])})}replaceGte(e,t,r,s){return this.replaceGt(e,t,r,s)}replaceLt(e,t,r,s){return this.replaceGt(e,t,r,s)}replaceLte(e,t,r,s){return this.replaceGt(e,t,r,s)}replaceAfter(e,t,r,s){const i=s[0];return this.replace(e,{date:this.validator.hasAttribute(i)?this.validator.getDisplayableAttribute(i):i})}replaceAfterOrEqual(e,t,r,s){return this.replaceAfter(e,t,r,s)}replaceBefore(e,t,r,s){return this.replaceAfter(e,t,r,s)}replaceBeforeOrEqual(e,t,r,s){return this.replaceAfter(e,t,r,s)}replaceDateEquals(e,t,r,s){return this.replaceAfter(e,t,r,s)}replaceDateFormat(e,t,r,s){return this.replace(e,{format:s[0]})}replaceInArray(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceIn(e,t,r,s){return this.replaceRequiredArrayKeys(e,t,r,s)}replaceNotIn(e,t,r,s){return this.replaceRequiredArrayKeys(e,t,r,s)}replaceMimetypes(e,t,r,s){return this.replace(e,{values:s.join(", ")})}replaceMimes(e,t,r,s){return this.replaceMimetypes(e,t,r,s)}replaceExtensions(e,t,r,s){return this.replaceMimetypes(e,t,r,s)}}class g{static#c={};static#a={};static#n=["active_url","bail","can","current_password","enum","exclude","exclude_if","exclude_unless","exclude_with","exclude_without","exists","nullable","sometimes","unique"];static#u=["accepted","accepted_if","declined","declined_if","filled","missing","missing_if","missing_unless","missing_with","missing_with_all","present","required","required_if","required_if_accepted","required_if_declined","required_unless","required_with","required_with_all","required_without","required_without_all"];#r;#h;#l;#o;#d;#p;#f;#g;#m;#k;#b;#A;static setLocale(e){p.locale(e)}static setMessages(e,t){p.setMessages(e,t)}static addChecker(e,t,r){g.#c[e]=t,r&&p.set(e,r)}static addImplicitChecker(e,t,r){g.addChecker(e,t,r),g.#u.push(e)}static addReplacer(e,t){g.#a[e]=t}static addDummyRule(e){g.#n.push(e)}constructor(e={},r={},s={},i={},c={}){this.#m=[],this.#k={},this.#b=!1,this.#A=!1,this.fileRules=["file","image","mimetypes","mimes"],this.numericRules=["decimal","numeric","integer"],this.sizeRules=["size","between","min","max","gt","lt","gte","lte"],this.setProperties(e,r,s,i,c),this.#p=new o(this),this.#f=new f(this);for(const[e,r]of Object.entries(g.#c))this.#p[t("check_"+e)]=r;for(const[e,r]of Object.entries(g.#a))this.#f[t("replace_"+e)]=r;this.#g=new d}setProperties(e={},t={},r={},i={},c={}){return this.#r=e,this.#h=this.parseRules(t),this.#l=r,this.#o=i,this.#d=s(c),this}setData(e){return this.#r=e,this}setRules(e){return this.#h=this.parseRules(e),this}setCustomMessages(e){return this.#l=e,this}setCustomAttributes(e){return this.#o=e,this}setCustomValues(e){return this.#d=s(e),this}addImplicitAttribute(e,t){return this.#k[e]=t,this}stopOnFirstFailure(e=!0){return this.#b=e,this}alwaysBail(e=!0){return this.#A=e,this}parseRules(e){const t={};for(const[r,s]of Object.entries(e)){const e=r.includes("*")?this.parseWildcardAttribute(r):[r];for(const r of e){const e={};for(const t of this.parseAttributeRules(s)){const[r,s]=this.parseAttributeRule(t);e[r]=s}t[r]=e}}return t}parseWildcardAttribute(e){const t=[],r=e.indexOf("*"),s=e.substring(0,r-1),i=e.substring(r+2),c=this.getValue(s);return Array.isArray(c)||h(c)?(Object.entries(c).forEach((([r,c])=>{const a=`${s}.${r}.${i}`.replace(/\.$/,""),n=a.includes("*")?this.parseWildcardAttribute(a):[a];t.push(...n),n.forEach((t=>this.#k[t]=e))})),t):[e]}parseAttributeRules(e){return Array.isArray(e)?e:String(e).split("|")}parseAttributeRule(e){if(Array.isArray(e))return[e.shift()??"",e];const t=e.indexOf(":");return-1===t?[e,[]]:[e.substring(0,t),i(e.substring(t+1))]}async validate(){this.#p.clearCaches(),this.#g=new d;const e=[],r=[];for(const[s,i]of Object.entries(this.#h)){let c=this.getValue(s);Object.hasOwn(i,"sometimes")&&void 0===c?r.push(s):e.push((async()=>{const e=this.#A||Object.hasOwn(i,"bail"),a=Object.hasOwn(i,"nullable");let u=!0;for(const[h,l]of Object.entries(i)){if(""===h||!g.#u.includes(h)&&(void 0===c||"string"==typeof c&&""===c.trim()||a&&null===c)){r.push(s);continue}let i,o,d;const p=t("check_"+h);if("function"==typeof this.#p[p])i=await this.#p[p](s,c,l);else{if(!g.#n.includes(h))throw new Error(`Invalid validation rule: ${h}`);i=!0}if("boolean"==typeof i?o=i:({success:o,message:d}=i),!o&&(u=!1,d=n(d)?this.getMessage(s,h):d,d=this.makeReplacements(d,s,h,l),this.#g.add(s,d),e||g.#u.includes(h)))break}return u}))}if(this.#b){for(const t of e)if(!await t())break}else await Promise.allSettled(e.map((e=>e()))),this.#g.sortByKeys(Object.keys(this.#h));return this.#m=r.filter(((e,t,r)=>r.indexOf(e)===t)),this.#g}async passes(){return await this.validate(),!this.#g.isNotEmpty()}async fails(){return!await this.passes()}getMessage(e,t){const r=this.getValue(e);let s;e=this.getPrimaryAttribute(e);for(const r of[`${e}.${t}`,t])if(Object.hasOwn(this.#l,r)){s=this.#l[r];break}if(!s){let i=t;this.sizeRules.includes(i)&&(Array.isArray(r)||h(r)||this.hasRule(e,"array")?i+=".array":r instanceof File||this.hasRule(e,this.fileRules)?i+=".file":u(r)||this.hasRule(e,this.numericRules)?i+=".numeric":i+=".string"),s=p.get(i)}return s??`validation.${t}`}makeReplacements(e,r,s,i){const c=this.getDisplayableAttribute(r),a=this.getValue(r),n={attribute:c,ATTRIBUTE:c.toLocaleUpperCase(),Attribute:c.charAt(0).toLocaleUpperCase()+c.substring(1),input:this.getDisplayableValue(r,a)};for(const[t,r]of Object.entries(n))e=e.replaceAll(":"+t,r);const u=r.match(/\.(\d+)\.?/),h=null===u?-1:parseInt(u[1],10);-1!==h&&(e=e.replaceAll(":index",h).replaceAll(":position",h+1));const l=t("replace_"+s);return"function"==typeof this.#f[l]&&(e=this.#f[l](e,r,s,i)),e}getDisplayableAttribute(e){const t=this.getPrimaryAttribute(e);for(const r of[e,t]){if(Object.hasOwn(this.#o,r))return this.#o[r];if(p.has(`attributes.${r}`))return p.get(`attributes.${r}`)}return Object.hasOwn(this.#k,e)?e:(r=e,r.replace(/(.)(?=[A-Z])/g,(e=>e+"_")).toLowerCase()).replaceAll("_"," ");var r}getDisplayableValue(e,t){const r=`${e=this.getPrimaryAttribute(e)}.${t}`;return n(t)?"empty":"boolean"==typeof t||this.hasRule(e,"boolean")?Number(t)?"true":"false":Object.hasOwn(this.#d,r)?this.#d[r]:p.has(`values.${r}`)?p.get(`values.${r}`):t}getSize(e,t){return n(t)?0:u(t)&&this.hasRule(e,this.numericRules)?parseFloat("string"==typeof t?t.trim():t,10):t instanceof File?t.size/1024:h(t)?Object.keys(t).length:Object.hasOwn(t,"length")?t.length:t}getRule(e){return e=this.getPrimaryAttribute(e),this.#h[e]??{}}hasRule(e,t){if(e=this.getPrimaryAttribute(e),t="string"==typeof t?[t]:t,!Object.hasOwn(this.#h,e))return!1;for(const r of t)if(this.#h[e].hasOwnProperty(r))return!0;return!1}getPrimaryAttribute(e){return Object.hasOwn(this.#k,e)?this.#k[e]:e}hasAttribute(e){return void 0!==this.getValue(e)}getValue(e){return function(e,t,r){const s=t.split(".");let i=e;for(const e of s){if(!Object.hasOwn(i,e))return r;i=i[e]}return i}(this.#r,e)}errors(){return this.#g}skippedAttributes(){return this.#m}}return e.Checkers=o,e.ErrorBag=d,e.Lang=p,e.Replacers=f,e.Validator=g,e}({});
6
+ var quival=function(e){"use strict";function t(e){return e.replace(/[-_]/g," ").replace(/\s+/," ").trim().replace(/(\s\w)/g,(e=>e[1].toUpperCase()))}function r(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function s(e,t=""){return Object.keys(e).reduce(((r,i)=>{const c=t?`${t}.${i}`:i;return"object"==typeof e[i]&&null!==e[i]?Object.assign(r,s(e[i],c)):r[c]=e[i],r}),{})}function i(e){const t=[];let r="",s=!1;for(let i=0;i<e.length;i++){const c=e[i];'"'===c?s&&'"'===e[i+1]?(r+='"',i++):(s=!s,s&&(r=r.trim())):","!==c||s?r+=c:(t.push(r),r="")}return t.push(r),t}function c(e){if(n(e)||"string"!=typeof e)return new Date("");if(e instanceof Date)return e;let t,r,s,i,c,a,u,l;const h=e=>e&&/^\d*$/.test(e)?parseInt(e):e;if(null!==(t=e.match(/^(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{2,4})\s?((\d{1,2}):(\d{1,2})(:(\d{1,2}))?\s?(am|pm)?)?/i)))[,i,s,r,,c=0,a=0,,u=0,l="am"]=t.map(h);else if(null!==(t=e.match(/^(\d{2,4})[.\/-](\d{1,2})[.\/-](\d{1,2})\s?((\d{1,2}):(\d{1,2})(:(\d{1,2}))?\s?(am|pm)?)?/i))||null!==(t=e.match(/^(\d{4})(\d{2})(\d{2})\s?((\d{2})(\d{2})((\d{2}))?\s?(am|pm)?)?/i)))[,r,s,i,,c=0,a=0,,u=0,l="am"]=t.map(h);else if(t=e.match(/(\d{1,2}):(\d{1,2})(:(\d{1,2}))?\s?(am|pm)?\s?(\d{4})[.\/-](\d{2})[.\/-](\d{2})/i))[,c,a,,u,l="am",r,s,i]=t.map(h);else if(t=e.match(/(\d{1,2}):(\d{1,2})(:(\d{1,2}))?\s?(am|pm)?\s?(\d{2})[.\/-](\d{2})[.\/-](\d{4})/i))[,c,a,,u,l="am",i,s,r]=t.map(h);else{if(!(t=e.match(/(\d{1,2}):(\d{1,2})(:(\d{1,2}))?\s?(am|pm)?/i)))return new Date(e);{const e=new Date;r=e.getFullYear(),s=e.getMonth()+1,i=e.getDate(),[,c=0,a=0,,u=0,l="am"]=t.map(h)}}return r>=10&&r<100&&(r+=2e3),"pm"===l.toLowerCase()&&c<12&&(c+=12),new Date(`${r}-${s}-${i} ${c}:${a}:${u}`)}function a(e,t){if(n(e))return new Date("");t=t.split("");const r={Y:"(\\d{4})",y:"(\\d{2})",m:"(\\d{2})",n:"([1-9]\\d?)",d:"(\\d{2})",j:"([1-9]\\d?)",G:"([1-9]\\d?)",g:"([1-9]\\d?)",H:"(\\d{2})",h:"(\\d{2})",i:"(\\d{2})",s:"(\\d{2})",A:"(AM|PM)",a:"(am|pm)"};let s="^",i={years:-1,months:-1,days:-1,hours:-1,minutes:-1,seconds:-1,meridiem:-1},c=1;for(const e of t)Object.hasOwn(r,e)?(s+=r[e],-1!==["Y","y"].indexOf(e)?i.years=c++:-1!==["m","n"].indexOf(e)?i.months=c++:-1!==["d","j"].indexOf(e)?i.days=c++:-1!==["G","g","H","h"].indexOf(e)?i.hours=c++:"i"===e?i.minutes=c++:"s"===e?i.seconds=c++:-1!==["A","a"].indexOf(e)&&(i.meridiem=c++)):s+="\\"+e;s+="$";let a=e.match(new RegExp(s));if(null===a)return new Date("");a=a.map((e=>e&&/^\d*$/.test(e)?parseInt(e):e));const u=new Date;let l=a[i.years],h=a[i.months],o=a[i.days],d=a[i.hours]??0,p=a[i.minutes]??0,f=a[i.seconds]??0,g=a[i.meridiem]??"am";return l||h||o?!l||h||o?l||!h||o?l||h||!o||(l=u.getFullYear(),h=u.getMonth()+1):(l=u.getFullYear(),o=1):(h=1,o=1):(l=u.getFullYear(),h=u.getMonth()+1,o=u.getDate()),l>=10&&l<100&&(l+=2e3),"pm"===g.toLowerCase()&&d<12&&(d+=12),new Date(`${l}-${h}-${o} ${d}:${p}:${f}`)}function n(e){return""===e||null==e}function u(e){const t=Number(e);return null!==e&&"boolean"!=typeof e&&"number"==typeof t&&!isNaN(t)}function l(e){return"[object Object]"===Object.prototype.toString.call(e)}function h(e){return e instanceof Date&&"Invalid Date"!==e.toDateString()}class o{#e;#t;constructor(e){this.#e={},this.#t={},this.validator=e}clearCaches(){this.#e={},this.#t={}}isDependent(e){const t=this.validator.getValue(e[0]);return e.slice(1).some((e=>e==t))}collectRequiredsThenTest(e,t,r,s){let i=[];for(const e of r)i.push(this.checkRequired(e,this.validator.getValue(e)));return!s(i)||this.checkRequired(e,t)}collectMissingsThenTest(e,t,r,s){let i=[];for(const e of r)i.push(this.checkMissing(e));return!s(i)||this.checkMissing(e)}testStringUsingRegex(e,t,r,s,i=!1){return("string"==typeof t||"number"==typeof t)&&(t=String(t),i||this.validator.hasRule(e,"ascii")?r.test(t):s.test(t))}compareValues(e,t,r,s){if(n(t))return!1;const i=r[0]??"";let c=this.validator.getValue(i);return c=void 0===c?u(i)?parseFloat(i,10):null:this.validator.getSize(i,c),!n(c)&&s(this.validator.getSize(e,t),c)}compareDates(e,t,r,s){const i=this.validator.getRule(e);if(!h(t=Object.hasOwn(i,"date_format")?a(t,i.date_format[0]):c(t)))return!1;const n=r[0]??"";let u=this.validator.getValue(n);if(void 0===u)u=c(n);else{const e=this.validator.getRule(n);u=Object.hasOwn(e,"date_format")?a(u,e.date_format[0]):c(u)}return!!h(u)&&s(t.getTime(),u.getTime())}checkArray(e,t,r){if(!Array.isArray(t)&&!l(t))return!1;if(r&&r.length>0)for(const e of Object.keys(t))if(!r.includes(e))return!1;return!0}checkList(e,t,r){return Array.isArray(t)}checkBoolean(e,t,r){return[!0,!1,0,1,"0","1"].includes(t)}checkDate(e,t,r){return h(c(t))}checkFile(e,t,r){return t instanceof File}checkInteger(e,t,r){return String(parseInt(t,10))===String(t)}checkNumeric(e,t,r){return u(t)}checkString(e,t,r){return"string"==typeof t}checkDecimal(e,t,r){if(!this.checkNumeric(e,t))return!1;const s=(String(t).split(".")[1]??"").length;return 1===r.length?s==r[0]:s>=r[0]&&s<=r[1]}checkMultipleOf(e,t,r){if(!u(t)||!u(r[0]))return!1;const s=parseInt(t,10),i=parseInt(r[0],10);return(0!==s||0!==i)&&(0===s||0!==i&&s%i==0)}checkAccepted(e,t,r){return["yes","on","1",1,!0,"true"].includes(t)}checkAcceptedIf(e,t,r){return!this.isDependent(r)||this.checkAccepted(e,t,r)}checkDeclined(e,t,r){return["no","off","0",0,!1,"false"].includes(t)}checkDeclinedIf(e,t,r){return!this.isDependent(r)||this.checkDeclined(e,t,r)}checkRequired(e,t,r){return!n(t)&&(Array.isArray(t)?t.length>0:t instanceof File?t.size>0:(t=String(t).replace(/\s/g,"")).length>0)}checkRequiredArrayKeys(e,t,r){if(!this.checkArray(e,t))return!1;const s=Object.keys(t);for(const e of r)if(!s.includes(e))return!1;return!0}checkRequiredIf(e,t,r){return!this.isDependent(r)||this.checkRequired(e,t)}checkRequiredIfAccepted(e,t,r){return!this.checkAccepted(r[0],this.validator.getValue(r[0]))||this.checkRequired(e,t)}checkRequiredIfDeclined(e,t,r){return!this.checkDeclined(r[0],this.validator.getValue(r[0]))||this.checkRequired(e,t)}checkRequiredUnless(e,t,r){return!!this.isDependent(r)||this.checkRequired(e,t)}checkRequiredWith(e,t,r){return this.collectRequiredsThenTest(e,t,r,(e=>e.includes(!0)))}checkRequiredWithAll(e,t,r){return this.collectRequiredsThenTest(e,t,r,(e=>!e.includes(!1)))}checkRequiredWithout(e,t,r){return this.collectRequiredsThenTest(e,t,r,(e=>e.includes(!1)))}checkRequiredWithoutAll(e,t,r){return this.collectRequiredsThenTest(e,t,r,(e=>!e.includes(!0)))}checkFilled(e,t,r){return void 0===t||this.checkRequired(e,t)}checkPresent(e,t,r){return void 0!==t}checkMissing(e,t,r){return!this.validator.hasAttribute(e)}checkMissingIf(e,t,r){return!this.isDependent(r)||this.checkMissing(e)}checkMissingUnless(e,t,r){return!!this.isDependent(r)||this.checkMissing(e)}checkMissingWith(e,t,r){return this.collectMissingsThenTest(e,t,r,(e=>e.includes(!1)))}checkMissingWithAll(e,t,r){return this.collectMissingsThenTest(e,t,r,(e=>!e.includes(!0)))}checkProhibited(e,t,r){return!this.checkRequired(e,t)}checkProhibitedIf(e,t,r){return!this.isDependent(r)||!this.checkRequired(e,t)}checkProhibitedUnless(e,t,r){return!!this.isDependent(r)||!this.checkRequired(e,t)}checkProhibits(e,t,r){if(this.checkRequired(e,t))for(const e of r)if(this.checkRequired(e,this.validator.getValue(e)))return!1;return!0}checkSize(e,t,r){return this.validator.getSize(e,t)===parseFloat(r[0])}checkMin(e,t,r){return this.validator.getSize(e,t)>=parseFloat(r[0])}checkMax(e,t,r){return this.validator.getSize(e,t)<=parseFloat(r[0])}checkBetween(e,t,r){return this.checkMin(e,t,[r[0]])&&this.checkMax(e,t,[r[1]])}checkDigits(e,t,r,s=(e,t)=>e===t){return!!function(e){return-1===String(e).search(/[^0-9]/)}(t=String(t??""))&&s(t.length,parseInt(r[0],10),parseInt(r[1]??0,10))}checkMinDigits(e,t,r){return this.checkDigits(e,t,r,((e,t)=>e>=t))}checkMaxDigits(e,t,r){return this.checkDigits(e,t,r,((e,t)=>e<=t))}checkDigitsBetween(e,t,r){return this.checkDigits(e,t,r,((e,t,r)=>e>=t&&e<=r))}checkAlpha(e,t,r){return this.testStringUsingRegex(e,t,/^[a-z]+$/i,/^[\p{L}\p{M}]+$/u,r.includes("ascii"))}checkAlphaDash(e,t,r){return this.testStringUsingRegex(e,t,/^[a-z0-9_-]+$/i,/^[\p{L}\p{M}\p{N}_-]+$/u,r.includes("ascii"))}checkAlphaNum(e,t,r){return this.testStringUsingRegex(e,t,/^[a-z0-9]+$/i,/^[\p{L}\p{M}\p{N}]+$/u,r.includes("ascii"))}checkAscii(e,t,r){return!/[^\x09\x10\x13\x0A\x0D\x20-\x7E]/.test(t)}checkRegex(e,t,r,s=!1){if("string"!=typeof t&&!u(t))return!1;const i=r.join(",");let[c,a,l]=i.match(/^\/(.*)\/([gimu]*)$/)??[];if(n(c))throw new Error(`Invalid regular expression pattern: ${i}`);l.includes("u")&&(a=a.replace(/\\A/g,"^").replace(/\\z/gi,"$").replace(/\\([pP])([CLMNPSZ])/g,"\\$1{$2}").replace(/\\\x\{([0-9a-f]+)\}/g,"\\u{$1}"));const h=new RegExp(a,l).test(t);return s?!h:h}checkNotRegex(e,t,r){return this.checkRegex(e,t,r,!0)}checkLowercase(e,t,r){return t===String(t).toLocaleLowerCase()}checkUppercase(e,t,r){return t===String(t).toLocaleUpperCase()}checkStartsWith(e,t,r){t=String(t);for(const e of r)if(t.startsWith(e))return!0;return!1}checkDoesntStartWith(e,t,r){return!this.checkStartsWith(e,t,r)}checkEndsWith(e,t,r){t=String(t);for(const e of r)if(t.endsWith(e))return!0;return!1}checkDoesntEndWith(e,t,r){return!this.checkEndsWith(e,t,r)}checkSame(e,t,r){return t===this.validator.getValue(r[0])}checkDifferent(e,t,r){for(const e of r){const r=this.validator.getValue(e);if(void 0!==r&&t===r)return!1}return!0}checkConfirmed(e,t,r){return this.checkSame(e,t,[e+"_confirmation"])}checkGt(e,t,r){return this.compareValues(e,t,r,((e,t)=>e>t))}checkGte(e,t,r){return this.compareValues(e,t,r,((e,t)=>e>=t))}checkLt(e,t,r){return this.compareValues(e,t,r,((e,t)=>e<t))}checkLte(e,t,r){return this.compareValues(e,t,r,((e,t)=>e<=t))}checkAfter(e,t,r){return this.compareDates(e,t,r,((e,t)=>e>t))}checkAfterOrEqual(e,t,r){return this.compareDates(e,t,r,((e,t)=>e>=t))}checkBefore(e,t,r){return this.compareDates(e,t,r,((e,t)=>e<t))}checkBeforeOrEqual(e,t,r){return this.compareDates(e,t,r,((e,t)=>e<=t))}checkDateEquals(e,t,r){return this.compareDates(e,t,r,((e,t)=>e===t))}checkDateFormat(e,t,r){const s=r[0].split(""),i={Y:"(\\d{4})",y:"(\\d{2})",m:"(\\d{2})",n:"([1-9]\\d?)",d:"(\\d{2})",j:"([1-9]\\d?)",G:"([1-9]\\d?)",g:"([1-9]\\d?)",H:"(\\d{2})",h:"(\\d{2})",i:"(\\d{2})",s:"(\\d{2})",A:"(AM|PM)",a:"(am|pm)"};let c="^";for(const e of s)Object.hasOwn(i,e)?c+=i[e]:c+="\\"+e;return c+="$",new RegExp(c).test(t)}checkContains(e,t,r){if(!this.checkArray(e,t))return!1;for(const e of r)if(!t.includes(e))return!1;return!0}checkDistinct(e,t,i){const c=this.validator.getPrimaryAttribute(e);if(!c.includes("*"))return!0;const a=c.indexOf("*"),n=c.substring(0,a-1);let u;Object.hasOwn(this.#e,n)?u=this.#e[n]:(u=JSON.stringify(s(this.validator.getValue(n)??{})),this.#e[n]=u);const l=i.includes("ignore_case"),h=!l&&i.includes("strict"),o=r(String(t));let d=`"${r(c.substring(a)).replaceAll("\\*",'[^."]+')}":`,p=0;return d+=h?"string"==typeof t?`"${o}"`:`${o}`:`(${o}|"${o}")`,d+="[,}]+",p+=u.match(new RegExp(d,"g"+(l?"i":"")))?.length??0,1===p}checkInArray(e,t,r){const i=this.validator.getPrimaryAttribute(r[0]);if(!i.includes("*"))return!1;const c=this.validator.getValue(i.split(".*")[0])??{};return Object.values(s(c)).some((e=>e==t))}checkIn(e,t,r){if(!this.checkArray(e,t)||!this.validator.hasRule(e,"array"))return r.some((e=>e==t));for(const e of Object.values(t))if(!r.some((t=>t==e)))return!1;return!0}checkNotIn(e,t,r){return!this.checkIn(e,t,r)}checkMimetypes(e,t,r){return!!this.checkFile(e,t)&&r.includes(t.type)}checkMimes(e,t,r){return!!this.checkFile(e,t)&&(r.includes("jpg")&&!r.includes("jpeg")&&r.push("jpeg"),r.includes("jpeg")&&!r.includes("jpg")&&r.push("jpg"),r.includes(t.name.split(".").pop().toLowerCase()))}checkExtensions(e,t,r){return this.checkMimes(e,t,r)}async checkImage(e,t,r){let s=this.checkMimes(e,t,["jpg","jpeg","png","gif","bmp","svg","webp"]);return s&&"undefined"!=typeof FileReader?(await new Promise(((e,r)=>{const s=new FileReader;s.onload=t=>e(t.target.result),s.onerror=r,s.readAsDataURL(t)})).then((async t=>{const r=new Image;r.src=t,await r.decode(),this.#t[e]=r})).catch((()=>{s=!1})),s):s}async checkDimensions(e,t,r){if(!this.checkImage(e,t)||!Object.hasOwn(this.#t,e))return!1;const s={};for(const e of r){const[t,r]=e.split("=",2);if("ratio"===t&&r.includes("/")){const[e,i]=r.split("/",2).map((e=>parseFloat(e,10)));s[t]=e/i}else s[t]=parseFloat(r,10)}const i=this.#t[e],c=i.naturalWidth,a=i.naturalHeight;return!(Object.hasOwn(s,"width")&&s.width!==c||Object.hasOwn(s,"height")&&s.height!==a||Object.hasOwn(s,"min_width")&&s.min_width>c||Object.hasOwn(s,"min_height")&&s.min_height>a||Object.hasOwn(s,"max_width")&&s.max_width<c||Object.hasOwn(s,"max_height")&&s.max_height<a)&&(!Object.hasOwn(s,"ratio")||Math.abs(s.ratio-c/a)<=1/(Math.max(c,a)+1))}checkEmail(e,t,r){if(!/^(([^<>()[\]\\.,;:\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,}))$/.test(t)){return/^((?:[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]))?)+)*$/.test(t)}return!0}checkJson(e,t,r){try{JSON.parse(t)}catch(e){return!1}return!0}checkHexColor(e,t,r){return/^#(?:(?:[0-9a-f]{3}){1,2}|(?:[0-9a-f]{4}){1,2})$/i.test(t)}checkMacAddress(e,t,r){t=String(t);const s={"-":2,":":2,".":4};let i,c;for([i,c]of Object.entries(s))if(t.includes(i))break;const a=t.split(i);if(a.length!==12/c)return!1;for(const e of a)if(!new RegExp("^[0-9a-f]{"+c+"}$","i").test(e))return!1;return!0}checkIpv4(e,t,r){if(/[^\d.]/.test(t))return!1;const s=String(t).split(".");if(4!==s.length)return!1;for(const e of s)if(e<0||e>255)return!1;return!0}checkIpv6(e,t,r){if((t=String(t)).includes(":::")||t.split("::").length>2)return!1;const s=t.split(":");if(s.length<3||s.length>8)return!1;for(const e of s)if(""!==e&&!/^[0-9a-f]{1,4}$/i.test(e))return!1;return!0}checkIp(e,t,r){return this.checkIpv4(e,t,r)||this.checkIpv6(e,t,r)}checkTimezone(e,t,r){try{Intl.DateTimeFormat(void 0,{timeZone:t})}catch(e){if(String(e).toLowerCase().includes("invalid time zone"))return!1}return!0}checkUrl(e,t,r){try{new URL(t)}catch(e){return!1}return!0}checkUlid(e,t,r){return/[0-7][0-9A-HJKMNP-TV-Z]{25}/.test(t)}checkUuid(e,t,r){return/[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}/.test(t)}}class d{#r;keys(){return Object.keys(this.#r)}values(){return Object.values(this.#r)}entries(){return Object.entries(this.#r)}add(e,t){Object.hasOwn(this.#r,e)?this.#r[e].push(t):this.#r[e]=[t]}get(e){if(!e.includes("*"))return Object.hasOwn(this.#r,e)?this.#r[e]:{};const t=new RegExp("^"+e.replaceAll("*",".*?")+"$"),r={};for(const[e,s]of this.entries())t.test(e)&&(r[e]=s);return r}first(e){for(const t of Object.values(this.get(e)))return Array.isArray(t)?t[0]:t;return""}has(e){return""!==this.first(e)}remove(e){delete this.#r[e]}messages(){return this.#r}all(){const e=[];return this.values().forEach((t=>e.push(...t))),e}count(){let e=0;return this.values().forEach((t=>e+=t.length)),e}isEmpty(){return 0===this.keys().length}isNotEmpty(){return!this.isEmpty()}sortByKeys(e){const t={};for(const r of e)Object.hasOwn(this.#r,r)&&(t[r]=this.#r[r]);this.#r=t}constructor(){this.#r={}}}class p{static#s;static#i={};static locale(e){this.#s=e}static setMessages(e,t){this.#i[e]=s(t)}static get(e){if(this.#i[this.#s]&&this.#i[this.#s][e])return this.#i[this.#s][e]}static has(e){return void 0!==this.get(e)}static set(e,t){l(t)?Object.assign(this.#i[this.#s],s(t,e)):"string"==typeof t&&(this.#i[this.#s][e]=t)}}class f{constructor(e){this.validator=e}replace(e,t){return Object.entries(t).forEach((([t,r])=>e=e.replaceAll(":"+t,r))),e}replaceDecimal(e,t,r,s){return this.replace(e,{decimal:s.join("-")})}replaceMultipleOf(e,t,r,s){return this.replace(e,{value:s[0]})}replaceAcceptedIf(e,t,r,s){return this.replace(e,{other:this.validator.getDisplayableAttribute(s[0]),value:this.validator.getDisplayableValue(s[0],this.validator.getValue(s[0]))})}replaceDeclinedIf(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceRequiredArrayKeys(e,t,r,s){return this.replace(e,{values:s.map((e=>this.validator.getDisplayableValue(t,e))).join(", ")})}replaceRequiredIf(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceRequiredIfAccepted(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceRequiredIfDeclined(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceRequiredUnless(e,t,r,s){return this.replace(e,{other:this.validator.getDisplayableAttribute(s[0]),values:s.slice(1).map((e=>this.validator.getDisplayableValue(s[0],e))).join(", ")})}replaceRequiredWith(e,t,r,s){return this.replace(e,{values:s.map((e=>this.validator.getDisplayableAttribute(e))).join(" / ")})}replaceRequiredWithAll(e,t,r,s){return this.replaceRequiredWith(e,t,r,s)}replaceRequiredWithout(e,t,r,s){return this.replaceRequiredWith(e,t,r,s)}replaceRequiredWithoutAll(e,t,r,s){return this.replaceRequiredWith(e,t,r,s)}replaceMissingIf(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceMissingUnless(e,t,r,s){return this.replace(this.replaceRequiredUnless(e,t,r,s),{value:this.validator.getDisplayableValue(s[0],s[1])})}replaceMissingWith(e,t,r,s){return this.replaceRequiredWith(e,t,r,s)}replaceMissingWithAll(e,t,r,s){return this.replaceRequiredWith(e,t,r,s)}replaceProhibitedIf(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceProhibitedUnless(e,t,r,s){return this.replaceRequiredUnless(e,t,r,s)}replaceProhibits(e,t,r,s){return this.replace(e,{other:s.map((e=>this.validator.getDisplayableAttribute(e))).join(" / ")})}replaceSize(e,t,r,s){return this.replace(e,{size:s[0]})}replaceMin(e,t,r,s){return this.replace(e,{min:s[0]})}replaceMax(e,t,r,s){return this.replace(e,{max:s[0]})}replaceBetween(e,t,r,s){return this.replace(e,{min:s[0],max:s[1]})}replaceDigits(e,t,r,s){return this.replace(e,{digits:s[0]})}replaceMinDigits(e,t,r,s){return this.replaceMin(e,t,r,s)}replaceMaxDigits(e,t,r,s){return this.replaceMax(e,t,r,s)}replaceDigitsBetween(e,t,r,s){return this.replaceBetween(e,t,r,s)}replaceStartsWith(e,t,r,s){return this.replaceRequiredArrayKeys(e,t,r,s)}replaceDoesntStartWith(e,t,r,s){return this.replaceRequiredArrayKeys(e,t,r,s)}replaceEndsWith(e,t,r,s){return this.replaceRequiredArrayKeys(e,t,r,s)}replaceDoesntEndWith(e,t,r,s){return this.replaceRequiredArrayKeys(e,t,r,s)}replaceSame(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceDifferent(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceGt(e,t,r,s){const i=this.validator.getValue(s[0]);return this.replace(e,{value:i?this.validator.getSize(s[0],i):this.validator.getDisplayableAttribute(s[0])})}replaceGte(e,t,r,s){return this.replaceGt(e,t,r,s)}replaceLt(e,t,r,s){return this.replaceGt(e,t,r,s)}replaceLte(e,t,r,s){return this.replaceGt(e,t,r,s)}replaceAfter(e,t,r,s){const i=s[0];return this.replace(e,{date:this.validator.hasAttribute(i)?this.validator.getDisplayableAttribute(i):i})}replaceAfterOrEqual(e,t,r,s){return this.replaceAfter(e,t,r,s)}replaceBefore(e,t,r,s){return this.replaceAfter(e,t,r,s)}replaceBeforeOrEqual(e,t,r,s){return this.replaceAfter(e,t,r,s)}replaceDateEquals(e,t,r,s){return this.replaceAfter(e,t,r,s)}replaceDateFormat(e,t,r,s){return this.replace(e,{format:s[0]})}replaceInArray(e,t,r,s){return this.replaceAcceptedIf(e,t,r,s)}replaceIn(e,t,r,s){return this.replaceRequiredArrayKeys(e,t,r,s)}replaceNotIn(e,t,r,s){return this.replaceRequiredArrayKeys(e,t,r,s)}replaceMimetypes(e,t,r,s){return this.replace(e,{values:s.join(", ")})}replaceMimes(e,t,r,s){return this.replaceMimetypes(e,t,r,s)}replaceExtensions(e,t,r,s){return this.replaceMimetypes(e,t,r,s)}}class g{static#c={};static#a={};static#n=["active_url","bail","can","current_password","enum","exclude","exclude_if","exclude_unless","exclude_with","exclude_without","exists","nullable","sometimes","unique"];static#u=["accepted","accepted_if","declined","declined_if","filled","missing","missing_if","missing_unless","missing_with","missing_with_all","present","required","required_if","required_if_accepted","required_if_declined","required_unless","required_with","required_with_all","required_without","required_without_all"];#r;#l;#h;#o;#d;#p;#f;#g;#m;#k;#b;#A;static setLocale(e){p.locale(e)}static setMessages(e,t){p.setMessages(e,t)}static addChecker(e,t,r){g.#c[e]=t,r&&p.set(e,r)}static addImplicitChecker(e,t,r){g.addChecker(e,t,r),g.#u.push(e)}static addReplacer(e,t){g.#a[e]=t}static addDummyRule(e){g.#n.push(e)}constructor(e={},r={},s={},i={},c={}){this.#m=[],this.#k={},this.#b=!1,this.#A=!1,this.fileRules=["file","image","mimetypes","mimes"],this.numericRules=["decimal","numeric","integer"],this.sizeRules=["size","between","min","max","gt","lt","gte","lte"],this.setProperties(e,r,s,i,c),this.#p=new o(this),this.#f=new f(this);for(const[e,r]of Object.entries(g.#c))this.#p[t("check_"+e)]=r;for(const[e,r]of Object.entries(g.#a))this.#f[t("replace_"+e)]=r;this.#g=new d}setProperties(e={},t={},r={},i={},c={}){return this.#r=e,this.#l=this.parseRules(t),this.#h=r,this.#o=i,this.#d=s(c),this}setData(e){return this.#r=e,this}setRules(e){return this.#l=this.parseRules(e),this}setCustomMessages(e){return this.#h=e,this}setCustomAttributes(e){return this.#o=e,this}setCustomValues(e){return this.#d=s(e),this}addImplicitAttribute(e,t){return this.#k[e]=t,this}stopOnFirstFailure(e=!0){return this.#b=e,this}alwaysBail(e=!0){return this.#A=e,this}parseRules(e){const t={};for(const[r,s]of Object.entries(e)){const e=r.includes("*")?this.parseWildcardAttribute(r):[r];for(const r of e){const e=[];for(const t of this.parseAttributeRules(s))e.push(this.parseAttributeRule(t));t[r]=e}}return t}parseWildcardAttribute(e){const t=[],r=e.indexOf("*"),s=e.substring(0,r-1),i=e.substring(r+2),c=this.getValue(s);return Array.isArray(c)||l(c)?(Object.entries(c).forEach((([r,c])=>{const a=`${s}.${r}.${i}`.replace(/\.$/,""),n=a.includes("*")?this.parseWildcardAttribute(a):[a];t.push(...n),n.forEach((t=>this.#k[t]=e))})),t):[e]}parseAttributeRules(e){return Array.isArray(e)?e:"function"==typeof e?[e]:String(e).split("|")}parseAttributeRule(e){if(Array.isArray(e))return[e[0]??"",e.slice(1)];if("function"==typeof e)return[e,[]];const t=e.indexOf(":");return-1===t?[e,[]]:[e.substring(0,t),i(e.substring(t+1))]}async validate(){this.#p.clearCaches(),this.#g=new d;const e=[],r=[];for(const[e,r]of Object.entries(this.#l))for(const[e]of r)if(""!==e&&"function"!=typeof e&&"function"!=typeof this.#p[t("check_"+e)]&&!g.#n.includes(e))throw new Error(`Invalid validation rule: ${e}`);for(const[s,i]of Object.entries(this.#l)){let c=this.getValue(s);const a=e=>i.some((t=>t[0]===e));a("sometimes")&&void 0===c?r.push(s):e.push((async()=>{const e=this.#A||a("bail"),u=a("nullable");let l=!0;for(const[a,h]of i){if(""===a||"function"!=typeof a&&!g.#u.includes(a)&&(void 0===c||"string"==typeof c&&""===c.trim()||u&&null===c)){r.push(s);continue}let i,o,d;const p=(()=>{if("function"==typeof a)return a;{const e=this.#p[t("check_"+a)]??null;return null===e&&g.#n.includes(a)?()=>!0:e}})();if(null===p)throw new Error(`Invalid validation rule: ${a}`);if(i=await p.call(this.#p,s,c,h),"boolean"==typeof i&&(i={success:i}),({success:o,message:d=""}=i),!o&&(l=!1,d=n(d)?this.getMessage(s,a):d,d=this.makeReplacements(d,s,a,h),this.#g.add(s,d),e||g.#u.includes(a)))break}return l}))}if(this.#b){for(const t of e)if(!await t())break}else await Promise.allSettled(e.map((e=>e()))).then((e=>{for(const t of e)if("rejected"===t.status)throw t.reason})),this.#g.sortByKeys(Object.keys(this.#l));return this.#m=r.filter(((e,t,r)=>r.indexOf(e)===t)),this.#g}async passes(){return await this.validate(),!this.#g.isNotEmpty()}async fails(){return!await this.passes()}getMessage(e,t){if("function"==typeof t)return"";const r=this.getValue(e);let s;e=this.getPrimaryAttribute(e);for(const r of[`${e}.${t}`,t])if(Object.hasOwn(this.#h,r)){s=this.#h[r];break}if(!s){let i=t;this.sizeRules.includes(i)&&(Array.isArray(r)||l(r)||this.hasRule(e,"array")?i+=".array":r instanceof File||this.hasRule(e,this.fileRules)?i+=".file":u(r)||this.hasRule(e,this.numericRules)?i+=".numeric":i+=".string"),s=p.get(i)}return s??`validation.${t}`}makeReplacements(e,r,s,i){const c=this.getDisplayableAttribute(r),a=this.getValue(r),n={attribute:c,ATTRIBUTE:c.toLocaleUpperCase(),Attribute:c.charAt(0).toLocaleUpperCase()+c.substring(1),input:this.getDisplayableValue(r,a)};for(const[t,r]of Object.entries(n))e=e.replaceAll(":"+t,r);const u=r.match(/\.(\d+)\.?/),l=null===u?-1:parseInt(u[1],10);if(-1!==l&&(e=e.replaceAll(":index",l).replaceAll(":position",l+1)),"string"==typeof s){const c=this.#f[t("replace_"+s)]??null;c&&(e=c.call(this.#f,e,r,s,i))}return e}getDisplayableAttribute(e){const t=this.getPrimaryAttribute(e);for(const r of[e,t]){if(Object.hasOwn(this.#o,r))return this.#o[r];if(p.has(`attributes.${r}`))return p.get(`attributes.${r}`)}return Object.hasOwn(this.#k,e)?e:(r=e,r.replace(/(.)(?=[A-Z])/g,(e=>e+"_")).toLowerCase()).replaceAll("_"," ");var r}getDisplayableValue(e,t){const r=`${e=this.getPrimaryAttribute(e)}.${t}`;return n(t)?"empty":"boolean"==typeof t||this.hasRule(e,"boolean")?Number(t)?"true":"false":Object.hasOwn(this.#d,r)?this.#d[r]:p.has(`values.${r}`)?p.get(`values.${r}`):t}getSize(e,t){return n(t)?0:u(t)&&this.hasRule(e,this.numericRules)?parseFloat("string"==typeof t?t.trim():t,10):t instanceof File?t.size/1024:l(t)?Object.keys(t).length:Object.hasOwn(t,"length")?t.length:t}getRule(e){return e=this.getPrimaryAttribute(e),this.#l[e]??{}}hasRule(e,t){if(e=this.getPrimaryAttribute(e),t="string"==typeof t?[t]:t,!Object.hasOwn(this.#l,e))return!1;for(const r of t)if(this.#l[e].some((e=>e[0]===r)))return!0;return!1}getPrimaryAttribute(e){return Object.hasOwn(this.#k,e)?this.#k[e]:e}hasAttribute(e){return void 0!==this.getValue(e)}getValue(e){return function(e,t,r){const s=t.split(".");let i=e;for(const e of s){if(!Object.hasOwn(i,e))return r;i=i[e]}return i}(this.#r,e)}errors(){return this.#g}skippedAttributes(){return this.#m}}return e.Checkers=o,e.ErrorBag=d,e.Lang=p,e.Replacers=f,e.Validator=g,e}({});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quival",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "description": "Data validation à la Laravel Validation",
5
5
  "author": "Mohd Hafizuddin M Marzuki <hafizuddin_83@yahoo.com>",
6
6
  "license": "MIT",
package/src/Checkers.js CHANGED
@@ -691,11 +691,19 @@ export default class Checkers {
691
691
  }
692
692
 
693
693
  checkMimes(attribute, value, parameters) {
694
- if (this.checkFile(attribute, value)) {
695
- return parameters.includes(value.name.split('.').pop().toLowerCase());
694
+ if (!this.checkFile(attribute, value)) {
695
+ return false;
696
696
  }
697
697
 
698
- return false;
698
+ if (parameters.includes('jpg') && !parameters.includes('jpeg')) {
699
+ parameters.push('jpeg');
700
+ }
701
+
702
+ if (parameters.includes('jpeg') && !parameters.includes('jpg')) {
703
+ parameters.push('jpg');
704
+ }
705
+
706
+ return parameters.includes(value.name.split('.').pop().toLowerCase());
699
707
  }
700
708
 
701
709
  checkExtensions(attribute, value, parameters) {
package/src/Validator.js CHANGED
@@ -178,12 +178,10 @@ export default class Validator {
178
178
  const attributes = attribute.includes('*') ? this.parseWildcardAttribute(attribute) : [attribute];
179
179
 
180
180
  for (const attribute of attributes) {
181
- const parsedAttributeRules = {};
181
+ const parsedAttributeRules = [];
182
182
 
183
183
  for (const attributeRule of this.parseAttributeRules(attributeRules)) {
184
- const [rule, parameters] = this.parseAttributeRule(attributeRule);
185
-
186
- parsedAttributeRules[rule] = parameters;
184
+ parsedAttributeRules.push(this.parseAttributeRule(attributeRule));
187
185
  }
188
186
 
189
187
  parsedRules[attribute] = parsedAttributeRules;
@@ -218,6 +216,8 @@ export default class Validator {
218
216
  parseAttributeRules(rules) {
219
217
  if (Array.isArray(rules)) {
220
218
  return rules;
219
+ } else if (typeof rules === 'function') {
220
+ return [rules];
221
221
  } else {
222
222
  return String(rules).split('|');
223
223
  }
@@ -225,7 +225,9 @@ export default class Validator {
225
225
 
226
226
  parseAttributeRule(rule) {
227
227
  if (Array.isArray(rule)) {
228
- return [rule.shift() ?? '', rule];
228
+ return [rule[0] ?? '', rule.slice(1)];
229
+ } else if (typeof rule === 'function') {
230
+ return [rule, []];
229
231
  }
230
232
 
231
233
  const index = rule.indexOf(':');
@@ -244,23 +246,39 @@ export default class Validator {
244
246
  const tasks = [];
245
247
  const skippedAttributes = [];
246
248
 
249
+ for (const [attribute, rules] of Object.entries(this.#rules)) {
250
+ for (const [rule] of rules) {
251
+ if (
252
+ rule === '' ||
253
+ typeof rule === 'function' ||
254
+ typeof this.#checkers[toCamelCase('check_' + rule)] === 'function' ||
255
+ Validator.#dummyRules.includes(rule)
256
+ )
257
+ continue;
258
+
259
+ throw new Error(`Invalid validation rule: ${rule}`);
260
+ }
261
+ }
262
+
247
263
  for (const [attribute, rules] of Object.entries(this.#rules)) {
248
264
  let value = this.getValue(attribute);
265
+ const hasRule = (ruleName) => rules.some((rule) => rule[0] === ruleName);
249
266
 
250
- if (Object.hasOwn(rules, 'sometimes') && typeof value === 'undefined') {
267
+ if (hasRule('sometimes') && typeof value === 'undefined') {
251
268
  skippedAttributes.push(attribute);
252
269
  continue;
253
270
  }
254
271
 
255
272
  tasks.push(async () => {
256
- const doBail = this.#alwaysBail || Object.hasOwn(rules, 'bail');
257
- const isNullable = Object.hasOwn(rules, 'nullable');
273
+ const doBail = this.#alwaysBail || hasRule('bail');
274
+ const isNullable = hasRule('nullable');
258
275
  let noError = true;
259
276
 
260
- for (const [rule, parameters] of Object.entries(rules)) {
277
+ for (const [rule, parameters] of rules) {
261
278
  if (
262
279
  rule === '' ||
263
- (!Validator.#implicitRules.includes(rule) &&
280
+ (typeof rule !== 'function' &&
281
+ !Validator.#implicitRules.includes(rule) &&
264
282
  (typeof value === 'undefined' || (typeof value === 'string' && value.trim() === '') || (isNullable && value === null)))
265
283
  ) {
266
284
  skippedAttributes.push(attribute);
@@ -268,22 +286,33 @@ export default class Validator {
268
286
  }
269
287
 
270
288
  let result, success, message;
271
- const camelRule = toCamelCase('check_' + rule);
272
289
 
273
- if (typeof this.#checkers[camelRule] === 'function') {
274
- result = await this.#checkers[camelRule](attribute, value, parameters);
275
- } else if (Validator.#dummyRules.includes(rule)) {
276
- result = true;
277
- } else {
290
+ const checker = (() => {
291
+ if (typeof rule === 'function') {
292
+ return rule;
293
+ } else {
294
+ const checker = this.#checkers[toCamelCase('check_' + rule)] ?? null;
295
+
296
+ if (checker === null && Validator.#dummyRules.includes(rule)) {
297
+ return () => true;
298
+ }
299
+
300
+ return checker;
301
+ }
302
+ })();
303
+
304
+ if (checker === null) {
278
305
  throw new Error(`Invalid validation rule: ${rule}`);
279
306
  }
280
307
 
308
+ result = await checker.call(this.#checkers, attribute, value, parameters);
309
+
281
310
  if (typeof result === 'boolean') {
282
- success = result;
283
- } else {
284
- ({ success, message } = result);
311
+ result = { success: result };
285
312
  }
286
313
 
314
+ ({ success, message = '' } = result);
315
+
287
316
  if (!success) {
288
317
  noError = false;
289
318
  message = isEmpty(message) ? this.getMessage(attribute, rule) : message;
@@ -306,7 +335,13 @@ export default class Validator {
306
335
  if (!(await task())) break;
307
336
  }
308
337
  } else {
309
- await Promise.allSettled(tasks.map((task) => task()));
338
+ await Promise.allSettled(tasks.map((task) => task())).then((results) => {
339
+ for (const result of results) {
340
+ if (result.status === 'rejected') {
341
+ throw result.reason;
342
+ }
343
+ }
344
+ });
310
345
 
311
346
  this.#errors.sortByKeys(Object.keys(this.#rules));
312
347
  }
@@ -331,6 +366,10 @@ export default class Validator {
331
366
  }
332
367
 
333
368
  getMessage(attribute, rule) {
369
+ if (typeof rule === 'function') {
370
+ return '';
371
+ }
372
+
334
373
  const value = this.getValue(attribute);
335
374
  attribute = this.getPrimaryAttribute(attribute);
336
375
 
@@ -387,10 +426,12 @@ export default class Validator {
387
426
  message = message.replaceAll(':index', index).replaceAll(':position', index + 1);
388
427
  }
389
428
 
390
- const camelRule = toCamelCase('replace_' + rule);
429
+ if (typeof rule === 'string') {
430
+ const replacer = this.#replacers[toCamelCase('replace_' + rule)] ?? null;
391
431
 
392
- if (typeof this.#replacers[camelRule] === 'function') {
393
- message = this.#replacers[camelRule](message, attribute, rule, parameters);
432
+ if (replacer) {
433
+ message = replacer.call(this.#replacers, message, attribute, rule, parameters);
434
+ }
394
435
  }
395
436
 
396
437
  return message;
@@ -463,7 +504,7 @@ export default class Validator {
463
504
  }
464
505
 
465
506
  for (const rule of rules) {
466
- if (this.#rules[attribute].hasOwnProperty(rule)) {
507
+ if (this.#rules[attribute].some((attributeRule) => attributeRule[0] === rule)) {
467
508
  return true;
468
509
  }
469
510
  }
@@ -24,6 +24,53 @@ describe('Validation', () => {
24
24
  });
25
25
  });
26
26
 
27
+ describe(`Invalid rule`, () => {
28
+ it(`Fails when the rule is invalid`, async () => {
29
+ const validator = new Validator({ field: 'abc' }, { field: 'foobar' });
30
+
31
+ try {
32
+ await validator.passes();
33
+ assert.fail('Invalid rule should throw an error');
34
+ } catch (error) {
35
+ assert.equal(error.message, 'Invalid validation rule: foobar');
36
+ }
37
+ });
38
+ });
39
+
40
+ describe(`Closure rule`, () => {
41
+ const rules = {
42
+ field: function (attribute, value) {
43
+ return /^[a-z]/i.test(value);
44
+ },
45
+ };
46
+
47
+ it(`Passes when the value starts with a letter`, async () => {
48
+ const validator = new Validator({ field: 'abc' }, rules);
49
+ assert(await validator.passes());
50
+ });
51
+
52
+ it(`Fails when the value does not start with a letter`, async () => {
53
+ const validator = new Validator({ field: 123 }, rules);
54
+ assert(await validator.fails());
55
+ });
56
+
57
+ it(`Passes when the error message is correct`, async () => {
58
+ const validator = new Validator(
59
+ { field: 123 },
60
+ {
61
+ field: function (attribute, value) {
62
+ return {
63
+ success: /^[a-z]/i.test(value),
64
+ message: 'The :attribute must start with a letter.',
65
+ };
66
+ },
67
+ },
68
+ );
69
+
70
+ assert.equal((await validator.validate()).first('field'), 'The field must start with a letter.');
71
+ });
72
+ });
73
+
27
74
  describe(`Rule 'accepted'`, () => {
28
75
  const rules = { field: 'accepted' };
29
76
 
@@ -79,6 +126,34 @@ describe('Validation', () => {
79
126
  const validator = new Validator({ field: true, other: 'bar' }, rules);
80
127
  assert(await validator.passes());
81
128
  });
129
+
130
+ const rules2 = { field: ['accepted_if:other1,foo', 'accepted_if:other2,bar'] };
131
+
132
+ it(`Passes when accepted if other fields' value are equal to provided values`, async () => {
133
+ const validator = new Validator({ field: true, other1: 'foo', other2: 'bar' }, rules2);
134
+ assert(await validator.passes());
135
+ });
136
+
137
+ it(`Fails when declined if other fields' value are equal to provided values`, async () => {
138
+ const validator = new Validator({ field: false, other1: 'foo', other2: 'bar' }, rules2);
139
+ assert(await validator.fails());
140
+ });
141
+
142
+ it(`Passes when accepted if any other fields' value is equal to provided value`, async () => {
143
+ const validator = new Validator({ field: true, other1: 'foo', other2: 'baz' }, rules2);
144
+ assert(await validator.passes());
145
+
146
+ validator.setData({ field: true, other1: 'baz', other2: 'bar' });
147
+ assert(await validator.passes());
148
+ });
149
+
150
+ it(`Fails when declined if any other fields' value is equal to provided value`, async () => {
151
+ const validator = new Validator({ field: false, other1: 'foo', other2: 'baz' }, rules2);
152
+ assert(await validator.fails());
153
+
154
+ validator.setData({ field: false, other1: 'baz', other2: 'bar' });
155
+ assert(await validator.fails());
156
+ });
82
157
  });
83
158
 
84
159
  describe(`Rule 'after'`, () => {
@@ -632,6 +707,34 @@ describe('Validation', () => {
632
707
  const validator = new Validator({ field: true, other: 'bar' }, rules);
633
708
  assert(await validator.passes());
634
709
  });
710
+
711
+ const rules2 = { field: ['declined_if:other1,foo', 'declined_if:other2,bar'] };
712
+
713
+ it(`Passes when declined if other fields' value are equal to provided values`, async () => {
714
+ const validator = new Validator({ field: false, other1: 'foo', other2: 'bar' }, rules2);
715
+ assert(await validator.passes());
716
+ });
717
+
718
+ it(`Fails when accepted if other fields' value are equal to provided values`, async () => {
719
+ const validator = new Validator({ field: true, other1: 'foo', other2: 'bar' }, rules2);
720
+ assert(await validator.fails());
721
+ });
722
+
723
+ it(`Passes when declined if any other fields' value is equal to provided value`, async () => {
724
+ const validator = new Validator({ field: false, other1: 'foo', other2: 'baz' }, rules2);
725
+ assert(await validator.passes());
726
+
727
+ validator.setData({ field: false, other1: 'baz', other2: 'bar' });
728
+ assert(await validator.passes());
729
+ });
730
+
731
+ it(`Fails when accepted if any other fields' value is equal to provided value`, async () => {
732
+ const validator = new Validator({ field: true, other1: 'foo', other2: 'baz' }, rules2);
733
+ assert(await validator.fails());
734
+
735
+ validator.setData({ field: true, other1: 'baz', other2: 'bar' });
736
+ assert(await validator.fails());
737
+ });
635
738
  });
636
739
 
637
740
  describe(`Rule 'different'`, () => {
@@ -805,7 +908,7 @@ describe('Validation', () => {
805
908
  const rules = { field: 'extensions:jpg,png' };
806
909
 
807
910
  it(`Passes when the field has a valid extension`, async () => {
808
- const validator = new Validator({ field: new File('hello.jpg', 5 * 1024, 'image/jpg') }, rules);
911
+ const validator = new Validator({ field: new File('hello.jpg', 5 * 1024, 'image/jpeg') }, rules);
809
912
  assert(await validator.passes());
810
913
 
811
914
  validator.setData({ field: new File('hello.png', 5 * 1024, 'image/png') });
@@ -1183,7 +1286,10 @@ describe('Validation', () => {
1183
1286
  const rules = { field: 'image' };
1184
1287
 
1185
1288
  it(`Passes when the field is an image`, async () => {
1186
- const validator = new Validator({ field: new File('hello.jpg', 5 * 1024, 'image/jpg') }, rules);
1289
+ const validator = new Validator({ field: new File('hello.jpg', 5 * 1024, 'image/jpeg') }, rules);
1290
+ assert(await validator.passes());
1291
+
1292
+ validator.setData({ field: new File('hello.jpeg', 5 * 1024, 'image/jpeg') }, rules);
1187
1293
  assert(await validator.passes());
1188
1294
  });
1189
1295
 
@@ -1748,7 +1854,7 @@ describe('Validation', () => {
1748
1854
  const rules = { field: 'mimes:jpg,png' };
1749
1855
 
1750
1856
  it(`Passes when the field has a valid extension`, async () => {
1751
- const validator = new Validator({ field: new File('hello.jpg', 5 * 1024, 'image/jpg') }, rules);
1857
+ const validator = new Validator({ field: new File('hello.jpg', 5 * 1024, 'image/jpeg') }, rules);
1752
1858
  assert(await validator.passes());
1753
1859
 
1754
1860
  validator.setData({ field: new File('hello.png', 5 * 1024, 'image/png') });
@@ -1762,13 +1868,21 @@ describe('Validation', () => {
1762
1868
  validator.setData({ field: new File('hello.txt', 5 * 1024, 'text/plain') });
1763
1869
  assert(await validator.fails());
1764
1870
  });
1871
+
1872
+ it(`Passes when the rule's parameter for JPEG file is defined as 'jpg' or 'jpeg'`, async () => {
1873
+ const validator = new Validator({ field: new File('hello.jpeg', 5 * 1024, 'image/jpeg') }, { field: 'mimes:jpg' });
1874
+ assert(await validator.passes());
1875
+
1876
+ validator.setProperties({ field: new File('hello.jpg', 5 * 1024, 'image/jpeg') }, { field: 'mimes:jpeg' });
1877
+ assert(await validator.passes());
1878
+ });
1765
1879
  });
1766
1880
 
1767
1881
  describe(`Rule 'mimetypes'`, () => {
1768
- const rules = { field: 'mimetypes:image/jpg,image/png' };
1882
+ const rules = { field: 'mimetypes:image/jpeg,image/png' };
1769
1883
 
1770
1884
  it(`Passes when the field has a valid type`, async () => {
1771
- const validator = new Validator({ field: new File('hello.jpg', 5 * 1024, 'image/jpg') }, rules);
1885
+ const validator = new Validator({ field: new File('hello.jpg', 5 * 1024, 'image/jpeg') }, rules);
1772
1886
  assert(await validator.passes());
1773
1887
 
1774
1888
  validator.setData({ field: new File('hello.png', 5 * 1024, 'image/png') });
@@ -1906,6 +2020,26 @@ describe('Validation', () => {
1906
2020
  const validator = new Validator({ field: '', other: 'bar' }, rules);
1907
2021
  assert(await validator.fails());
1908
2022
  });
2023
+
2024
+ const rules2 = { field: ['missing_if:other1,foo,bar', 'missing_if:other2,win,amp'] };
2025
+
2026
+ it(`Passes when the field is present and other fields' value are not equal to provided values`, async () => {
2027
+ const validator = new Validator({ field: '', other1: 'baz', other2: 'rar' }, rules2);
2028
+ assert(await validator.passes());
2029
+ });
2030
+
2031
+ it(`Fails when the field is present and other fields' value are equal to provided values`, async () => {
2032
+ const validator = new Validator({ field: '', other1: 'foo', other2: 'win' }, rules2);
2033
+ assert(await validator.fails());
2034
+ });
2035
+
2036
+ it(`Fails when the field is present and any other fields' value is equal to provided value`, async () => {
2037
+ const validator = new Validator({ field: '', other1: 'foo', other2: 'rar' }, rules2);
2038
+ assert(await validator.fails());
2039
+
2040
+ validator.setData({ field: '', other1: 'baz', other2: 'win' });
2041
+ assert(await validator.fails());
2042
+ });
1909
2043
  });
1910
2044
 
1911
2045
  describe(`Rule 'missing_unless'`, () => {
@@ -1930,6 +2064,26 @@ describe('Validation', () => {
1930
2064
  const validator = new Validator({ field: '', other: 'bob' }, rules);
1931
2065
  assert(await validator.fails());
1932
2066
  });
2067
+
2068
+ const rules2 = { field: ['missing_unless:other1,foo,bar', 'missing_unless:other2,win,amp'] };
2069
+
2070
+ it(`Passes when the field is present and other fields' value are equal to provided values`, async () => {
2071
+ const validator = new Validator({ field: '', other1: 'foo', other2: 'win' }, rules2);
2072
+ assert(await validator.passes());
2073
+ });
2074
+
2075
+ it(`Fails when the field is present and other fields' value are not equal to provided values`, async () => {
2076
+ const validator = new Validator({ field: '', other1: 'baz', other2: 'rar' }, rules2);
2077
+ assert(await validator.fails());
2078
+ });
2079
+
2080
+ it(`Fails when the field is present and any other fields' value is not equal to provided value`, async () => {
2081
+ const validator = new Validator({ field: '', other1: 'foo', other2: 'rar' }, rules2);
2082
+ assert(await validator.fails());
2083
+
2084
+ validator.setData({ field: '', other1: 'baz', other2: 'win' });
2085
+ assert(await validator.fails());
2086
+ });
1933
2087
  });
1934
2088
 
1935
2089
  describe(`Rule 'missing_with'`, () => {
@@ -2142,6 +2296,26 @@ describe('Validation', () => {
2142
2296
  const validator = new Validator({ field: 'abc', other: 'bar' }, rules);
2143
2297
  assert(await validator.fails());
2144
2298
  });
2299
+
2300
+ const rules2 = { field: ['prohibited_if:other1,foo,bar', 'prohibited_if:other2,win,amp'] };
2301
+
2302
+ it(`Passes when the field is filled and other fields' value are not equal to provided values`, async () => {
2303
+ const validator = new Validator({ field: 'abc', other1: 'baz', other2: 'rar' }, rules2);
2304
+ assert(await validator.passes());
2305
+ });
2306
+
2307
+ it(`Fails when the field is filled and other fields' value are equal to provided values`, async () => {
2308
+ const validator = new Validator({ field: 'abc', other1: 'foo', other2: 'win' }, rules2);
2309
+ assert(await validator.fails());
2310
+ });
2311
+
2312
+ it(`Fails when the field is filled and any other fields' value is equal to provided value`, async () => {
2313
+ const validator = new Validator({ field: 'abc', other1: 'foo', other2: 'rar' }, rules2);
2314
+ assert(await validator.fails());
2315
+
2316
+ validator.setData({ field: 'abc', other1: 'baz', other2: 'win' });
2317
+ assert(await validator.fails());
2318
+ });
2145
2319
  });
2146
2320
 
2147
2321
  describe(`Rule 'prohibited_unless'`, () => {
@@ -2166,6 +2340,26 @@ describe('Validation', () => {
2166
2340
  const validator = new Validator({ field: 'abc', other: 'bob' }, rules);
2167
2341
  assert(await validator.fails());
2168
2342
  });
2343
+
2344
+ const rules2 = { field: ['prohibited_unless:other1,foo,bar', 'prohibited_unless:other2,win,amp'] };
2345
+
2346
+ it(`Passes when the field is filled and other fields' value are equal to provided values`, async () => {
2347
+ const validator = new Validator({ field: 'abc', other1: 'foo', other2: 'win' }, rules2);
2348
+ assert(await validator.passes());
2349
+ });
2350
+
2351
+ it(`Fails when the field is filled and other fields' value are not equal to provided values`, async () => {
2352
+ const validator = new Validator({ field: 'abc', other1: 'baz', other2: 'rar' }, rules2);
2353
+ assert(await validator.fails());
2354
+ });
2355
+
2356
+ it(`Fails when the field is filled and any other fields' value is not equal to provided value`, async () => {
2357
+ const validator = new Validator({ field: 'abc', other1: 'foo', other2: 'rar' }, rules2);
2358
+ assert(await validator.fails());
2359
+
2360
+ validator.setData({ field: 'abc', other1: 'baz', other2: 'win' });
2361
+ assert(await validator.fails());
2362
+ });
2169
2363
  });
2170
2364
 
2171
2365
  describe(`Rule 'prohibits'`, () => {
@@ -2280,6 +2474,26 @@ describe('Validation', () => {
2280
2474
  const validator = new Validator({ field: '', other: 'bar' }, rules);
2281
2475
  assert(await validator.fails());
2282
2476
  });
2477
+
2478
+ const rules2 = { field: ['required_if:other1,foo,bar', 'required_if:other2,win,amp'] };
2479
+
2480
+ it(`Passes when the field is empty and other fields' value are not equal to provided values`, async () => {
2481
+ const validator = new Validator({ field: '', other1: 'baz', other2: 'rar' }, rules2);
2482
+ assert(await validator.passes());
2483
+ });
2484
+
2485
+ it(`Fails when the field is empty and other fields' value are equal to provided values`, async () => {
2486
+ const validator = new Validator({ field: '', other1: 'foo', other2: 'win' }, rules2);
2487
+ assert(await validator.fails());
2488
+ });
2489
+
2490
+ it(`Fails when the field is empty and any other fields' value is equal to provided value`, async () => {
2491
+ const validator = new Validator({ field: '', other1: 'foo', other2: 'rar' }, rules2);
2492
+ assert(await validator.fails());
2493
+
2494
+ validator.setData({ field: '', other1: 'baz', other2: 'win' });
2495
+ assert(await validator.fails());
2496
+ });
2283
2497
  });
2284
2498
 
2285
2499
  describe(`Rule 'required_if_accepted'`, () => {
@@ -2304,6 +2518,26 @@ describe('Validation', () => {
2304
2518
  const validator = new Validator({ field: '', foo: true }, rules);
2305
2519
  assert(await validator.fails());
2306
2520
  });
2521
+
2522
+ const rules2 = { field: ['required_if_accepted:other1', 'required_if_accepted:other2'] };
2523
+
2524
+ it(`Passes when the field is empty and other fields are declined`, async () => {
2525
+ const validator = new Validator({ field: '', other1: false, other2: false }, rules2);
2526
+ assert(await validator.passes());
2527
+ });
2528
+
2529
+ it(`Fails when the field is empty and all fields are accepted`, async () => {
2530
+ const validator = new Validator({ field: '', other1: true, other2: true }, rules2);
2531
+ assert(await validator.fails());
2532
+ });
2533
+
2534
+ it(`Fails when the field is empty and any field is accepted`, async () => {
2535
+ const validator = new Validator({ field: '', other1: true, other2: false }, rules2);
2536
+ assert(await validator.fails());
2537
+
2538
+ validator.setData({ field: '', other1: false, other2: true });
2539
+ assert(await validator.fails());
2540
+ });
2307
2541
  });
2308
2542
 
2309
2543
  describe(`Rule 'required_if_declined'`, () => {
@@ -2328,6 +2562,26 @@ describe('Validation', () => {
2328
2562
  const validator = new Validator({ field: '', foo: false }, rules);
2329
2563
  assert(await validator.fails());
2330
2564
  });
2565
+
2566
+ const rules2 = { field: ['required_if_declined:other1', 'required_if_declined:other2'] };
2567
+
2568
+ it(`Passes when the field is empty and other fields are accepted`, async () => {
2569
+ const validator = new Validator({ field: '', other1: true, other2: true }, rules2);
2570
+ assert(await validator.passes());
2571
+ });
2572
+
2573
+ it(`Fails when the field is empty and all fields are declined`, async () => {
2574
+ const validator = new Validator({ field: '', other1: false, other2: false }, rules2);
2575
+ assert(await validator.fails());
2576
+ });
2577
+
2578
+ it(`Fails when the field is empty and any field is declined`, async () => {
2579
+ const validator = new Validator({ field: '', other1: true, other2: false }, rules2);
2580
+ assert(await validator.fails());
2581
+
2582
+ validator.setData({ field: '', other1: false, other2: true });
2583
+ assert(await validator.fails());
2584
+ });
2331
2585
  });
2332
2586
 
2333
2587
  describe(`Rule 'required_unless'`, () => {
@@ -2352,6 +2606,26 @@ describe('Validation', () => {
2352
2606
  const validator = new Validator({ field: '', other: 'bob' }, rules);
2353
2607
  assert(await validator.fails());
2354
2608
  });
2609
+
2610
+ const rules2 = { field: ['required_unless:other1,foo,bar', 'required_unless:other2,win,amp'] };
2611
+
2612
+ it(`Passes when the field is empty and other fields' value are equal to provided values`, async () => {
2613
+ const validator = new Validator({ field: '', other1: 'foo', other2: 'win' }, rules2);
2614
+ assert(await validator.passes());
2615
+ });
2616
+
2617
+ it(`Fails when the field is empty and other fields' value are not equal to provided values`, async () => {
2618
+ const validator = new Validator({ field: '', other1: 'baz', other2: 'rar' }, rules2);
2619
+ assert(await validator.fails());
2620
+ });
2621
+
2622
+ it(`Fails when the field is empty and any other fields' value is not equal to provided value`, async () => {
2623
+ const validator = new Validator({ field: '', other1: 'foo', other2: 'rar' }, rules2);
2624
+ assert(await validator.fails());
2625
+
2626
+ validator.setData({ field: '', other1: 'baz', other2: 'win' });
2627
+ assert(await validator.fails());
2628
+ });
2355
2629
  });
2356
2630
 
2357
2631
  describe(`Rule 'required_with'`, () => {