z-schema 12.2.0 → 12.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.
Files changed (111) hide show
  1. package/README.md +2 -2
  2. package/bin/z-schema +1 -1
  3. package/cjs/{index.js → index.cjs} +838 -707
  4. package/cjs/{index.d.ts → index.d.cts} +47 -26
  5. package/dist/{errors.d.mts → errors.d.ts} +2 -2
  6. package/dist/{errors.mjs → errors.js} +1 -2
  7. package/dist/{format-validators.mjs → format-validators.js} +60 -43
  8. package/dist/{index.d.mts → index.d.ts} +9 -9
  9. package/dist/{index.mjs → index.js} +3 -3
  10. package/dist/{json-schema-versions.d.mts → json-schema-versions.d.ts} +34 -3
  11. package/dist/{json-schema.d.mts → json-schema.d.ts} +7 -7
  12. package/dist/{json-schema.mjs → json-schema.js} +6 -5
  13. package/dist/{json-validation.mjs → json-validation.js} +144 -127
  14. package/dist/{report.d.mts → report.d.ts} +8 -9
  15. package/dist/{report.mjs → report.js} +28 -31
  16. package/dist/{schema-cache.d.mts → schema-cache.d.ts} +5 -5
  17. package/dist/{schema-cache.mjs → schema-cache.js} +10 -11
  18. package/dist/{schema-compiler.d.mts → schema-compiler.d.ts} +4 -4
  19. package/dist/{schema-compiler.mjs → schema-compiler.js} +101 -79
  20. package/dist/{schema-validator.d.mts → schema-validator.d.ts} +5 -5
  21. package/dist/{schema-validator.mjs → schema-validator.js} +138 -166
  22. package/dist/utils/{array.mjs → array.js} +4 -3
  23. package/dist/utils/{base64.mjs → base64.js} +3 -2
  24. package/dist/utils/{clone.mjs → clone.js} +18 -20
  25. package/dist/utils/hostname.js +176 -0
  26. package/dist/utils/{json.mjs → json.js} +13 -8
  27. package/dist/utils/{schema-regex.mjs → schema-regex.js} +5 -5
  28. package/dist/utils/{time.mjs → time.js} +8 -8
  29. package/dist/utils/unicode.js +22 -0
  30. package/dist/utils/{what-is.mjs → what-is.js} +1 -2
  31. package/dist/validation/{array.mjs → array.js} +18 -20
  32. package/dist/validation/{combinators.mjs → combinators.js} +16 -16
  33. package/dist/validation/{numeric.mjs → numeric.js} +11 -11
  34. package/dist/validation/{object.mjs → object.js} +35 -34
  35. package/dist/validation/{ref.mjs → ref.js} +5 -5
  36. package/dist/validation/{shared.mjs → shared.js} +15 -12
  37. package/dist/validation/{string.mjs → string.js} +35 -35
  38. package/dist/validation/type.js +34 -0
  39. package/dist/{z-schema-base.d.mts → z-schema-base.d.ts} +11 -12
  40. package/dist/{z-schema-base.mjs → z-schema-base.js} +45 -40
  41. package/dist/{z-schema-options.d.mts → z-schema-options.d.ts} +3 -3
  42. package/dist/{z-schema-options.mjs → z-schema-options.js} +5 -5
  43. package/dist/{z-schema-reader.d.mts → z-schema-reader.d.ts} +1 -1
  44. package/dist/{z-schema-versions.mjs → z-schema-versions.js} +21 -21
  45. package/dist/{z-schema.d.mts → z-schema.d.ts} +5 -13
  46. package/dist/{z-schema.mjs → z-schema.js} +38 -48
  47. package/package.json +24 -25
  48. package/src/errors.ts +1 -2
  49. package/src/format-validators.ts +173 -67
  50. package/src/json-schema-versions.ts +56 -2
  51. package/src/json-schema.ts +10 -9
  52. package/src/json-validation.ts +189 -146
  53. package/src/report.ts +37 -49
  54. package/src/schema-cache.ts +13 -13
  55. package/src/schema-compiler.ts +170 -117
  56. package/src/schema-validator.ts +239 -238
  57. package/src/utils/array.ts +9 -6
  58. package/src/utils/base64.ts +13 -2
  59. package/src/utils/clone.ts +28 -30
  60. package/src/utils/date.ts +6 -3
  61. package/src/utils/hostname.ts +257 -31
  62. package/src/utils/json.ts +16 -9
  63. package/src/utils/properties.ts +2 -2
  64. package/src/utils/schema-regex.ts +4 -4
  65. package/src/utils/time.ts +8 -7
  66. package/src/utils/unicode.ts +12 -5
  67. package/src/utils/what-is.ts +1 -5
  68. package/src/validation/array.ts +24 -22
  69. package/src/validation/combinators.ts +14 -14
  70. package/src/validation/numeric.ts +14 -28
  71. package/src/validation/object.ts +32 -36
  72. package/src/validation/ref.ts +5 -6
  73. package/src/validation/shared.ts +22 -21
  74. package/src/validation/string.ts +36 -42
  75. package/src/validation/type.ts +17 -17
  76. package/src/z-schema-base.ts +49 -38
  77. package/src/z-schema-options.ts +4 -3
  78. package/src/z-schema.ts +35 -45
  79. package/umd/ZSchema.js +853 -715
  80. package/umd/ZSchema.min.js +2 -2
  81. package/umd/package.json +3 -0
  82. package/dist/utils/hostname.mjs +0 -75
  83. package/dist/utils/unicode.mjs +0 -12
  84. package/dist/validation/type.mjs +0 -32
  85. /package/dist/{format-validators.d.mts → format-validators.d.ts} +0 -0
  86. /package/dist/{json-schema-versions.mjs → json-schema-versions.js} +0 -0
  87. /package/dist/schemas/{draft-04-schema.mjs → draft-04-schema.js} +0 -0
  88. /package/dist/schemas/{draft-06-schema.mjs → draft-06-schema.js} +0 -0
  89. /package/dist/schemas/{draft-07-schema.mjs → draft-07-schema.js} +0 -0
  90. /package/dist/schemas/{draft-2019-09-meta-applicator.mjs → draft-2019-09-meta-applicator.js} +0 -0
  91. /package/dist/schemas/{draft-2019-09-meta-content.mjs → draft-2019-09-meta-content.js} +0 -0
  92. /package/dist/schemas/{draft-2019-09-meta-core.mjs → draft-2019-09-meta-core.js} +0 -0
  93. /package/dist/schemas/{draft-2019-09-meta-format.mjs → draft-2019-09-meta-format.js} +0 -0
  94. /package/dist/schemas/{draft-2019-09-meta-meta-data.mjs → draft-2019-09-meta-meta-data.js} +0 -0
  95. /package/dist/schemas/{draft-2019-09-meta-validation.mjs → draft-2019-09-meta-validation.js} +0 -0
  96. /package/dist/schemas/{draft-2019-09-schema.mjs → draft-2019-09-schema.js} +0 -0
  97. /package/dist/schemas/{draft-2020-12-meta-applicator.mjs → draft-2020-12-meta-applicator.js} +0 -0
  98. /package/dist/schemas/{draft-2020-12-meta-content.mjs → draft-2020-12-meta-content.js} +0 -0
  99. /package/dist/schemas/{draft-2020-12-meta-core.mjs → draft-2020-12-meta-core.js} +0 -0
  100. /package/dist/schemas/{draft-2020-12-meta-format-annotation.mjs → draft-2020-12-meta-format-annotation.js} +0 -0
  101. /package/dist/schemas/{draft-2020-12-meta-format-assertion.mjs → draft-2020-12-meta-format-assertion.js} +0 -0
  102. /package/dist/schemas/{draft-2020-12-meta-meta-data.mjs → draft-2020-12-meta-meta-data.js} +0 -0
  103. /package/dist/schemas/{draft-2020-12-meta-unevaluated.mjs → draft-2020-12-meta-unevaluated.js} +0 -0
  104. /package/dist/schemas/{draft-2020-12-meta-validation.mjs → draft-2020-12-meta-validation.js} +0 -0
  105. /package/dist/schemas/{draft-2020-12-schema.mjs → draft-2020-12-schema.js} +0 -0
  106. /package/dist/utils/{constants.mjs → constants.js} +0 -0
  107. /package/dist/utils/{date.mjs → date.js} +0 -0
  108. /package/dist/utils/{properties.mjs → properties.js} +0 -0
  109. /package/dist/utils/{symbols.mjs → symbols.js} +0 -0
  110. /package/dist/utils/{uri.mjs → uri.js} +0 -0
  111. /package/dist/{z-schema-reader.mjs → z-schema-reader.js} +0 -0
@@ -0,0 +1,176 @@
1
+ import isIPModule from "validator/lib/isIP.js";
2
+ import punycode from "punycode/punycode.js";
3
+ //#region src/utils/hostname.ts
4
+ const IDN_SEPARATOR_REGEX = /[\u3002\uFF0E\uFF61]/g;
5
+ const IDN_SEPARATOR_TEST_REGEX = /[\u3002\uFF0E\uFF61]/;
6
+ const XN_LABEL_REGEX = /^xn--/i;
7
+ const DISALLOWED_CATEGORY_REGEX = /[\p{P}\p{S}\p{Z}\p{C}]/u;
8
+ const DISALLOWED_CATEGORY_WHITELIST = /* @__PURE__ */ new Set([
9
+ "-",
10
+ "·",
11
+ "͵",
12
+ "׳",
13
+ "״",
14
+ "・",
15
+ "۽",
16
+ "۾",
17
+ "་",
18
+ "‌",
19
+ "‍"
20
+ ]);
21
+ const isDisallowedCodePoint = (char) => DISALLOWED_CATEGORY_REGEX.test(char) && !DISALLOWED_CATEGORY_WHITELIST.has(char);
22
+ const TRANSPARENT_MARK_REGEX = /\p{Mn}/u;
23
+ const ARABIC_SCRIPT_REGEX = /\p{Script=Arabic}/u;
24
+ const ARABIC_INDIC_DIGITS_REGEX = /[\u0660-\u0669\u06F0-\u06F9]/;
25
+ const isArabicJoiningLetter = (char) => char !== void 0 && ARABIC_SCRIPT_REGEX.test(char) && !ARABIC_INDIC_DIGITS_REGEX.test(char);
26
+ const hasZwnjJoiningContext = (label, idx) => {
27
+ let before = idx - 1;
28
+ while (before >= 0 && TRANSPARENT_MARK_REGEX.test(label[before])) before--;
29
+ let after = idx + 1;
30
+ while (after < label.length && TRANSPARENT_MARK_REGEX.test(label[after])) after++;
31
+ return isArabicJoiningLetter(label[before]) && isArabicJoiningLetter(label[after]);
32
+ };
33
+ const BIDI_NSM_REGEX = /[\p{Mn}\p{Me}]/u;
34
+ const BIDI_ARABIC_INDIC_DIGIT_REGEX = /[\u0660-\u0669]/;
35
+ const BIDI_EXTENDED_ARABIC_INDIC_DIGIT_REGEX = /[\u06F0-\u06F9]/;
36
+ const BIDI_HEBREW_SCRIPT_REGEX = /\p{Script=Hebrew}/u;
37
+ const BIDI_AL_SCRIPT_REGEX = /[\p{Script=Arabic}\p{Script=Syriac}\p{Script=Thaana}]/u;
38
+ const BIDI_ASCII_DIGIT_REGEX = /[0-9]/;
39
+ const BIDI_LETTER_REGEX = /\p{L}/u;
40
+ const classifyBidi = (char) => {
41
+ if (BIDI_NSM_REGEX.test(char)) return "NSM";
42
+ if (BIDI_ARABIC_INDIC_DIGIT_REGEX.test(char)) return "AN";
43
+ if (BIDI_EXTENDED_ARABIC_INDIC_DIGIT_REGEX.test(char)) return "EN";
44
+ if (BIDI_HEBREW_SCRIPT_REGEX.test(char)) return "R";
45
+ if (BIDI_AL_SCRIPT_REGEX.test(char)) return "AL";
46
+ if (BIDI_ASCII_DIGIT_REGEX.test(char)) return "EN";
47
+ if (BIDI_LETTER_REGEX.test(char)) return "L";
48
+ return "ON";
49
+ };
50
+ const isLabelBidiTriggering = (label) => {
51
+ for (const char of label) {
52
+ const bidiClass = classifyBidi(char);
53
+ if (bidiClass === "R" || bidiClass === "AL" || bidiClass === "AN") return true;
54
+ }
55
+ return false;
56
+ };
57
+ const isLabelBidiRuleValid = (label) => {
58
+ const classes = [];
59
+ for (const char of label) classes.push(classifyBidi(char));
60
+ if (classes.length === 0) return false;
61
+ const first = classes[0];
62
+ if (first !== "L" && first !== "R" && first !== "AL") return false;
63
+ let lastIdx = classes.length - 1;
64
+ while (lastIdx > 0 && classes[lastIdx] === "NSM") lastIdx--;
65
+ const last = classes[lastIdx];
66
+ if (first === "R" || first === "AL") {
67
+ let hasEN = false;
68
+ let hasAN = false;
69
+ for (let i = 0; i < classes.length; i++) {
70
+ const c = classes[i];
71
+ if (c !== "R" && c !== "AL" && c !== "AN" && c !== "EN" && c !== "NSM" && c !== "ON") return false;
72
+ if (c === "EN") hasEN = true;
73
+ else if (c === "AN") hasAN = true;
74
+ }
75
+ if (hasEN && hasAN) return false;
76
+ return last === "R" || last === "AL" || last === "EN" || last === "AN";
77
+ }
78
+ for (let i = 0; i < classes.length; i++) {
79
+ const c = classes[i];
80
+ if (c !== "L" && c !== "EN" && c !== "NSM" && c !== "ON") return false;
81
+ }
82
+ return last === "L" || last === "EN";
83
+ };
84
+ const isDomainBidiValid = (unicodeLabels) => {
85
+ let isBidiDomain = false;
86
+ for (let i = 0; i < unicodeLabels.length; i++) if (isLabelBidiTriggering(unicodeLabels[i])) {
87
+ isBidiDomain = true;
88
+ break;
89
+ }
90
+ if (!isBidiDomain) return true;
91
+ for (let i = 0; i < unicodeLabels.length; i++) if (!isLabelBidiRuleValid(unicodeLabels[i])) return false;
92
+ return true;
93
+ };
94
+ const splitHostnameLabels = (hostname) => {
95
+ if (hostname.length === 0 || hostname.length > 255) return null;
96
+ if (hostname.startsWith(".") || hostname.endsWith(".")) return null;
97
+ const labels = hostname.split(".");
98
+ for (let i = 0; i < labels.length; i++) {
99
+ const len = labels[i].length;
100
+ if (len === 0 || len > 63) return null;
101
+ }
102
+ return labels;
103
+ };
104
+ const isAsciiHostnameLabel = (label) => /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(label);
105
+ const isGreek = (char) => /\p{Script=Greek}/u.test(char);
106
+ const isHebrew = (char) => /\p{Script=Hebrew}/u.test(char);
107
+ const hasCjkKanaOrHan = (input) => /[\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Han}]/u.test(input);
108
+ const toUnicodeLabel = (label) => {
109
+ if (!XN_LABEL_REGEX.test(label)) return label;
110
+ try {
111
+ return punycode.toUnicode(label.toLowerCase());
112
+ } catch {
113
+ return null;
114
+ }
115
+ };
116
+ const isValidIdnUnicodeLabel = (label) => {
117
+ if (label.startsWith("-") || label.endsWith("-")) return false;
118
+ if (label.length >= 4 && label[2] === "-" && label[3] === "-" && !XN_LABEL_REGEX.test(label)) return false;
119
+ if (/^\p{M}/u.test(label)) return false;
120
+ if (/[\u302E\u302F\u0640\u07FA]/u.test(label)) return false;
121
+ for (let idx = 0; idx < label.length; idx++) {
122
+ const char = label[idx];
123
+ if (char === "·" && (idx === 0 || idx === label.length - 1 || label[idx - 1] !== "l" || label[idx + 1] !== "l")) return false;
124
+ if (char === "͵" && (idx === label.length - 1 || !isGreek(label[idx + 1]))) return false;
125
+ if ((char === "׳" || char === "״") && (idx === 0 || !isHebrew(label[idx - 1]))) return false;
126
+ if (char === "‍" && (idx === 0 || label[idx - 1] !== "्")) return false;
127
+ if (char === "‌" && (idx === 0 || label[idx - 1] !== "्" && !hasZwnjJoiningContext(label, idx))) return false;
128
+ }
129
+ for (const char of label) if (isDisallowedCodePoint(char)) return false;
130
+ if (label.includes("・") && !hasCjkKanaOrHan(label.replaceAll("・", ""))) return false;
131
+ const hasArabicIndic = /[\u0660-\u0669]/.test(label);
132
+ const hasExtendedArabicIndic = /[\u06F0-\u06F9]/.test(label);
133
+ if (hasArabicIndic && hasExtendedArabicIndic) return false;
134
+ return true;
135
+ };
136
+ const isValidHostname = (hostname) => {
137
+ if (IDN_SEPARATOR_TEST_REGEX.test(hostname) || /[^\u0000-\u007F]/.test(hostname)) return false;
138
+ if (isIPModule.default(hostname, 4)) return false;
139
+ const labels = splitHostnameLabels(hostname);
140
+ if (labels === null) return false;
141
+ for (let i = 0; i < labels.length; i++) {
142
+ const label = labels[i];
143
+ if (!isAsciiHostnameLabel(label)) return false;
144
+ if (XN_LABEL_REGEX.test(label)) {
145
+ const unicodeLabel = toUnicodeLabel(label);
146
+ if (unicodeLabel === null || !isValidIdnUnicodeLabel(unicodeLabel)) return false;
147
+ }
148
+ }
149
+ return true;
150
+ };
151
+ const isValidIdnHostname = (hostname) => {
152
+ const normalizedHostname = hostname.replace(IDN_SEPARATOR_REGEX, ".");
153
+ const labels = splitHostnameLabels(normalizedHostname);
154
+ if (labels === null) return false;
155
+ const unicodeLabels = [];
156
+ let totalLength = labels.length - 1;
157
+ for (let i = 0; i < labels.length; i++) {
158
+ const label = labels[i];
159
+ const unicodeLabel = toUnicodeLabel(label);
160
+ if (unicodeLabel === null || !isValidIdnUnicodeLabel(unicodeLabel)) return false;
161
+ let aLabel;
162
+ try {
163
+ aLabel = punycode.toASCII(unicodeLabel);
164
+ } catch {
165
+ return false;
166
+ }
167
+ if (XN_LABEL_REGEX.test(label) && aLabel.toLowerCase() !== label.toLowerCase()) return false;
168
+ if (aLabel.length > 63) return false;
169
+ totalLength += aLabel.length;
170
+ unicodeLabels.push(unicodeLabel);
171
+ }
172
+ if (totalLength > 253) return false;
173
+ return isDomainBidiValid(unicodeLabels);
174
+ };
175
+ //#endregion
176
+ export { isValidHostname, isValidIdnHostname };
@@ -1,10 +1,11 @@
1
- import { isObject } from "./what-is.mjs";
1
+ import { isObject } from "./what-is.js";
2
2
  //#region src/utils/json.ts
3
+ const sortedKeys = (obj) => Object.keys(obj).sort();
3
4
  const areEqual = (json1, json2, options, _depth = 0) => {
4
5
  const caseInsensitiveComparison = options?.caseInsensitiveComparison || false;
5
6
  const maxDepth = options?.maxDepth ?? 100;
6
7
  if (json1 === json2) return true;
7
- if (caseInsensitiveComparison === true && typeof json1 === "string" && typeof json2 === "string" && json1.toUpperCase() === json2.toUpperCase()) return true;
8
+ if (caseInsensitiveComparison && typeof json1 === "string" && typeof json2 === "string" && json1.toUpperCase() === json2.toUpperCase()) return true;
8
9
  if (_depth >= maxDepth) throw new Error(`Maximum recursion depth (${maxDepth}) exceeded in areEqual. If your data is deeply nested and valid, increase the maxRecursionDepth option.`);
9
10
  let i, len;
10
11
  if (Array.isArray(json1) && Array.isArray(json2)) {
@@ -15,20 +16,24 @@ const areEqual = (json1, json2, options, _depth = 0) => {
15
16
  }
16
17
  if (isObject(json1) && isObject(json2)) {
17
18
  const keys1 = sortedKeys(json1);
18
- if (!areEqual(keys1, sortedKeys(json2), options, _depth + 1)) return false;
19
+ const keys2 = sortedKeys(json2);
20
+ if (!areEqual(keys1, keys2, options, _depth + 1)) return false;
19
21
  len = keys1.length;
20
22
  for (i = 0; i < len; i++) if (!areEqual(json1[keys1[i]], json2[keys1[i]], options, _depth + 1)) return false;
21
23
  return true;
22
24
  }
23
25
  return false;
24
26
  };
25
- const decodeJSONPointer = (str) => {
26
- return decodeURIComponent(str).replace(/~[0-1]/g, (x) => x === "~1" ? "/" : "~");
27
- };
28
- const sortedKeys = (obj) => Object.keys(obj).sort();
27
+ const decodeJSONPointer = (str) => decodeURIComponent(str).replaceAll(/~[0-1]/g, (x) => x === "~1" ? "/" : "~");
29
28
  const get = (obj, path) => {
30
29
  if (typeof path === "string") path = path.split(".");
31
- return path.reduce((acc, key) => acc && acc[key] !== void 0 ? acc[key] : void 0, obj);
30
+ let acc = obj;
31
+ for (let i = 0; i < path.length; i++) {
32
+ const key = path[i];
33
+ if (acc && acc[key] !== void 0) acc = acc[key];
34
+ else return;
35
+ }
36
+ return acc;
32
37
  };
33
38
  //#endregion
34
39
  export { areEqual, decodeJSONPointer, get, sortedKeys };
@@ -1,4 +1,4 @@
1
- import { MAX_SCHEMA_REGEX_LENGTH } from "./constants.mjs";
1
+ import { MAX_SCHEMA_REGEX_LENGTH } from "./constants.js";
2
2
  import isSafeRegex from "safe-regex2";
3
3
  //#region src/utils/schema-regex.ts
4
4
  function compileSchemaRegex(pattern) {
@@ -21,12 +21,12 @@ function compileSchemaRegex(pattern) {
21
21
  ok: true,
22
22
  value: new RegExp(pattern, "u")
23
23
  };
24
- } catch (e) {
24
+ } catch (error) {
25
25
  return {
26
26
  ok: false,
27
27
  error: {
28
28
  pattern,
29
- message: e && e.message ? e.message : "Invalid regular expression"
29
+ message: error instanceof Error ? error.message : "Invalid regular expression"
30
30
  }
31
31
  };
32
32
  }
@@ -35,12 +35,12 @@ function compileSchemaRegex(pattern) {
35
35
  ok: true,
36
36
  value: new RegExp(pattern)
37
37
  };
38
- } catch (e) {
38
+ } catch (error) {
39
39
  return {
40
40
  ok: false,
41
41
  error: {
42
42
  pattern,
43
- message: e && e.message ? e.message : "Invalid regular expression"
43
+ message: error instanceof Error ? error.message : "Invalid regular expression"
44
44
  }
45
45
  };
46
46
  }
@@ -8,22 +8,22 @@ const toUtcTime = (hour, minute, offsetSign, offsetHour, offsetMinute) => {
8
8
  minute: normalizedUtcTotalMinutes % 60
9
9
  };
10
10
  };
11
- const RFC3339_TIME_REGEX = /^([0-9]{2}):([0-9]{2}):([0-9]{2})(\.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$/i;
11
+ const RFC3339_TIME_REGEX = /^(?<hour>[0-9]{2}):(?<minute>[0-9]{2}):(?<second>[0-9]{2})(?<fraction>\.[0-9]+)?(?<offset>z|(?<offsetValue>[+-][0-9]{2}:[0-9]{2}))$/i;
12
12
  const parseRfc3339Time = (time) => {
13
13
  const matches = RFC3339_TIME_REGEX.exec(time);
14
14
  if (matches === null) return null;
15
- const hour = parseInt(matches[1], 10);
16
- const minute = parseInt(matches[2], 10);
17
- const second = parseInt(matches[3], 10);
15
+ const hour = Number.parseInt(matches[1], 10);
16
+ const minute = Number.parseInt(matches[2], 10);
17
+ const second = Number.parseInt(matches[3], 10);
18
18
  if (hour > 23 || minute > 59 || second > 60) return null;
19
19
  let utcHour = hour;
20
20
  let utcMinute = minute;
21
21
  if (matches[5].toLowerCase() !== "z") {
22
- const offsetMatches = /^([+-])([0-9]{2}):([0-9]{2})$/.exec(matches[5]);
22
+ const offsetMatches = /^(?<sign>[+-])(?<hour>[0-9]{2}):(?<minute>[0-9]{2})$/.exec(matches[5]);
23
23
  if (offsetMatches === null) return null;
24
24
  const offsetSign = offsetMatches[1];
25
- const offsetHour = parseInt(offsetMatches[2], 10);
26
- const offsetMinute = parseInt(offsetMatches[3], 10);
25
+ const offsetHour = Number.parseInt(offsetMatches[2], 10);
26
+ const offsetMinute = Number.parseInt(offsetMatches[3], 10);
27
27
  if (offsetHour > 23 || offsetMinute > 59) return null;
28
28
  const utc = toUtcTime(hour, minute, offsetSign, offsetHour, offsetMinute);
29
29
  utcHour = utc.hour;
@@ -39,4 +39,4 @@ const parseRfc3339Time = (time) => {
39
39
  };
40
40
  };
41
41
  //#endregion
42
- export { parseRfc3339Time };
42
+ export { parseRfc3339Time, toUtcTime };
@@ -0,0 +1,22 @@
1
+ //#region src/utils/unicode.ts
2
+ /**
3
+ * Returns the number of Unicode code points in the string.
4
+ * Uses a surrogate-aware charCodeAt scan (equivalent to the string iterator)
5
+ * that counts a surrogate pair as one code point and lone surrogates as one each.
6
+ */
7
+ function unicodeLength(str) {
8
+ let count = str.length;
9
+ for (let i = 0; i < str.length - 1; i++) {
10
+ const hi = str.charCodeAt(i);
11
+ if (hi >= 55296 && hi <= 56319) {
12
+ const lo = str.charCodeAt(i + 1);
13
+ if (lo >= 56320 && lo <= 57343) {
14
+ count--;
15
+ i++;
16
+ }
17
+ }
18
+ }
19
+ return count;
20
+ }
21
+ //#endregion
22
+ export { unicodeLength };
@@ -6,8 +6,7 @@ const whatIs = (what) => {
6
6
  return "object";
7
7
  }
8
8
  if (typeof what === "number") {
9
- if (Number.isFinite(what)) if (what % 1 === 0) return "integer";
10
- else return "number";
9
+ if (Number.isFinite(what)) return what % 1 === 0 ? "integer" : "number";
11
10
  if (Number.isNaN(what)) return "not-a-number";
12
11
  return "unknown-number";
13
12
  }
@@ -1,35 +1,33 @@
1
- import { isUniqueArray } from "../utils/array.mjs";
2
- import { cacheValidationResult, deferOrRunSync, shouldSkipValidate } from "./shared.mjs";
1
+ import { isUniqueArray } from "../utils/array.js";
2
+ import { cacheValidationResult, deferOrRunSync, shouldSkipValidate } from "./shared.js";
3
3
  //#region src/validation/array.ts
4
- function additionalItemsValidator(report, schema, json) {
5
- if (shouldSkipValidate(this.validateOptions, ["ARRAY_ADDITIONAL_ITEMS"])) return;
4
+ function additionalItemsValidator(ctx, report, schema, json) {
5
+ if (shouldSkipValidate(ctx.validateOptions, ["ARRAY_ADDITIONAL_ITEMS"])) return;
6
6
  if (!Array.isArray(json)) return;
7
- if (schema.additionalItems === false && Array.isArray(schema.items)) {
8
- if (json.length > schema.items.length) report.addError("ARRAY_ADDITIONAL_ITEMS", void 0, void 0, schema, "additionalItems");
9
- }
7
+ if (schema.additionalItems === false && Array.isArray(schema.items) && json.length > schema.items.length) report.addError("ARRAY_ADDITIONAL_ITEMS", void 0, void 0, schema, "additionalItems");
10
8
  }
11
9
  function itemsValidator() {}
12
10
  function prefixItemsValidator() {}
13
- function maxItemsValidator(report, schema, json) {
14
- if (shouldSkipValidate(this.validateOptions, ["ARRAY_LENGTH_LONG"])) return;
11
+ function maxItemsValidator(ctx, report, schema, json) {
12
+ if (shouldSkipValidate(ctx.validateOptions, ["ARRAY_LENGTH_LONG"])) return;
15
13
  if (!Array.isArray(json)) return;
16
14
  if (json.length > schema.maxItems) report.addError("ARRAY_LENGTH_LONG", [json.length, schema.maxItems], void 0, schema, "maxItems");
17
15
  }
18
- function minItemsValidator(report, schema, json) {
19
- if (shouldSkipValidate(this.validateOptions, ["ARRAY_LENGTH_SHORT"])) return;
16
+ function minItemsValidator(ctx, report, schema, json) {
17
+ if (shouldSkipValidate(ctx.validateOptions, ["ARRAY_LENGTH_SHORT"])) return;
20
18
  if (!Array.isArray(json)) return;
21
19
  if (json.length < schema.minItems) report.addError("ARRAY_LENGTH_SHORT", [json.length, schema.minItems], void 0, schema, "minItems");
22
20
  }
23
- function uniqueItemsValidator(report, schema, json) {
24
- if (shouldSkipValidate(this.validateOptions, ["ARRAY_UNIQUE"])) return;
21
+ function uniqueItemsValidator(ctx, report, schema, json) {
22
+ if (shouldSkipValidate(ctx.validateOptions, ["ARRAY_UNIQUE"])) return;
25
23
  if (!Array.isArray(json)) return;
26
24
  if (schema.uniqueItems === true) {
27
25
  const matches = [];
28
- if (isUniqueArray(json, matches, this.options.maxRecursionDepth) === false) report.addError("ARRAY_UNIQUE", matches, void 0, schema, "uniqueItems");
26
+ if (!isUniqueArray(json, matches, ctx.options.maxRecursionDepth)) report.addError("ARRAY_UNIQUE", matches, void 0, schema, "uniqueItems");
29
27
  }
30
28
  }
31
- function containsValidator(report, schema, json) {
32
- if (shouldSkipValidate(this.validateOptions, ["CONTAINS"])) return;
29
+ function containsValidator(ctx, report, schema, json) {
30
+ if (shouldSkipValidate(ctx.validateOptions, ["CONTAINS"])) return;
33
31
  if (!Array.isArray(json)) return;
34
32
  const containsSchema = schema.contains;
35
33
  if (containsSchema === void 0) return;
@@ -38,16 +36,16 @@ function containsValidator(report, schema, json) {
38
36
  for (let idx = 0; idx < json.length; idx++) {
39
37
  const subReport = new Report_(report);
40
38
  subReports.push(subReport);
41
- this._jsonValidate(subReport, containsSchema, json[idx]);
39
+ ctx._jsonValidate(subReport, containsSchema, json[idx]);
42
40
  cacheValidationResult(report, containsSchema, json[idx], subReport.errors.length === 0);
43
41
  }
44
42
  const addContainsErrorIfNeeded = () => {
45
43
  let matchingItems = 0;
46
- for (const subReport of subReports) if (subReport.errors.length === 0) matchingItems += 1;
47
- const supportsContainsBounds = this.options.version === "draft2019-09" || this.options.version === "draft2020-12";
44
+ for (let i = 0; i < subReports.length; i++) if (subReports[i].errors.length === 0) matchingItems += 1;
45
+ const supportsContainsBounds = ctx.options.version === "draft2019-09" || ctx.options.version === "draft2020-12";
48
46
  const minContains = supportsContainsBounds && typeof schema.minContains === "number" ? schema.minContains ?? 1 : 1;
49
47
  const maxContains = supportsContainsBounds && typeof schema.maxContains === "number" ? schema.maxContains : void 0;
50
- if (!(matchingItems >= minContains) || !(maxContains === void 0 || matchingItems <= maxContains)) report.addError("CONTAINS", void 0, subReports, schema, void 0);
48
+ if (!(matchingItems >= minContains) || !(maxContains === void 0 || matchingItems <= maxContains)) report.addError("CONTAINS", void 0, subReports, schema);
51
49
  };
52
50
  deferOrRunSync(report, subReports, addContainsErrorIfNeeded);
53
51
  }
@@ -1,18 +1,18 @@
1
- import { Report } from "../report.mjs";
2
- import { cacheValidationResult, deferOrRunSync } from "./shared.mjs";
1
+ import { Report } from "../report.js";
2
+ import { cacheValidationResult, deferOrRunSync } from "./shared.js";
3
3
  //#region src/validation/combinators.ts
4
- function allOfValidator(report, schema, json) {
4
+ function allOfValidator(ctx, report, schema, json) {
5
5
  for (let i = 0; i < schema.allOf.length; i++) {
6
- const validateResult = this._jsonValidate(report, schema.allOf[i], json);
7
- if (this.options.breakOnFirstError && validateResult === false) break;
6
+ const validateResult = ctx._jsonValidate(report, schema.allOf[i], json);
7
+ if (ctx.options.breakOnFirstError && !validateResult) break;
8
8
  }
9
9
  }
10
- function anyOfValidator(report, schema, json) {
10
+ function anyOfValidator(ctx, report, schema, json) {
11
11
  const subReports = [];
12
12
  for (let i = 0; i < schema.anyOf.length; i++) {
13
13
  const subReport = new Report(report);
14
14
  subReports.push(subReport);
15
- this._jsonValidate(subReport, schema.anyOf[i], json);
15
+ ctx._jsonValidate(subReport, schema.anyOf[i], json);
16
16
  cacheValidationResult(report, schema.anyOf[i], json, subReport.errors.length === 0);
17
17
  }
18
18
  deferOrRunSync(report, subReports, () => {
@@ -21,15 +21,15 @@ function anyOfValidator(report, schema, json) {
21
21
  passed = true;
22
22
  break;
23
23
  }
24
- if (passed === false) report.addError("ANY_OF_MISSING", void 0, subReports, schema, "anyOf");
24
+ if (!passed) report.addError("ANY_OF_MISSING", void 0, subReports, schema, "anyOf");
25
25
  });
26
26
  }
27
- function oneOfValidator(report, schema, json) {
27
+ function oneOfValidator(ctx, report, schema, json) {
28
28
  const subReports = [];
29
29
  for (let i = 0; i < schema.oneOf.length; i++) {
30
30
  const subReport = new Report(report);
31
31
  subReports.push(subReport);
32
- this._jsonValidate(subReport, schema.oneOf[i], json);
32
+ ctx._jsonValidate(subReport, schema.oneOf[i], json);
33
33
  cacheValidationResult(report, schema.oneOf[i], json, subReport.errors.length === 0);
34
34
  }
35
35
  deferOrRunSync(report, subReports, () => {
@@ -39,22 +39,22 @@ function oneOfValidator(report, schema, json) {
39
39
  else if (passes > 1) report.addError("ONE_OF_MULTIPLE", void 0, void 0, schema, "oneOf");
40
40
  });
41
41
  }
42
- function notValidator(report, schema, json) {
42
+ function notValidator(ctx, report, schema, json) {
43
43
  const subReport = new Report(report);
44
- if (this._jsonValidate(subReport, schema.not, json) === true) report.addError("NOT_PASSED", void 0, void 0, schema, "not");
44
+ if (ctx._jsonValidate(subReport, schema.not, json)) report.addError("NOT_PASSED", void 0, void 0, schema, "not");
45
45
  }
46
- function ifValidator(report, schema, json) {
47
- if (this.options.version === "draft-04" || this.options.version === "draft-06") return;
46
+ function ifValidator(ctx, report, schema, json) {
47
+ if (ctx.options.version === "draft-04" || ctx.options.version === "draft-06") return;
48
48
  const conditionSchema = schema.if;
49
49
  const thenSchema = schema.then;
50
50
  const elseSchema = schema.else;
51
51
  if (conditionSchema === void 0 || thenSchema === void 0 && elseSchema === void 0) return;
52
52
  const conditionReport = new Report(report);
53
- this._jsonValidate(conditionReport, conditionSchema, json);
53
+ ctx._jsonValidate(conditionReport, conditionSchema, json);
54
54
  cacheValidationResult(report, conditionSchema, json, conditionReport.errors.length === 0);
55
55
  const branchSchema = conditionReport.errors.length === 0 ? thenSchema : elseSchema;
56
56
  if (branchSchema === void 0) return;
57
- this._jsonValidate(report, branchSchema, json);
57
+ ctx._jsonValidate(report, branchSchema, json);
58
58
  }
59
59
  function thenValidator() {}
60
60
  function elseValidator() {}
@@ -1,35 +1,35 @@
1
- import { shouldSkipValidate } from "./shared.mjs";
1
+ import { shouldSkipValidate } from "./shared.js";
2
2
  //#region src/validation/numeric.ts
3
- function multipleOfValidator(report, schema, json) {
4
- if (shouldSkipValidate(this.validateOptions, ["MULTIPLE_OF"])) return;
3
+ function multipleOfValidator(ctx, report, schema, json) {
4
+ if (shouldSkipValidate(ctx.validateOptions, ["MULTIPLE_OF"])) return;
5
5
  if (typeof json !== "number") return;
6
6
  const result = json / schema.multipleOf;
7
7
  if (!Number.isFinite(result) || Math.abs(result - Math.round(result)) >= 1e-10) report.addError("MULTIPLE_OF", [json, schema.multipleOf], void 0, schema, "multipleOf");
8
8
  }
9
- function maximumValidator(report, schema, json) {
10
- if (shouldSkipValidate(this.validateOptions, ["MAXIMUM", "MAXIMUM_EXCLUSIVE"])) return;
9
+ function maximumValidator(ctx, report, schema, json) {
10
+ if (shouldSkipValidate(ctx.validateOptions, ["MAXIMUM", "MAXIMUM_EXCLUSIVE"])) return;
11
11
  if (typeof json !== "number") return;
12
12
  if (schema.exclusiveMaximum !== true) {
13
13
  if (json > schema.maximum) report.addError("MAXIMUM", [json, schema.maximum], void 0, schema, "maximum");
14
14
  } else if (json >= schema.maximum) report.addError("MAXIMUM_EXCLUSIVE", [json, schema.maximum], void 0, schema, "maximum");
15
15
  }
16
- function exclusiveMaximumValidator(report, schema, json) {
16
+ function exclusiveMaximumValidator(ctx, report, schema, json) {
17
17
  if (typeof schema.exclusiveMaximum === "number") {
18
- if (shouldSkipValidate(this.validateOptions, ["MAXIMUM_EXCLUSIVE"])) return;
18
+ if (shouldSkipValidate(ctx.validateOptions, ["MAXIMUM_EXCLUSIVE"])) return;
19
19
  if (typeof json !== "number") return;
20
20
  if (json >= schema.exclusiveMaximum) report.addError("MAXIMUM_EXCLUSIVE", [json, schema.exclusiveMaximum], void 0, schema, "exclusiveMaximum");
21
21
  }
22
22
  }
23
- function minimumValidator(report, schema, json) {
24
- if (shouldSkipValidate(this.validateOptions, ["MINIMUM", "MINIMUM_EXCLUSIVE"])) return;
23
+ function minimumValidator(ctx, report, schema, json) {
24
+ if (shouldSkipValidate(ctx.validateOptions, ["MINIMUM", "MINIMUM_EXCLUSIVE"])) return;
25
25
  if (typeof json !== "number") return;
26
26
  if (schema.exclusiveMinimum !== true) {
27
27
  if (json < schema.minimum) report.addError("MINIMUM", [json, schema.minimum], void 0, schema, "minimum");
28
28
  } else if (json <= schema.minimum) report.addError("MINIMUM_EXCLUSIVE", [json, schema.minimum], void 0, schema, "minimum");
29
29
  }
30
- function exclusiveMinimumValidator(report, schema, json) {
30
+ function exclusiveMinimumValidator(ctx, report, schema, json) {
31
31
  if (typeof schema.exclusiveMinimum === "number") {
32
- if (shouldSkipValidate(this.validateOptions, ["MINIMUM_EXCLUSIVE"])) return;
32
+ if (shouldSkipValidate(ctx.validateOptions, ["MINIMUM_EXCLUSIVE"])) return;
33
33
  if (typeof json !== "number") return;
34
34
  if (json <= schema.exclusiveMinimum) report.addError("MINIMUM_EXCLUSIVE", [json, schema.exclusiveMinimum], void 0, schema, "exclusiveMinimum");
35
35
  }