quival 0.3.4 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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.4 (https://github.com/apih/quival)
2
+ * quival v0.4.1 (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.4 (https://github.com/apih/quival)
2
+ * quival v0.4.1 (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.4 (https://github.com/apih/quival)
2
+ * quival v0.4.1 (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.4 (https://github.com/apih/quival)
2
+ * quival v0.4.1 (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.4 (https://github.com/apih/quival)
2
+ * quival v0.4.1 (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
  */
@@ -1309,7 +1309,9 @@ var quival = (function (exports) {
1309
1309
  this.#implicitAttributes = {};
1310
1310
  this.#stopOnFirstFailure = false;
1311
1311
  this.#alwaysBail = false;
1312
+ this.arrayRules = ['array', 'list'];
1312
1313
  this.fileRules = ['file', 'image', 'mimetypes', 'mimes'];
1314
+ this.stringRules = ['string', 'alpha', 'alpha_dash', 'alpha_num', 'ascii', 'email'];
1313
1315
  this.numericRules = ['decimal', 'numeric', 'integer'];
1314
1316
  this.sizeRules = ['size', 'between', 'min', 'max', 'gt', 'lt', 'gte', 'lte'];
1315
1317
  this.setProperties(data, rules, messages, attributes, values);
@@ -1368,10 +1370,9 @@ var quival = (function (exports) {
1368
1370
  for (const [attribute, attributeRules] of Object.entries(rules)) {
1369
1371
  const attributes = attribute.includes('*') ? this.parseWildcardAttribute(attribute) : [attribute];
1370
1372
  for (const attribute of attributes) {
1371
- const parsedAttributeRules = {};
1373
+ const parsedAttributeRules = [];
1372
1374
  for (const attributeRule of this.parseAttributeRules(attributeRules)) {
1373
- const [rule, parameters] = this.parseAttributeRule(attributeRule);
1374
- parsedAttributeRules[rule] = parameters;
1375
+ parsedAttributeRules.push(this.parseAttributeRule(attributeRule));
1375
1376
  }
1376
1377
  parsedRules[attribute] = parsedAttributeRules;
1377
1378
  }
@@ -1398,13 +1399,17 @@ var quival = (function (exports) {
1398
1399
  parseAttributeRules(rules) {
1399
1400
  if (Array.isArray(rules)) {
1400
1401
  return rules;
1402
+ } else if (typeof rules === 'function') {
1403
+ return [rules];
1401
1404
  } else {
1402
1405
  return String(rules).split('|');
1403
1406
  }
1404
1407
  }
1405
1408
  parseAttributeRule(rule) {
1406
1409
  if (Array.isArray(rule)) {
1407
- return [rule.shift() ?? '', rule];
1410
+ return [rule[0] ?? '', rule.slice(1)];
1411
+ } else if (typeof rule === 'function') {
1412
+ return [rule, []];
1408
1413
  }
1409
1414
  const index = rule.indexOf(':');
1410
1415
  if (index === -1) {
@@ -1418,39 +1423,61 @@ var quival = (function (exports) {
1418
1423
  this.#errors = new ErrorBag();
1419
1424
  const tasks = [];
1420
1425
  const skippedAttributes = [];
1426
+ for (const [attribute, rules] of Object.entries(this.#rules)) {
1427
+ for (const [rule] of rules) {
1428
+ if (
1429
+ rule === '' ||
1430
+ typeof rule === 'function' ||
1431
+ typeof this.#checkers[toCamelCase('check_' + rule)] === 'function' ||
1432
+ Validator.#dummyRules.includes(rule)
1433
+ )
1434
+ continue;
1435
+ throw new Error(`Invalid validation rule: ${rule}`);
1436
+ }
1437
+ }
1421
1438
  for (const [attribute, rules] of Object.entries(this.#rules)) {
1422
1439
  let value = this.getValue(attribute);
1423
- if (Object.hasOwn(rules, 'sometimes') && typeof value === 'undefined') {
1440
+ const hasRule = (ruleName) => rules.some((rule) => rule[0] === ruleName);
1441
+ if (hasRule('sometimes') && typeof value === 'undefined') {
1424
1442
  skippedAttributes.push(attribute);
1425
1443
  continue;
1426
1444
  }
1427
1445
  tasks.push(async () => {
1428
- const doBail = this.#alwaysBail || Object.hasOwn(rules, 'bail');
1429
- const isNullable = Object.hasOwn(rules, 'nullable');
1446
+ const doBail = this.#alwaysBail || hasRule('bail');
1447
+ const isNullable = hasRule('nullable');
1430
1448
  let noError = true;
1431
- for (const [rule, parameters] of Object.entries(rules)) {
1449
+ for (const [rule, parameters] of rules) {
1432
1450
  if (
1433
1451
  rule === '' ||
1434
- (!Validator.#implicitRules.includes(rule) &&
1452
+ (typeof rule !== 'function' &&
1453
+ !Validator.#implicitRules.includes(rule) &&
1435
1454
  (typeof value === 'undefined' || (typeof value === 'string' && value.trim() === '') || (isNullable && value === null)))
1436
1455
  ) {
1437
1456
  skippedAttributes.push(attribute);
1438
1457
  continue;
1439
1458
  }
1440
1459
  let result, success, message;
1441
- const camelRule = toCamelCase('check_' + rule);
1442
- if (typeof this.#checkers[camelRule] === 'function') {
1443
- result = await this.#checkers[camelRule](attribute, value, parameters);
1444
- } else if (Validator.#dummyRules.includes(rule)) {
1445
- result = true;
1446
- } else {
1460
+ const checker = (() => {
1461
+ if (typeof rule === 'function') {
1462
+ return rule;
1463
+ } else {
1464
+ const checker = this.#checkers[toCamelCase('check_' + rule)] ?? null;
1465
+ if (checker === null && Validator.#dummyRules.includes(rule)) {
1466
+ return () => true;
1467
+ }
1468
+ return checker;
1469
+ }
1470
+ })();
1471
+ if (checker === null) {
1447
1472
  throw new Error(`Invalid validation rule: ${rule}`);
1448
1473
  }
1474
+ result = await checker.call(this.#checkers, attribute, value, parameters);
1449
1475
  if (typeof result === 'boolean') {
1450
- success = result;
1451
- } else {
1452
- ({ success, message } = result);
1476
+ result = {
1477
+ success: result,
1478
+ };
1453
1479
  }
1480
+ ({ success, message = '' } = result);
1454
1481
  if (!success) {
1455
1482
  noError = false;
1456
1483
  message = isEmpty(message) ? this.getMessage(attribute, rule) : message;
@@ -1469,7 +1496,13 @@ var quival = (function (exports) {
1469
1496
  if (!(await task())) break;
1470
1497
  }
1471
1498
  } else {
1472
- await Promise.allSettled(tasks.map((task) => task()));
1499
+ await Promise.allSettled(tasks.map((task) => task())).then((results) => {
1500
+ for (const result of results) {
1501
+ if (result.status === 'rejected') {
1502
+ throw result.reason;
1503
+ }
1504
+ }
1505
+ });
1473
1506
  this.#errors.sortByKeys(Object.keys(this.#rules));
1474
1507
  }
1475
1508
  this.#skippedAttributes = skippedAttributes.filter((value, index, array) => array.indexOf(value) === index);
@@ -1486,6 +1519,9 @@ var quival = (function (exports) {
1486
1519
  return !(await this.passes());
1487
1520
  }
1488
1521
  getMessage(attribute, rule) {
1522
+ if (typeof rule === 'function') {
1523
+ return '';
1524
+ }
1489
1525
  const value = this.getValue(attribute);
1490
1526
  attribute = this.getPrimaryAttribute(attribute);
1491
1527
  let message;
@@ -1498,10 +1534,12 @@ var quival = (function (exports) {
1498
1534
  if (!message) {
1499
1535
  let key = rule;
1500
1536
  if (this.sizeRules.includes(key)) {
1501
- if (Array.isArray(value) || isPlainObject(value) || this.hasRule(attribute, 'array')) {
1537
+ if (Array.isArray(value) || isPlainObject(value) || this.hasRule(attribute, this.arrayRules)) {
1502
1538
  key += '.array';
1503
1539
  } else if (value instanceof File || this.hasRule(attribute, this.fileRules)) {
1504
1540
  key += '.file';
1541
+ } else if (this.hasRule(attribute, this.stringRules)) {
1542
+ key += '.string';
1505
1543
  } else if (isNumeric(value) || this.hasRule(attribute, this.numericRules)) {
1506
1544
  key += '.numeric';
1507
1545
  } else {
@@ -1529,9 +1567,11 @@ var quival = (function (exports) {
1529
1567
  if (index !== -1) {
1530
1568
  message = message.replaceAll(':index', index).replaceAll(':position', index + 1);
1531
1569
  }
1532
- const camelRule = toCamelCase('replace_' + rule);
1533
- if (typeof this.#replacers[camelRule] === 'function') {
1534
- message = this.#replacers[camelRule](message, attribute, rule, parameters);
1570
+ if (typeof rule === 'string') {
1571
+ const replacer = this.#replacers[toCamelCase('replace_' + rule)] ?? null;
1572
+ if (replacer) {
1573
+ message = replacer.call(this.#replacers, message, attribute, rule, parameters);
1574
+ }
1535
1575
  }
1536
1576
  return message;
1537
1577
  }
@@ -1566,6 +1606,8 @@ var quival = (function (exports) {
1566
1606
  getSize(attribute, value) {
1567
1607
  if (isEmpty(value)) {
1568
1608
  return 0;
1609
+ } else if (this.hasRule(attribute, this.stringRules)) {
1610
+ return String(value).length;
1569
1611
  } else if (isNumeric(value) && this.hasRule(attribute, this.numericRules)) {
1570
1612
  return parseFloat(typeof value === 'string' ? value.trim() : value, 10);
1571
1613
  } else if (value instanceof File) {
@@ -1588,7 +1630,7 @@ var quival = (function (exports) {
1588
1630
  return false;
1589
1631
  }
1590
1632
  for (const rule of rules) {
1591
- if (this.#rules[attribute].hasOwnProperty(rule)) {
1633
+ if (this.#rules[attribute].some((attributeRule) => attributeRule[0] === rule)) {
1592
1634
  return true;
1593
1635
  }
1594
1636
  }
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * quival v0.3.4 (https://github.com/apih/quival)
2
+ * quival v0.4.1 (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("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){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],p=a[i.hours]??0,d=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()&&p<12&&(p+=12),new Date(`${l}-${h}-${o} ${p}:${d}:${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 p=`"${r(c.substring(a)).replaceAll("\\*",'[^."]+')}":`,d=0;return p+=h?"string"==typeof t?`"${o}"`:`${o}`:`(${o}|"${o}")`,p+="[,}]+",d+=u.match(new RegExp(p,"g"+(l?"i":"")))?.length??0,1===d}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 p{#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 d{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;#p;#d;#f;#g;#m;#k;#b;#y;static setLocale(e){d.locale(e)}static setMessages(e,t){d.setMessages(e,t)}static addChecker(e,t,r){g.#c[e]=t,r&&d.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.#y=!1,this.arrayRules=["array","list"],this.fileRules=["file","image","mimetypes","mimes"],this.stringRules=["string","alpha","alpha_dash","alpha_num","ascii","email"],this.numericRules=["decimal","numeric","integer"],this.sizeRules=["size","between","min","max","gt","lt","gte","lte"],this.setProperties(e,r,s,i,c),this.#d=new o(this),this.#f=new f(this);for(const[e,r]of Object.entries(g.#c))this.#d[t("check_"+e)]=r;for(const[e,r]of Object.entries(g.#a))this.#f[t("replace_"+e)]=r;this.#g=new p}setProperties(e={},t={},r={},i={},c={}){return this.#r=e,this.#l=this.parseRules(t),this.#h=r,this.#o=i,this.#p=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.#p=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.#y=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.#d.clearCaches(),this.#g=new p;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.#d[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.#y||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,p;const d=(()=>{if("function"==typeof a)return a;{const e=this.#d[t("check_"+a)]??null;return null===e&&g.#n.includes(a)?()=>!0:e}})();if(null===d)throw new Error(`Invalid validation rule: ${a}`);if(i=await d.call(this.#d,s,c,h),"boolean"==typeof i&&(i={success:i}),({success:o,message:p=""}=i),!o&&(l=!1,p=n(p)?this.getMessage(s,a):p,p=this.makeReplacements(p,s,a,h),this.#g.add(s,p),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,this.arrayRules)?i+=".array":r instanceof File||this.hasRule(e,this.fileRules)?i+=".file":this.hasRule(e,this.stringRules)?i+=".string":u(r)||this.hasRule(e,this.numericRules)?i+=".numeric":i+=".string"),s=d.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(d.has(`attributes.${r}`))return d.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.#p,r)?this.#p[r]:d.has(`values.${r}`)?d.get(`values.${r}`):t}getSize(e,t){return n(t)?0:this.hasRule(e,this.stringRules)?String(t).length: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=p,e.Lang=d,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.4",
3
+ "version": "0.4.1",
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/Validator.js CHANGED
@@ -63,7 +63,9 @@ export default class Validator {
63
63
  #stopOnFirstFailure = false;
64
64
  #alwaysBail = false;
65
65
 
66
+ arrayRules = ['array', 'list'];
66
67
  fileRules = ['file', 'image', 'mimetypes', 'mimes'];
68
+ stringRules = ['string', 'alpha', 'alpha_dash', 'alpha_num', 'ascii', 'email'];
67
69
  numericRules = ['decimal', 'numeric', 'integer'];
68
70
  sizeRules = ['size', 'between', 'min', 'max', 'gt', 'lt', 'gte', 'lte'];
69
71
 
@@ -178,12 +180,10 @@ export default class Validator {
178
180
  const attributes = attribute.includes('*') ? this.parseWildcardAttribute(attribute) : [attribute];
179
181
 
180
182
  for (const attribute of attributes) {
181
- const parsedAttributeRules = {};
183
+ const parsedAttributeRules = [];
182
184
 
183
185
  for (const attributeRule of this.parseAttributeRules(attributeRules)) {
184
- const [rule, parameters] = this.parseAttributeRule(attributeRule);
185
-
186
- parsedAttributeRules[rule] = parameters;
186
+ parsedAttributeRules.push(this.parseAttributeRule(attributeRule));
187
187
  }
188
188
 
189
189
  parsedRules[attribute] = parsedAttributeRules;
@@ -218,6 +218,8 @@ export default class Validator {
218
218
  parseAttributeRules(rules) {
219
219
  if (Array.isArray(rules)) {
220
220
  return rules;
221
+ } else if (typeof rules === 'function') {
222
+ return [rules];
221
223
  } else {
222
224
  return String(rules).split('|');
223
225
  }
@@ -225,7 +227,9 @@ export default class Validator {
225
227
 
226
228
  parseAttributeRule(rule) {
227
229
  if (Array.isArray(rule)) {
228
- return [rule.shift() ?? '', rule];
230
+ return [rule[0] ?? '', rule.slice(1)];
231
+ } else if (typeof rule === 'function') {
232
+ return [rule, []];
229
233
  }
230
234
 
231
235
  const index = rule.indexOf(':');
@@ -244,23 +248,39 @@ export default class Validator {
244
248
  const tasks = [];
245
249
  const skippedAttributes = [];
246
250
 
251
+ for (const [attribute, rules] of Object.entries(this.#rules)) {
252
+ for (const [rule] of rules) {
253
+ if (
254
+ rule === '' ||
255
+ typeof rule === 'function' ||
256
+ typeof this.#checkers[toCamelCase('check_' + rule)] === 'function' ||
257
+ Validator.#dummyRules.includes(rule)
258
+ )
259
+ continue;
260
+
261
+ throw new Error(`Invalid validation rule: ${rule}`);
262
+ }
263
+ }
264
+
247
265
  for (const [attribute, rules] of Object.entries(this.#rules)) {
248
266
  let value = this.getValue(attribute);
267
+ const hasRule = (ruleName) => rules.some((rule) => rule[0] === ruleName);
249
268
 
250
- if (Object.hasOwn(rules, 'sometimes') && typeof value === 'undefined') {
269
+ if (hasRule('sometimes') && typeof value === 'undefined') {
251
270
  skippedAttributes.push(attribute);
252
271
  continue;
253
272
  }
254
273
 
255
274
  tasks.push(async () => {
256
- const doBail = this.#alwaysBail || Object.hasOwn(rules, 'bail');
257
- const isNullable = Object.hasOwn(rules, 'nullable');
275
+ const doBail = this.#alwaysBail || hasRule('bail');
276
+ const isNullable = hasRule('nullable');
258
277
  let noError = true;
259
278
 
260
- for (const [rule, parameters] of Object.entries(rules)) {
279
+ for (const [rule, parameters] of rules) {
261
280
  if (
262
281
  rule === '' ||
263
- (!Validator.#implicitRules.includes(rule) &&
282
+ (typeof rule !== 'function' &&
283
+ !Validator.#implicitRules.includes(rule) &&
264
284
  (typeof value === 'undefined' || (typeof value === 'string' && value.trim() === '') || (isNullable && value === null)))
265
285
  ) {
266
286
  skippedAttributes.push(attribute);
@@ -268,22 +288,33 @@ export default class Validator {
268
288
  }
269
289
 
270
290
  let result, success, message;
271
- const camelRule = toCamelCase('check_' + rule);
272
291
 
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 {
292
+ const checker = (() => {
293
+ if (typeof rule === 'function') {
294
+ return rule;
295
+ } else {
296
+ const checker = this.#checkers[toCamelCase('check_' + rule)] ?? null;
297
+
298
+ if (checker === null && Validator.#dummyRules.includes(rule)) {
299
+ return () => true;
300
+ }
301
+
302
+ return checker;
303
+ }
304
+ })();
305
+
306
+ if (checker === null) {
278
307
  throw new Error(`Invalid validation rule: ${rule}`);
279
308
  }
280
309
 
310
+ result = await checker.call(this.#checkers, attribute, value, parameters);
311
+
281
312
  if (typeof result === 'boolean') {
282
- success = result;
283
- } else {
284
- ({ success, message } = result);
313
+ result = { success: result };
285
314
  }
286
315
 
316
+ ({ success, message = '' } = result);
317
+
287
318
  if (!success) {
288
319
  noError = false;
289
320
  message = isEmpty(message) ? this.getMessage(attribute, rule) : message;
@@ -306,7 +337,13 @@ export default class Validator {
306
337
  if (!(await task())) break;
307
338
  }
308
339
  } else {
309
- await Promise.allSettled(tasks.map((task) => task()));
340
+ await Promise.allSettled(tasks.map((task) => task())).then((results) => {
341
+ for (const result of results) {
342
+ if (result.status === 'rejected') {
343
+ throw result.reason;
344
+ }
345
+ }
346
+ });
310
347
 
311
348
  this.#errors.sortByKeys(Object.keys(this.#rules));
312
349
  }
@@ -331,6 +368,10 @@ export default class Validator {
331
368
  }
332
369
 
333
370
  getMessage(attribute, rule) {
371
+ if (typeof rule === 'function') {
372
+ return '';
373
+ }
374
+
334
375
  const value = this.getValue(attribute);
335
376
  attribute = this.getPrimaryAttribute(attribute);
336
377
 
@@ -348,10 +389,12 @@ export default class Validator {
348
389
  let key = rule;
349
390
 
350
391
  if (this.sizeRules.includes(key)) {
351
- if (Array.isArray(value) || isPlainObject(value) || this.hasRule(attribute, 'array')) {
392
+ if (Array.isArray(value) || isPlainObject(value) || this.hasRule(attribute, this.arrayRules)) {
352
393
  key += '.array';
353
394
  } else if (value instanceof File || this.hasRule(attribute, this.fileRules)) {
354
395
  key += '.file';
396
+ } else if (this.hasRule(attribute, this.stringRules)) {
397
+ key += '.string';
355
398
  } else if (isNumeric(value) || this.hasRule(attribute, this.numericRules)) {
356
399
  key += '.numeric';
357
400
  } else {
@@ -387,10 +430,12 @@ export default class Validator {
387
430
  message = message.replaceAll(':index', index).replaceAll(':position', index + 1);
388
431
  }
389
432
 
390
- const camelRule = toCamelCase('replace_' + rule);
433
+ if (typeof rule === 'string') {
434
+ const replacer = this.#replacers[toCamelCase('replace_' + rule)] ?? null;
391
435
 
392
- if (typeof this.#replacers[camelRule] === 'function') {
393
- message = this.#replacers[camelRule](message, attribute, rule, parameters);
436
+ if (replacer) {
437
+ message = replacer.call(this.#replacers, message, attribute, rule, parameters);
438
+ }
394
439
  }
395
440
 
396
441
  return message;
@@ -435,6 +480,8 @@ export default class Validator {
435
480
  getSize(attribute, value) {
436
481
  if (isEmpty(value)) {
437
482
  return 0;
483
+ } else if (this.hasRule(attribute, this.stringRules)) {
484
+ return String(value).length;
438
485
  } else if (isNumeric(value) && this.hasRule(attribute, this.numericRules)) {
439
486
  return parseFloat(typeof value === 'string' ? value.trim() : value, 10);
440
487
  } else if (value instanceof File) {
@@ -463,7 +510,7 @@ export default class Validator {
463
510
  }
464
511
 
465
512
  for (const rule of rules) {
466
- if (this.#rules[attribute].hasOwnProperty(rule)) {
513
+ if (this.#rules[attribute].some((attributeRule) => attributeRule[0] === rule)) {
467
514
  return true;
468
515
  }
469
516
  }
@@ -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'`, () => {
@@ -1917,6 +2020,26 @@ describe('Validation', () => {
1917
2020
  const validator = new Validator({ field: '', other: 'bar' }, rules);
1918
2021
  assert(await validator.fails());
1919
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
+ });
1920
2043
  });
1921
2044
 
1922
2045
  describe(`Rule 'missing_unless'`, () => {
@@ -1941,6 +2064,26 @@ describe('Validation', () => {
1941
2064
  const validator = new Validator({ field: '', other: 'bob' }, rules);
1942
2065
  assert(await validator.fails());
1943
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
+ });
1944
2087
  });
1945
2088
 
1946
2089
  describe(`Rule 'missing_with'`, () => {
@@ -2153,6 +2296,26 @@ describe('Validation', () => {
2153
2296
  const validator = new Validator({ field: 'abc', other: 'bar' }, rules);
2154
2297
  assert(await validator.fails());
2155
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
+ });
2156
2319
  });
2157
2320
 
2158
2321
  describe(`Rule 'prohibited_unless'`, () => {
@@ -2177,6 +2340,26 @@ describe('Validation', () => {
2177
2340
  const validator = new Validator({ field: 'abc', other: 'bob' }, rules);
2178
2341
  assert(await validator.fails());
2179
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
+ });
2180
2363
  });
2181
2364
 
2182
2365
  describe(`Rule 'prohibits'`, () => {
@@ -2291,6 +2474,26 @@ describe('Validation', () => {
2291
2474
  const validator = new Validator({ field: '', other: 'bar' }, rules);
2292
2475
  assert(await validator.fails());
2293
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
+ });
2294
2497
  });
2295
2498
 
2296
2499
  describe(`Rule 'required_if_accepted'`, () => {
@@ -2315,6 +2518,26 @@ describe('Validation', () => {
2315
2518
  const validator = new Validator({ field: '', foo: true }, rules);
2316
2519
  assert(await validator.fails());
2317
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
+ });
2318
2541
  });
2319
2542
 
2320
2543
  describe(`Rule 'required_if_declined'`, () => {
@@ -2339,6 +2562,26 @@ describe('Validation', () => {
2339
2562
  const validator = new Validator({ field: '', foo: false }, rules);
2340
2563
  assert(await validator.fails());
2341
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
+ });
2342
2585
  });
2343
2586
 
2344
2587
  describe(`Rule 'required_unless'`, () => {
@@ -2363,6 +2606,26 @@ describe('Validation', () => {
2363
2606
  const validator = new Validator({ field: '', other: 'bob' }, rules);
2364
2607
  assert(await validator.fails());
2365
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
+ });
2366
2629
  });
2367
2630
 
2368
2631
  describe(`Rule 'required_with'`, () => {