z-schema 12.2.0 → 12.3.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.
Files changed (110) hide show
  1. package/README.md +2 -2
  2. package/bin/z-schema +1 -1
  3. package/cjs/{index.js → index.cjs} +696 -687
  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} +43 -36
  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} +7 -12
  13. package/dist/{json-validation.mjs → json-validation.js} +143 -127
  14. package/dist/{report.d.mts → report.d.ts} +7 -8
  15. package/dist/{report.mjs → report.js} +28 -31
  16. package/dist/{schema-cache.d.mts → schema-cache.d.ts} +4 -4
  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} +95 -77
  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.mjs → hostname.js} +19 -22
  26. package/dist/utils/{json.mjs → json.js} +11 -7
  27. package/dist/utils/{schema-regex.mjs → schema-regex.js} +5 -5
  28. package/dist/utils/{time.mjs → time.js} +5 -5
  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} +4 -4
  36. package/dist/validation/{shared.mjs → shared.js} +12 -11
  37. package/dist/validation/{string.mjs → string.js} +32 -32
  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} +4 -4
  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} +37 -47
  47. package/package.json +22 -23
  48. package/src/errors.ts +1 -2
  49. package/src/format-validators.ts +139 -59
  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 +27 -27
  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 +5 -5
  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 +29 -39
  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 +711 -695
  80. package/umd/ZSchema.min.js +2 -2
  81. package/umd/package.json +3 -0
  82. package/dist/utils/unicode.mjs +0 -12
  83. package/dist/validation/type.mjs +0 -32
  84. /package/dist/{format-validators.d.mts → format-validators.d.ts} +0 -0
  85. /package/dist/{json-schema-versions.mjs → json-schema-versions.js} +0 -0
  86. /package/dist/schemas/{draft-04-schema.mjs → draft-04-schema.js} +0 -0
  87. /package/dist/schemas/{draft-06-schema.mjs → draft-06-schema.js} +0 -0
  88. /package/dist/schemas/{draft-07-schema.mjs → draft-07-schema.js} +0 -0
  89. /package/dist/schemas/{draft-2019-09-meta-applicator.mjs → draft-2019-09-meta-applicator.js} +0 -0
  90. /package/dist/schemas/{draft-2019-09-meta-content.mjs → draft-2019-09-meta-content.js} +0 -0
  91. /package/dist/schemas/{draft-2019-09-meta-core.mjs → draft-2019-09-meta-core.js} +0 -0
  92. /package/dist/schemas/{draft-2019-09-meta-format.mjs → draft-2019-09-meta-format.js} +0 -0
  93. /package/dist/schemas/{draft-2019-09-meta-meta-data.mjs → draft-2019-09-meta-meta-data.js} +0 -0
  94. /package/dist/schemas/{draft-2019-09-meta-validation.mjs → draft-2019-09-meta-validation.js} +0 -0
  95. /package/dist/schemas/{draft-2019-09-schema.mjs → draft-2019-09-schema.js} +0 -0
  96. /package/dist/schemas/{draft-2020-12-meta-applicator.mjs → draft-2020-12-meta-applicator.js} +0 -0
  97. /package/dist/schemas/{draft-2020-12-meta-content.mjs → draft-2020-12-meta-content.js} +0 -0
  98. /package/dist/schemas/{draft-2020-12-meta-core.mjs → draft-2020-12-meta-core.js} +0 -0
  99. /package/dist/schemas/{draft-2020-12-meta-format-annotation.mjs → draft-2020-12-meta-format-annotation.js} +0 -0
  100. /package/dist/schemas/{draft-2020-12-meta-format-assertion.mjs → draft-2020-12-meta-format-assertion.js} +0 -0
  101. /package/dist/schemas/{draft-2020-12-meta-meta-data.mjs → draft-2020-12-meta-meta-data.js} +0 -0
  102. /package/dist/schemas/{draft-2020-12-meta-unevaluated.mjs → draft-2020-12-meta-unevaluated.js} +0 -0
  103. /package/dist/schemas/{draft-2020-12-meta-validation.mjs → draft-2020-12-meta-validation.js} +0 -0
  104. /package/dist/schemas/{draft-2020-12-schema.mjs → draft-2020-12-schema.js} +0 -0
  105. /package/dist/utils/{constants.mjs → constants.js} +0 -0
  106. /package/dist/utils/{date.mjs → date.js} +0 -0
  107. /package/dist/utils/{properties.mjs → properties.js} +0 -0
  108. /package/dist/utils/{symbols.mjs → symbols.js} +0 -0
  109. /package/dist/utils/{uri.mjs → uri.js} +0 -0
  110. /package/dist/{z-schema-reader.mjs → z-schema-reader.js} +0 -0
@@ -7,9 +7,11 @@ import { areEqual } from './json.js';
7
7
  * Falls back to pairwise deep comparison (O(n²)) when the array contains
8
8
  * objects or arrays that need structural equality checks.
9
9
  */
10
- export const isUniqueArray = <T>(arr: T[], indexes?: number[], maxDepth?: number): boolean => {
10
+ export const isUniqueArray = (arr: unknown[], indexes?: number[], maxDepth?: number): boolean => {
11
11
  const l = arr.length;
12
- if (l <= 1) return true;
12
+ if (l <= 1) {
13
+ return true;
14
+ }
13
15
 
14
16
  // Fast path: if every element is a primitive, use a Set.
15
17
  // We distinguish types so that e.g. 1 !== '1' and 0 !== false.
@@ -27,7 +29,7 @@ export const isUniqueArray = <T>(arr: T[], indexes?: number[], maxDepth?: number
27
29
  const seen = new Set<string>();
28
30
  for (let i = 0; i < l; i++) {
29
31
  const v = arr[i];
30
- const key = typeof v + ':' + String(v);
32
+ const key = `${typeof v}:${String(v)}`;
31
33
  if (seen.has(key)) {
32
34
  // Find the first occurrence for the indexes report.
33
35
  if (indexes) {
@@ -47,9 +49,10 @@ export const isUniqueArray = <T>(arr: T[], indexes?: number[], maxDepth?: number
47
49
  }
48
50
 
49
51
  // Slow path: at least one element is an object/array — need deep comparison.
52
+ const eqOpts = { maxDepth };
50
53
  for (let i = 0; i < l; i++) {
51
54
  for (let j = i + 1; j < l; j++) {
52
- if (areEqual(arr[i], arr[j], { maxDepth })) {
55
+ if (areEqual(arr[i], arr[j], eqOpts)) {
53
56
  if (indexes) {
54
57
  indexes.push(i, j);
55
58
  }
@@ -60,9 +63,9 @@ export const isUniqueArray = <T>(arr: T[], indexes?: number[], maxDepth?: number
60
63
  return true;
61
64
  };
62
65
 
63
- export const difference = (bigSet: any[], subSet: any[]) => {
66
+ export const difference = <T>(bigSet: readonly T[], subSet: readonly T[]): T[] => {
64
67
  const exclusions = new Set(subSet);
65
- const arr = [];
68
+ const arr: T[] = [];
66
69
  let idx = bigSet.length;
67
70
  while (idx--) {
68
71
  if (!exclusions.has(bigSet[idx])) {
@@ -20,9 +20,20 @@ export const decodeBase64 = (value: string): string | undefined => {
20
20
  }
21
21
  }
22
22
 
23
- if (typeof Buffer !== 'undefined') {
23
+ // Node fallback (reached only when `atob` is unavailable, i.e. not a browser).
24
+ // Read `Buffer` off `globalThis` rather than the bare global so it is typed
25
+ // without an untyped global reference; on Node >=22 `Buffer` is always present
26
+ // on `globalThis`. (A bundler polyfill injected as a module-scoped variable but
27
+ // not onto `globalThis` would be missed, but that path is unreachable in browsers
28
+ // where `atob` above is used instead.)
29
+ const bufferCtor = (
30
+ globalThis as {
31
+ Buffer?: { from(data: string, encoding: string): { toString(encoding: string): string } };
32
+ }
33
+ ).Buffer;
34
+ if (bufferCtor !== undefined) {
24
35
  try {
25
- return Buffer.from(value, 'base64').toString('utf8');
36
+ return bufferCtor.from(value, 'base64').toString('utf-8');
26
37
  } catch {
27
38
  return undefined;
28
39
  }
@@ -5,29 +5,28 @@ export const shallowClone = <T>(src: T): T => {
5
5
  if (src == null || typeof src !== 'object') {
6
6
  return src;
7
7
  }
8
- let res: any;
9
8
  if (Array.isArray(src)) {
10
- res = [];
9
+ const res: unknown[] = [];
11
10
  for (let i = 0; i < src.length; i++) {
12
11
  res[i] = src[i];
13
12
  }
14
- } else {
15
- res = {};
16
- const keys = Object.keys(src).sort() as Array<keyof T>;
17
- for (const key of keys) {
18
- copyProp(src, res, key);
19
- }
13
+ return res as T;
14
+ }
15
+ const res: Record<string, unknown> = {};
16
+ const keys = Object.keys(src).sort() as Array<keyof T>;
17
+ for (let i = 0; i < keys.length; i++) {
18
+ copyProp(src, res, keys[i]);
20
19
  }
21
- return res;
20
+ return res as T;
22
21
  };
23
22
 
24
23
  export const deepClone = <T>(src: T, maxDepth = DEFAULT_MAX_RECURSION_DEPTH): T => {
25
24
  let vidx = 0;
26
- const visited = new Map();
27
- const cloned: any[] = [];
28
- const cloneDeepInner = <T>(src: T, _depth: number): T => {
29
- if (typeof src !== 'object' || src === null) {
30
- return src;
25
+ const visited = new Map<unknown, number>();
26
+ const cloned: unknown[] = [];
27
+ const cloneDeepInner = <U>(node: U, _depth: number): U => {
28
+ if (typeof node !== 'object' || node === null) {
29
+ return node;
31
30
  }
32
31
 
33
32
  if (_depth >= maxDepth) {
@@ -37,29 +36,28 @@ export const deepClone = <T>(src: T, maxDepth = DEFAULT_MAX_RECURSION_DEPTH): T
37
36
  );
38
37
  }
39
38
 
40
- let res: any;
41
- const cidx = visited.get(src);
39
+ const cidx = visited.get(node);
42
40
 
43
41
  if (cidx !== undefined) {
44
- return cloned[cidx];
42
+ return cloned[cidx] as U;
45
43
  }
46
44
 
47
- visited.set(src, vidx++);
48
- if (Array.isArray(src)) {
49
- res = [];
45
+ visited.set(node, vidx++);
46
+ if (Array.isArray(node)) {
47
+ const res: unknown[] = [];
50
48
  cloned.push(res);
51
- for (let i = 0; i < src.length; i++) {
52
- res[i] = cloneDeepInner(src[i], _depth + 1);
53
- }
54
- } else {
55
- res = {};
56
- cloned.push(res);
57
- const keys = Object.keys(src).sort() as Array<keyof T>;
58
- for (const key of keys) {
59
- copyProp(src, res, key, (v: any) => cloneDeepInner(v, _depth + 1));
49
+ for (let i = 0; i < node.length; i++) {
50
+ res[i] = cloneDeepInner(node[i], _depth + 1);
60
51
  }
52
+ return res as U;
53
+ }
54
+ const res: Record<string, unknown> = {};
55
+ cloned.push(res);
56
+ const keys = Object.keys(node).sort() as Array<keyof U>;
57
+ for (let i = 0; i < keys.length; i++) {
58
+ copyProp(node, res, keys[i], (v: unknown) => cloneDeepInner(v, _depth + 1));
61
59
  }
62
- return res;
60
+ return res as U;
63
61
  };
64
62
  return cloneDeepInner(src, 0);
65
63
  };
package/src/utils/date.ts CHANGED
@@ -2,15 +2,18 @@ const isLeapYear = (year: number): boolean => year % 4 === 0 && (year % 100 !==
2
2
 
3
3
  const getDaysInMonth = (year: number, month: number): number => {
4
4
  switch (month) {
5
- case 2:
5
+ case 2: {
6
6
  return isLeapYear(year) ? 29 : 28;
7
+ }
7
8
  case 4:
8
9
  case 6:
9
10
  case 9:
10
- case 11:
11
+ case 11: {
11
12
  return 30;
12
- default:
13
+ }
14
+ default: {
13
15
  return 31;
16
+ }
14
17
  }
15
18
  };
16
19
 
@@ -1,8 +1,8 @@
1
1
  import punycode from 'punycode/punycode.js';
2
2
  import isIPModule from 'validator/lib/isIP.js';
3
3
 
4
- const IDN_SEPARATOR_REGEX = /[\u3002\uff0e\uff61]/g;
5
- const IDN_SEPARATOR_TEST_REGEX = /[\u3002\uff0e\uff61]/;
4
+ const IDN_SEPARATOR_REGEX = /[\u3002\uFF0E\uFF61]/g;
5
+ const IDN_SEPARATOR_TEST_REGEX = /[\u3002\uFF0E\uFF61]/;
6
6
 
7
7
  const splitHostnameLabels = (hostname: string): string[] | null => {
8
8
  if (hostname.length === 0 || hostname.length > 255) {
@@ -12,8 +12,11 @@ const splitHostnameLabels = (hostname: string): string[] | null => {
12
12
  return null;
13
13
  }
14
14
  const labels = hostname.split('.');
15
- if (labels.some((label) => label.length === 0 || label.length > 63)) {
16
- return null;
15
+ for (let i = 0; i < labels.length; i++) {
16
+ const len = labels[i].length;
17
+ if (len === 0 || len > 63) {
18
+ return null;
19
+ }
17
20
  }
18
21
  return labels;
19
22
  };
@@ -33,7 +36,7 @@ const toUnicodeLabel = (label: string): string | null => {
33
36
  }
34
37
  try {
35
38
  return punycode.toUnicode(label.toLowerCase());
36
- } catch (_e) {
39
+ } catch {
37
40
  return null;
38
41
  }
39
42
  };
@@ -51,44 +54,39 @@ const isValidIdnUnicodeLabel = (label: string): boolean => {
51
54
  return false;
52
55
  }
53
56
 
54
- if (/[\u302e\u302f\u0640\u07fa]/u.test(label)) {
57
+ if (/[\u302E\u302F\u0640\u07FA]/u.test(label)) {
55
58
  return false;
56
59
  }
57
60
 
58
61
  for (let idx = 0; idx < label.length; idx++) {
59
62
  const char = label[idx];
60
63
 
61
- if (char === '\u00b7') {
62
- if (idx === 0 || idx === label.length - 1 || label[idx - 1] !== 'l' || label[idx + 1] !== 'l') {
63
- return false;
64
- }
64
+ if (
65
+ char === '\u00B7' &&
66
+ (idx === 0 || idx === label.length - 1 || label[idx - 1] !== 'l' || label[idx + 1] !== 'l')
67
+ ) {
68
+ return false;
65
69
  }
66
70
 
67
- if (char === '\u0375') {
68
- if (idx === label.length - 1 || !isGreek(label[idx + 1])) {
69
- return false;
70
- }
71
+ if (char === '\u0375' && (idx === label.length - 1 || !isGreek(label[idx + 1]))) {
72
+ return false;
71
73
  }
72
74
 
73
- if (char === '\u05f3' || char === '\u05f4') {
74
- if (idx === 0 || !isHebrew(label[idx - 1])) {
75
- return false;
76
- }
75
+ if ((char === '\u05F3' || char === '\u05F4') && (idx === 0 || !isHebrew(label[idx - 1]))) {
76
+ return false;
77
77
  }
78
78
 
79
- if (char === '\u200d') {
80
- if (idx === 0 || label[idx - 1] !== '\u094d') {
81
- return false;
82
- }
79
+ if (char === '\u200D' && (idx === 0 || label[idx - 1] !== '\u094D')) {
80
+ return false;
83
81
  }
84
82
  }
85
83
 
86
- if (label.includes('\u30fb') && !hasCjkKanaOrHan(label.replace(/\u30fb/g, ''))) {
84
+ if (label.includes('\u30FB') && !hasCjkKanaOrHan(label.replaceAll('・', ''))) {
87
85
  return false;
88
86
  }
89
87
 
90
88
  const hasArabicIndic = /[\u0660-\u0669]/.test(label);
91
- const hasExtendedArabicIndic = /[\u06f0-\u06f9]/.test(label);
89
+ const hasExtendedArabicIndic = /[\u06F0-\u06F9]/.test(label);
92
90
  if (hasArabicIndic && hasExtendedArabicIndic) {
93
91
  return false;
94
92
  }
@@ -129,7 +127,7 @@ const isValidIdnUnicodeLabel = (label: string): boolean => {
129
127
  */
130
128
  export const isValidHostname = (hostname: string): boolean => {
131
129
  // eslint-disable-next-line no-control-regex
132
- if (IDN_SEPARATOR_TEST_REGEX.test(hostname) || /[^\x00-\x7F]/.test(hostname)) {
130
+ if (IDN_SEPARATOR_TEST_REGEX.test(hostname) || /[^\u0000-\u007F]/.test(hostname)) {
133
131
  return false;
134
132
  }
135
133
 
@@ -142,7 +140,8 @@ export const isValidHostname = (hostname: string): boolean => {
142
140
  return false;
143
141
  }
144
142
 
145
- for (const label of labels) {
143
+ for (let i = 0; i < labels.length; i++) {
144
+ const label = labels[i];
146
145
  if (!isAsciiHostnameLabel(label)) {
147
146
  return false;
148
147
  }
@@ -166,7 +165,8 @@ export const isValidIdnHostname = (hostname: string): boolean => {
166
165
  return false;
167
166
  }
168
167
 
169
- for (const label of labels) {
168
+ for (let i = 0; i < labels.length; i++) {
169
+ const label = labels[i];
170
170
  const unicodeLabel = toUnicodeLabel(label);
171
171
  if (unicodeLabel === null || !isValidIdnUnicodeLabel(unicodeLabel)) {
172
172
  return false;
package/src/utils/json.ts CHANGED
@@ -6,6 +6,8 @@ interface AreEqualOptions {
6
6
  maxDepth?: number;
7
7
  }
8
8
 
9
+ export const sortedKeys = (obj: Record<string, unknown>): string[] => Object.keys(obj).sort();
10
+
9
11
  export const areEqual = (json1: unknown, json2: unknown, options?: AreEqualOptions, _depth = 0): boolean => {
10
12
  const caseInsensitiveComparison = options?.caseInsensitiveComparison || false;
11
13
  const maxDepth = options?.maxDepth ?? DEFAULT_MAX_RECURSION_DEPTH;
@@ -21,7 +23,7 @@ export const areEqual = (json1: unknown, json2: unknown, options?: AreEqualOptio
21
23
  return true;
22
24
  }
23
25
  if (
24
- caseInsensitiveComparison === true &&
26
+ caseInsensitiveComparison &&
25
27
  typeof json1 === 'string' &&
26
28
  typeof json2 === 'string' &&
27
29
  json1.toUpperCase() === json2.toUpperCase()
@@ -75,16 +77,21 @@ export const areEqual = (json1: unknown, json2: unknown, options?: AreEqualOptio
75
77
  return false;
76
78
  };
77
79
 
78
- export const decodeJSONPointer = (str: string) => {
79
- // http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07#section-3
80
- return decodeURIComponent(str).replace(/~[0-1]/g, (x) => (x === '~1' ? '/' : '~'));
81
- };
80
+ export const decodeJSONPointer = (str: string) =>
81
+ decodeURIComponent(str).replaceAll(/~[0-1]/g, (x) => (x === '~1' ? '/' : '~'));
82
82
 
83
- export const sortedKeys = (obj: Record<string, unknown>): string[] => Object.keys(obj).sort();
84
-
85
- export const get = (obj: any, path: string | Array<string | number>): any => {
83
+ export const get = (obj: unknown, path: string | Array<string | number>): unknown => {
86
84
  if (typeof path === 'string') {
87
85
  path = path.split('.');
88
86
  }
89
- return path.reduce((acc, key) => (acc && acc[key] !== undefined ? acc[key] : undefined), obj);
87
+ let acc: unknown = obj;
88
+ for (let i = 0; i < path.length; i++) {
89
+ const key = path[i];
90
+ if (acc && (acc as Record<string | number, unknown>)[key] !== undefined) {
91
+ acc = (acc as Record<string | number, unknown>)[key];
92
+ } else {
93
+ return undefined;
94
+ }
95
+ }
96
+ return acc;
90
97
  };
@@ -1,7 +1,7 @@
1
- export function copyProp(from: object, to: object, key: string | number | symbol, fn?: <T>(obj: T) => T) {
1
+ export function copyProp(from: object, to: object, key: string | number | symbol, fn?: (value: unknown) => unknown) {
2
2
  if (Object.hasOwn(from, key)) {
3
3
  Object.defineProperty(to, key, {
4
- value: fn ? fn((from as any)[key]) : (from as any)[key],
4
+ value: fn ? fn((from as Record<PropertyKey, unknown>)[key]) : (from as Record<PropertyKey, unknown>)[key],
5
5
  enumerable: true,
6
6
  writable: true,
7
7
  configurable: true,
@@ -40,12 +40,12 @@ export function compileSchemaRegex(
40
40
  try {
41
41
  const re = new RegExp(pattern, 'u');
42
42
  return { ok: true, value: re };
43
- } catch (e: any) {
43
+ } catch (error: unknown) {
44
44
  return {
45
45
  ok: false,
46
46
  error: {
47
47
  pattern,
48
- message: e && e.message ? e.message : 'Invalid regular expression',
48
+ message: error instanceof Error ? error.message : 'Invalid regular expression',
49
49
  },
50
50
  };
51
51
  }
@@ -53,12 +53,12 @@ export function compileSchemaRegex(
53
53
  try {
54
54
  const re = new RegExp(pattern);
55
55
  return { ok: true, value: re };
56
- } catch (e: any) {
56
+ } catch (error: unknown) {
57
57
  return {
58
58
  ok: false,
59
59
  error: {
60
60
  pattern,
61
- message: e && e.message ? e.message : 'Invalid regular expression',
61
+ message: error instanceof Error ? error.message : 'Invalid regular expression',
62
62
  },
63
63
  };
64
64
  }
package/src/utils/time.ts CHANGED
@@ -32,9 +32,9 @@ export const parseRfc3339Time = (time: string): ParsedRfc3339Time | null => {
32
32
  return null;
33
33
  }
34
34
 
35
- const hour = parseInt(matches[1], 10);
36
- const minute = parseInt(matches[2], 10);
37
- const second = parseInt(matches[3], 10);
35
+ const hour = Number.parseInt(matches[1], 10);
36
+ const minute = Number.parseInt(matches[2], 10);
37
+ const second = Number.parseInt(matches[3], 10);
38
38
  if (hour > 23 || minute > 59 || second > 60) {
39
39
  return null;
40
40
  }
@@ -48,8 +48,8 @@ export const parseRfc3339Time = (time: string): ParsedRfc3339Time | null => {
48
48
  }
49
49
 
50
50
  const offsetSign = offsetMatches[1] as '+' | '-';
51
- const offsetHour = parseInt(offsetMatches[2], 10);
52
- const offsetMinute = parseInt(offsetMatches[3], 10);
51
+ const offsetHour = Number.parseInt(offsetMatches[2], 10);
52
+ const offsetMinute = Number.parseInt(offsetMatches[3], 10);
53
53
  if (offsetHour > 23 || offsetMinute > 59) {
54
54
  return null;
55
55
  }
@@ -1,12 +1,19 @@
1
1
  /**
2
2
  * Returns the number of Unicode code points in the string.
3
- * Uses the built-in string iterator which correctly handles surrogate pairs.
3
+ * Uses a surrogate-aware charCodeAt scan (equivalent to the string iterator)
4
+ * that counts a surrogate pair as one code point and lone surrogates as one each.
4
5
  */
5
6
  export function unicodeLength(str: string): number {
6
- let count = 0;
7
- for (const _cp of str) {
8
- void _cp;
9
- count++;
7
+ let count = str.length;
8
+ for (let i = 0; i < str.length - 1; i++) {
9
+ const hi = str.charCodeAt(i);
10
+ if (hi >= 0xd8_00 && hi <= 0xdb_ff) {
11
+ const lo = str.charCodeAt(i + 1);
12
+ if (lo >= 0xdc_00 && lo <= 0xdf_ff) {
13
+ count--;
14
+ i++;
15
+ }
16
+ }
10
17
  }
11
18
  return count;
12
19
  }
@@ -26,11 +26,7 @@ export const whatIs = (what: unknown): WHAT_IS => {
26
26
 
27
27
  if (typeof what === 'number') {
28
28
  if (Number.isFinite(what)) {
29
- if (what % 1 === 0) {
30
- return 'integer';
31
- } else {
32
- return 'number';
33
- }
29
+ return what % 1 === 0 ? 'integer' : 'number';
34
30
  }
35
31
  if (Number.isNaN(what)) {
36
32
  return 'not-a-number';
@@ -9,9 +9,9 @@ import { cacheValidationResult, deferOrRunSync, shouldSkipValidate } from './sha
9
9
  // additionalItems
10
10
  // ---------------------------------------------------------------------------
11
11
 
12
- export function additionalItemsValidator(this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
12
+ export function additionalItemsValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
13
13
  // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.3.1.2
14
- if (shouldSkipValidate(this.validateOptions, ['ARRAY_ADDITIONAL_ITEMS'])) {
14
+ if (shouldSkipValidate(ctx.validateOptions, ['ARRAY_ADDITIONAL_ITEMS'])) {
15
15
  return;
16
16
  }
17
17
  if (!Array.isArray(json)) {
@@ -19,10 +19,8 @@ export function additionalItemsValidator(this: ZSchemaBase, report: Report, sche
19
19
  }
20
20
  // if the value of "additionalItems" is boolean value false and the value of "items" is an array,
21
21
  // the json is valid if its size is less than, or equal to, the size of "items".
22
- if (schema.additionalItems === false && Array.isArray(schema.items)) {
23
- if (json.length > schema.items.length) {
24
- report.addError('ARRAY_ADDITIONAL_ITEMS', undefined, undefined, schema, 'additionalItems');
25
- }
22
+ if (schema.additionalItems === false && Array.isArray(schema.items) && json.length > schema.items.length) {
23
+ report.addError('ARRAY_ADDITIONAL_ITEMS', undefined, undefined, schema, 'additionalItems');
26
24
  }
27
25
  }
28
26
 
@@ -47,9 +45,9 @@ export function prefixItemsValidator() {
47
45
  // maxItems
48
46
  // ---------------------------------------------------------------------------
49
47
 
50
- export function maxItemsValidator(this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
48
+ export function maxItemsValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
51
49
  // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.3.2.2
52
- if (shouldSkipValidate(this.validateOptions, ['ARRAY_LENGTH_LONG'])) {
50
+ if (shouldSkipValidate(ctx.validateOptions, ['ARRAY_LENGTH_LONG'])) {
53
51
  return;
54
52
  }
55
53
  if (!Array.isArray(json)) {
@@ -64,9 +62,9 @@ export function maxItemsValidator(this: ZSchemaBase, report: Report, schema: Jso
64
62
  // minItems
65
63
  // ---------------------------------------------------------------------------
66
64
 
67
- export function minItemsValidator(this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
65
+ export function minItemsValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
68
66
  // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.3.3.2
69
- if (shouldSkipValidate(this.validateOptions, ['ARRAY_LENGTH_SHORT'])) {
67
+ if (shouldSkipValidate(ctx.validateOptions, ['ARRAY_LENGTH_SHORT'])) {
70
68
  return;
71
69
  }
72
70
  if (!Array.isArray(json)) {
@@ -81,9 +79,9 @@ export function minItemsValidator(this: ZSchemaBase, report: Report, schema: Jso
81
79
  // uniqueItems
82
80
  // ---------------------------------------------------------------------------
83
81
 
84
- export function uniqueItemsValidator(this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
82
+ export function uniqueItemsValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
85
83
  // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.3.4.2
86
- if (shouldSkipValidate(this.validateOptions, ['ARRAY_UNIQUE'])) {
84
+ if (shouldSkipValidate(ctx.validateOptions, ['ARRAY_UNIQUE'])) {
87
85
  return;
88
86
  }
89
87
  if (!Array.isArray(json)) {
@@ -91,7 +89,7 @@ export function uniqueItemsValidator(this: ZSchemaBase, report: Report, schema:
91
89
  }
92
90
  if (schema.uniqueItems === true) {
93
91
  const matches: any[] = [];
94
- if (isUniqueArray(json, matches, this.options.maxRecursionDepth) === false) {
92
+ if (!isUniqueArray(json, matches, ctx.options.maxRecursionDepth)) {
95
93
  report.addError('ARRAY_UNIQUE', matches, undefined, schema, 'uniqueItems');
96
94
  }
97
95
  }
@@ -101,8 +99,8 @@ export function uniqueItemsValidator(this: ZSchemaBase, report: Report, schema:
101
99
  // contains
102
100
  // ---------------------------------------------------------------------------
103
101
 
104
- export function containsValidator(this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
105
- if (shouldSkipValidate(this.validateOptions, ['CONTAINS'])) {
102
+ export function containsValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
103
+ if (shouldSkipValidate(ctx.validateOptions, ['CONTAINS'])) {
106
104
  return;
107
105
  }
108
106
 
@@ -120,19 +118,19 @@ export function containsValidator(this: ZSchemaBase, report: Report, schema: Jso
120
118
  for (let idx = 0; idx < json.length; idx++) {
121
119
  const subReport = new Report_(report);
122
120
  subReports.push(subReport);
123
- this._jsonValidate(subReport, containsSchema as any, json[idx]);
121
+ ctx._jsonValidate(subReport, containsSchema, json[idx]);
124
122
  cacheValidationResult(report, containsSchema, json[idx], subReport.errors.length === 0);
125
123
  }
126
124
 
127
125
  const addContainsErrorIfNeeded = () => {
128
126
  let matchingItems = 0;
129
- for (const subReport of subReports) {
130
- if (subReport.errors.length === 0) {
127
+ for (let i = 0; i < subReports.length; i++) {
128
+ if (subReports[i].errors.length === 0) {
131
129
  matchingItems += 1;
132
130
  }
133
131
  }
134
132
 
135
- const supportsContainsBounds = this.options.version === 'draft2019-09' || this.options.version === 'draft2020-12';
133
+ const supportsContainsBounds = ctx.options.version === 'draft2019-09' || ctx.options.version === 'draft2020-12';
136
134
  const minContains: number =
137
135
  supportsContainsBounds && typeof schema.minContains === 'number' ? (schema.minContains ?? 1) : 1;
138
136
  const maxContains =
@@ -142,7 +140,7 @@ export function containsValidator(this: ZSchemaBase, report: Report, schema: Jso
142
140
  const notTooManyMatches = maxContains === undefined || matchingItems <= maxContains;
143
141
 
144
142
  if (!hasEnoughMatches || !notTooManyMatches) {
145
- report.addError('CONTAINS', undefined, subReports, schema, undefined);
143
+ report.addError('CONTAINS', undefined, subReports, schema);
146
144
  }
147
145
  };
148
146
 
@@ -153,5 +151,9 @@ export function containsValidator(this: ZSchemaBase, report: Report, schema: Jso
153
151
  // maxContains / minContains (no-op — handled inside contains)
154
152
  // ---------------------------------------------------------------------------
155
153
 
156
- export function maxContainsValidator() {}
157
- export function minContainsValidator() {}
154
+ export function maxContainsValidator() {
155
+ // no-op: maxContains is evaluated inside the `contains` validator
156
+ }
157
+ export function minContainsValidator() {
158
+ // no-op: minContains is evaluated inside the `contains` validator
159
+ }