z-schema 12.0.4 → 12.1.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 (176) hide show
  1. package/bin/z-schema +7 -2
  2. package/cjs/index.d.ts +541 -530
  3. package/cjs/index.js +3963 -7740
  4. package/dist/errors.d.mts +64 -0
  5. package/dist/errors.mjs +67 -0
  6. package/dist/format-validators.d.mts +14 -0
  7. package/dist/format-validators.mjs +261 -0
  8. package/dist/index.d.mts +10 -0
  9. package/dist/index.mjs +7 -0
  10. package/dist/json-schema-versions.d.mts +137 -0
  11. package/dist/json-schema-versions.mjs +11 -0
  12. package/dist/json-schema.d.mts +61 -0
  13. package/dist/json-schema.mjs +53 -0
  14. package/dist/json-validation.mjs +441 -0
  15. package/dist/report.d.mts +97 -0
  16. package/dist/report.mjs +194 -0
  17. package/dist/schema-cache.d.mts +23 -0
  18. package/dist/schema-cache.mjs +144 -0
  19. package/dist/schema-compiler.d.mts +23 -0
  20. package/dist/schema-compiler.mjs +265 -0
  21. package/dist/schema-validator.d.mts +15 -0
  22. package/dist/schema-validator.mjs +446 -0
  23. package/dist/schemas/draft-04-schema.mjs +125 -0
  24. package/dist/schemas/draft-06-schema.mjs +126 -0
  25. package/dist/schemas/draft-07-schema.mjs +141 -0
  26. package/dist/schemas/draft-2019-09-meta-applicator.mjs +46 -0
  27. package/dist/schemas/draft-2019-09-meta-content.mjs +15 -0
  28. package/dist/schemas/draft-2019-09-meta-core.mjs +52 -0
  29. package/dist/schemas/draft-2019-09-meta-format.mjs +11 -0
  30. package/dist/schemas/draft-2019-09-meta-meta-data.mjs +31 -0
  31. package/dist/schemas/draft-2019-09-meta-validation.mjs +80 -0
  32. package/dist/schemas/draft-2019-09-schema.mjs +39 -0
  33. package/dist/schemas/draft-2020-12-meta-applicator.mjs +45 -0
  34. package/dist/schemas/draft-2020-12-meta-content.mjs +15 -0
  35. package/dist/schemas/draft-2020-12-meta-core.mjs +46 -0
  36. package/dist/schemas/draft-2020-12-meta-format-annotation.mjs +11 -0
  37. package/dist/schemas/draft-2020-12-meta-format-assertion.mjs +11 -0
  38. package/dist/schemas/draft-2020-12-meta-meta-data.mjs +31 -0
  39. package/dist/schemas/draft-2020-12-meta-unevaluated.mjs +14 -0
  40. package/dist/schemas/draft-2020-12-meta-validation.mjs +80 -0
  41. package/dist/schemas/draft-2020-12-schema.mjs +55 -0
  42. package/dist/utils/array.mjs +54 -0
  43. package/dist/utils/base64.mjs +21 -0
  44. package/dist/utils/clone.mjs +42 -0
  45. package/dist/utils/constants.mjs +16 -0
  46. package/dist/utils/date.mjs +19 -0
  47. package/dist/utils/hostname.mjs +73 -0
  48. package/dist/utils/json.mjs +34 -0
  49. package/dist/utils/properties.mjs +11 -0
  50. package/dist/utils/schema-regex.mjs +49 -0
  51. package/dist/utils/symbols.mjs +5 -0
  52. package/dist/utils/time.mjs +42 -0
  53. package/dist/utils/unicode.mjs +12 -0
  54. package/dist/utils/uri.mjs +12 -0
  55. package/dist/utils/what-is.mjs +23 -0
  56. package/dist/validation/array.mjs +57 -0
  57. package/dist/validation/combinators.mjs +62 -0
  58. package/dist/validation/numeric.mjs +38 -0
  59. package/dist/validation/object.mjs +109 -0
  60. package/dist/validation/ref.mjs +49 -0
  61. package/dist/validation/shared.mjs +97 -0
  62. package/dist/validation/string.mjs +88 -0
  63. package/dist/validation/type.mjs +32 -0
  64. package/dist/z-schema-base.d.mts +85 -0
  65. package/dist/z-schema-base.mjs +230 -0
  66. package/dist/z-schema-options.d.mts +35 -0
  67. package/dist/z-schema-options.mjs +55 -0
  68. package/dist/z-schema-reader.d.mts +6 -0
  69. package/dist/z-schema-reader.mjs +10 -0
  70. package/dist/z-schema-versions.mjs +67 -0
  71. package/dist/z-schema.d.mts +193 -0
  72. package/dist/z-schema.mjs +300 -0
  73. package/package.json +49 -64
  74. package/src/index.ts +3 -3
  75. package/src/schema-compiler.ts +30 -10
  76. package/src/schema-validator.ts +1 -1
  77. package/src/utils/schema-regex.ts +13 -2
  78. package/src/z-schema-base.ts +1 -1
  79. package/src/z-schema-versions.ts +1 -2
  80. package/src/z-schema.ts +0 -1
  81. package/umd/ZSchema.js +5934 -8110
  82. package/umd/ZSchema.min.js +2 -1
  83. package/dist/errors.js +0 -72
  84. package/dist/format-validators.js +0 -392
  85. package/dist/index.js +0 -5
  86. package/dist/json-schema-versions.js +0 -8
  87. package/dist/json-schema.js +0 -84
  88. package/dist/json-validation.js +0 -728
  89. package/dist/package.json +0 -3
  90. package/dist/report.js +0 -265
  91. package/dist/schema-cache.js +0 -211
  92. package/dist/schema-compiler.js +0 -415
  93. package/dist/schema-validator.js +0 -721
  94. package/dist/schemas/draft-04-schema.json +0 -149
  95. package/dist/schemas/draft-06-schema.json +0 -155
  96. package/dist/schemas/draft-07-schema.json +0 -172
  97. package/dist/schemas/draft-2019-09-meta-applicator.json +0 -52
  98. package/dist/schemas/draft-2019-09-meta-content.json +0 -12
  99. package/dist/schemas/draft-2019-09-meta-core.json +0 -53
  100. package/dist/schemas/draft-2019-09-meta-format.json +0 -10
  101. package/dist/schemas/draft-2019-09-meta-meta-data.json +0 -32
  102. package/dist/schemas/draft-2019-09-meta-validation.json +0 -94
  103. package/dist/schemas/draft-2019-09-schema.json +0 -41
  104. package/dist/schemas/draft-2020-12-meta-applicator.json +0 -44
  105. package/dist/schemas/draft-2020-12-meta-content.json +0 -12
  106. package/dist/schemas/draft-2020-12-meta-core.json +0 -47
  107. package/dist/schemas/draft-2020-12-meta-format-annotation.json +0 -10
  108. package/dist/schemas/draft-2020-12-meta-format-assertion.json +0 -10
  109. package/dist/schemas/draft-2020-12-meta-meta-data.json +0 -32
  110. package/dist/schemas/draft-2020-12-meta-unevaluated.json +0 -11
  111. package/dist/schemas/draft-2020-12-meta-validation.json +0 -94
  112. package/dist/schemas/draft-2020-12-schema.json +0 -57
  113. package/dist/types/errors.d.ts +0 -64
  114. package/dist/types/format-validators.d.ts +0 -11
  115. package/dist/types/index.d.ts +0 -14
  116. package/dist/types/json-schema-versions.d.ts +0 -142
  117. package/dist/types/json-schema.d.ts +0 -66
  118. package/dist/types/json-validation.d.ts +0 -6
  119. package/dist/types/report.d.ts +0 -94
  120. package/dist/types/schema-cache.d.ts +0 -27
  121. package/dist/types/schema-compiler.d.ts +0 -31
  122. package/dist/types/schema-validator.d.ts +0 -10
  123. package/dist/types/utils/array.d.ts +0 -9
  124. package/dist/types/utils/base64.d.ts +0 -2
  125. package/dist/types/utils/clone.d.ts +0 -2
  126. package/dist/types/utils/constants.d.ts +0 -19
  127. package/dist/types/utils/date.d.ts +0 -1
  128. package/dist/types/utils/hostname.d.ts +0 -2
  129. package/dist/types/utils/json.d.ts +0 -9
  130. package/dist/types/utils/properties.d.ts +0 -1
  131. package/dist/types/utils/schema-regex.d.ts +0 -10
  132. package/dist/types/utils/symbols.d.ts +0 -2
  133. package/dist/types/utils/time.d.ts +0 -12
  134. package/dist/types/utils/unicode.d.ts +0 -5
  135. package/dist/types/utils/uri.d.ts +0 -4
  136. package/dist/types/utils/what-is.d.ts +0 -4
  137. package/dist/types/validation/array.d.ts +0 -12
  138. package/dist/types/validation/combinators.d.ts +0 -10
  139. package/dist/types/validation/numeric.d.ts +0 -8
  140. package/dist/types/validation/object.d.ts +0 -13
  141. package/dist/types/validation/ref.d.ts +0 -11
  142. package/dist/types/validation/shared.d.ts +0 -26
  143. package/dist/types/validation/string.d.ts +0 -9
  144. package/dist/types/validation/type.d.ts +0 -6
  145. package/dist/types/z-schema-base.d.ts +0 -87
  146. package/dist/types/z-schema-options.d.ts +0 -35
  147. package/dist/types/z-schema-reader.d.ts +0 -4
  148. package/dist/types/z-schema-versions.d.ts +0 -1
  149. package/dist/types/z-schema.d.ts +0 -191
  150. package/dist/utils/array.js +0 -69
  151. package/dist/utils/base64.js +0 -29
  152. package/dist/utils/clone.js +0 -59
  153. package/dist/utils/constants.js +0 -19
  154. package/dist/utils/date.js +0 -21
  155. package/dist/utils/hostname.js +0 -146
  156. package/dist/utils/json.js +0 -70
  157. package/dist/utils/properties.js +0 -10
  158. package/dist/utils/schema-regex.js +0 -52
  159. package/dist/utils/symbols.js +0 -2
  160. package/dist/utils/time.js +0 -50
  161. package/dist/utils/unicode.js +0 -12
  162. package/dist/utils/uri.js +0 -15
  163. package/dist/utils/what-is.js +0 -32
  164. package/dist/validation/array.js +0 -127
  165. package/dist/validation/combinators.js +0 -106
  166. package/dist/validation/numeric.js +0 -97
  167. package/dist/validation/object.js +0 -237
  168. package/dist/validation/ref.js +0 -70
  169. package/dist/validation/shared.js +0 -136
  170. package/dist/validation/string.js +0 -170
  171. package/dist/validation/type.js +0 -55
  172. package/dist/z-schema-base.js +0 -286
  173. package/dist/z-schema-options.js +0 -99
  174. package/dist/z-schema-reader.js +0 -7
  175. package/dist/z-schema-versions.js +0 -110
  176. package/dist/z-schema.js +0 -287
@@ -0,0 +1,11 @@
1
+ //#region src/schemas/draft-2020-12-meta-format-assertion.json
2
+ var draft_2020_12_meta_format_assertion_default = {
3
+ $schema: "https://json-schema.org/draft/2020-12/schema",
4
+ $id: "https://json-schema.org/draft/2020-12/meta/format-assertion",
5
+ $dynamicAnchor: "meta",
6
+ title: "Format vocabulary meta-schema for assertion results",
7
+ type: ["object", "boolean"],
8
+ properties: { "format": { "type": "string" } }
9
+ };
10
+ //#endregion
11
+ export { draft_2020_12_meta_format_assertion_default as default };
@@ -0,0 +1,31 @@
1
+ //#region src/schemas/draft-2020-12-meta-meta-data.json
2
+ var draft_2020_12_meta_meta_data_default = {
3
+ $schema: "https://json-schema.org/draft/2020-12/schema",
4
+ $id: "https://json-schema.org/draft/2020-12/meta/meta-data",
5
+ $dynamicAnchor: "meta",
6
+ title: "Meta-data vocabulary meta-schema",
7
+ type: ["object", "boolean"],
8
+ properties: {
9
+ "title": { "type": "string" },
10
+ "description": { "type": "string" },
11
+ "default": true,
12
+ "deprecated": {
13
+ "type": "boolean",
14
+ "default": false
15
+ },
16
+ "readOnly": {
17
+ "type": "boolean",
18
+ "default": false
19
+ },
20
+ "writeOnly": {
21
+ "type": "boolean",
22
+ "default": false
23
+ },
24
+ "examples": {
25
+ "type": "array",
26
+ "items": true
27
+ }
28
+ }
29
+ };
30
+ //#endregion
31
+ export { draft_2020_12_meta_meta_data_default as default };
@@ -0,0 +1,14 @@
1
+ //#region src/schemas/draft-2020-12-meta-unevaluated.json
2
+ var draft_2020_12_meta_unevaluated_default = {
3
+ $schema: "https://json-schema.org/draft/2020-12/schema",
4
+ $id: "https://json-schema.org/draft/2020-12/meta/unevaluated",
5
+ $dynamicAnchor: "meta",
6
+ title: "Unevaluated applicator vocabulary meta-schema",
7
+ type: ["object", "boolean"],
8
+ properties: {
9
+ "unevaluatedItems": { "$dynamicRef": "#meta" },
10
+ "unevaluatedProperties": { "$dynamicRef": "#meta" }
11
+ }
12
+ };
13
+ //#endregion
14
+ export { draft_2020_12_meta_unevaluated_default as default };
@@ -0,0 +1,80 @@
1
+ //#region src/schemas/draft-2020-12-meta-validation.json
2
+ var draft_2020_12_meta_validation_default = {
3
+ $schema: "https://json-schema.org/draft/2020-12/schema",
4
+ $id: "https://json-schema.org/draft/2020-12/meta/validation",
5
+ $dynamicAnchor: "meta",
6
+ title: "Validation vocabulary meta-schema",
7
+ type: ["object", "boolean"],
8
+ properties: {
9
+ "type": { "anyOf": [{ "$ref": "#/$defs/simpleTypes" }, {
10
+ "type": "array",
11
+ "items": { "$ref": "#/$defs/simpleTypes" },
12
+ "minItems": 1,
13
+ "uniqueItems": true
14
+ }] },
15
+ "const": true,
16
+ "enum": {
17
+ "type": "array",
18
+ "items": true
19
+ },
20
+ "multipleOf": {
21
+ "type": "number",
22
+ "exclusiveMinimum": 0
23
+ },
24
+ "maximum": { "type": "number" },
25
+ "exclusiveMaximum": { "type": "number" },
26
+ "minimum": { "type": "number" },
27
+ "exclusiveMinimum": { "type": "number" },
28
+ "maxLength": { "$ref": "#/$defs/nonNegativeInteger" },
29
+ "minLength": { "$ref": "#/$defs/nonNegativeIntegerDefault0" },
30
+ "pattern": {
31
+ "type": "string",
32
+ "format": "regex"
33
+ },
34
+ "maxItems": { "$ref": "#/$defs/nonNegativeInteger" },
35
+ "minItems": { "$ref": "#/$defs/nonNegativeIntegerDefault0" },
36
+ "uniqueItems": {
37
+ "type": "boolean",
38
+ "default": false
39
+ },
40
+ "maxContains": { "$ref": "#/$defs/nonNegativeInteger" },
41
+ "minContains": {
42
+ "$ref": "#/$defs/nonNegativeInteger",
43
+ "default": 1
44
+ },
45
+ "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" },
46
+ "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" },
47
+ "required": { "$ref": "#/$defs/stringArray" },
48
+ "dependentRequired": {
49
+ "type": "object",
50
+ "additionalProperties": { "$ref": "#/$defs/stringArray" }
51
+ }
52
+ },
53
+ $defs: {
54
+ "nonNegativeInteger": {
55
+ "type": "integer",
56
+ "minimum": 0
57
+ },
58
+ "nonNegativeIntegerDefault0": {
59
+ "$ref": "#/$defs/nonNegativeInteger",
60
+ "default": 0
61
+ },
62
+ "simpleTypes": { "enum": [
63
+ "array",
64
+ "boolean",
65
+ "integer",
66
+ "null",
67
+ "number",
68
+ "object",
69
+ "string"
70
+ ] },
71
+ "stringArray": {
72
+ "type": "array",
73
+ "items": { "type": "string" },
74
+ "uniqueItems": true,
75
+ "default": []
76
+ }
77
+ }
78
+ };
79
+ //#endregion
80
+ export { draft_2020_12_meta_validation_default as default };
@@ -0,0 +1,55 @@
1
+ //#region src/schemas/draft-2020-12-schema.json
2
+ var draft_2020_12_schema_default = {
3
+ $schema: "https://json-schema.org/draft/2020-12/schema",
4
+ $id: "https://json-schema.org/draft/2020-12/schema",
5
+ $vocabulary: {
6
+ "https://json-schema.org/draft/2020-12/vocab/core": true,
7
+ "https://json-schema.org/draft/2020-12/vocab/applicator": true,
8
+ "https://json-schema.org/draft/2020-12/vocab/unevaluated": true,
9
+ "https://json-schema.org/draft/2020-12/vocab/validation": true,
10
+ "https://json-schema.org/draft/2020-12/vocab/meta-data": true,
11
+ "https://json-schema.org/draft/2020-12/vocab/format-annotation": true,
12
+ "https://json-schema.org/draft/2020-12/vocab/content": true
13
+ },
14
+ $dynamicAnchor: "meta",
15
+ title: "Core and Validation specifications meta-schema",
16
+ allOf: [
17
+ { "$ref": "meta/core" },
18
+ { "$ref": "meta/applicator" },
19
+ { "$ref": "meta/unevaluated" },
20
+ { "$ref": "meta/validation" },
21
+ { "$ref": "meta/meta-data" },
22
+ { "$ref": "meta/format-annotation" },
23
+ { "$ref": "meta/content" }
24
+ ],
25
+ type: ["object", "boolean"],
26
+ $comment: "This meta-schema also defines keywords that have appeared in previous drafts in order to prevent incompatible extensions as they remain in common use.",
27
+ properties: {
28
+ "definitions": {
29
+ "$comment": "\"definitions\" has been replaced by \"$defs\".",
30
+ "type": "object",
31
+ "additionalProperties": { "$dynamicRef": "#meta" },
32
+ "deprecated": true,
33
+ "default": {}
34
+ },
35
+ "dependencies": {
36
+ "$comment": "\"dependencies\" has been split and replaced by \"dependentSchemas\" and \"dependentRequired\" in order to serve their differing semantics.",
37
+ "type": "object",
38
+ "additionalProperties": { "anyOf": [{ "$dynamicRef": "#meta" }, { "$ref": "meta/validation#/$defs/stringArray" }] },
39
+ "deprecated": true,
40
+ "default": {}
41
+ },
42
+ "$recursiveAnchor": {
43
+ "$comment": "\"$recursiveAnchor\" has been replaced by \"$dynamicAnchor\".",
44
+ "$ref": "meta/core#/$defs/anchorString",
45
+ "deprecated": true
46
+ },
47
+ "$recursiveRef": {
48
+ "$comment": "\"$recursiveRef\" has been replaced by \"$dynamicRef\".",
49
+ "$ref": "meta/core#/$defs/uriReferenceString",
50
+ "deprecated": true
51
+ }
52
+ }
53
+ };
54
+ //#endregion
55
+ export { draft_2020_12_schema_default as default };
@@ -0,0 +1,54 @@
1
+ import { areEqual } from "./json.mjs";
2
+ //#region src/utils/array.ts
3
+ /**
4
+ * Check if all elements in an array are unique.
5
+ *
6
+ * Uses a Set-based fast path for arrays of pure primitives (O(n)).
7
+ * Falls back to pairwise deep comparison (O(n²)) when the array contains
8
+ * objects or arrays that need structural equality checks.
9
+ */
10
+ const isUniqueArray = (arr, indexes, maxDepth) => {
11
+ const l = arr.length;
12
+ if (l <= 1) return true;
13
+ let allPrimitive = true;
14
+ for (let i = 0; i < l; i++) {
15
+ const v = arr[i];
16
+ if (v !== null && typeof v === "object") {
17
+ allPrimitive = false;
18
+ break;
19
+ }
20
+ }
21
+ if (allPrimitive) {
22
+ const seen = /* @__PURE__ */ new Set();
23
+ for (let i = 0; i < l; i++) {
24
+ const v = arr[i];
25
+ const key = typeof v + ":" + String(v);
26
+ if (seen.has(key)) {
27
+ if (indexes) for (let j = 0; j < i; j++) {
28
+ const prev = arr[j];
29
+ if (typeof prev === typeof v && prev === v) {
30
+ indexes.push(j, i);
31
+ break;
32
+ }
33
+ }
34
+ return false;
35
+ }
36
+ seen.add(key);
37
+ }
38
+ return true;
39
+ }
40
+ for (let i = 0; i < l; i++) for (let j = i + 1; j < l; j++) if (areEqual(arr[i], arr[j], { maxDepth })) {
41
+ if (indexes) indexes.push(i, j);
42
+ return false;
43
+ }
44
+ return true;
45
+ };
46
+ const difference = (bigSet, subSet) => {
47
+ const exclusions = new Set(subSet);
48
+ const arr = [];
49
+ let idx = bigSet.length;
50
+ while (idx--) if (!exclusions.has(bigSet[idx])) arr.push(bigSet[idx]);
51
+ return arr;
52
+ };
53
+ //#endregion
54
+ export { difference, isUniqueArray };
@@ -0,0 +1,21 @@
1
+ //#region src/utils/base64.ts
2
+ const base64Pattern = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
3
+ const isValidBase64 = (value) => {
4
+ if (value.length % 4 !== 0) return false;
5
+ return base64Pattern.test(value);
6
+ };
7
+ const decodeBase64 = (value) => {
8
+ if (!isValidBase64(value)) return;
9
+ if (typeof atob === "function") try {
10
+ return atob(value);
11
+ } catch {
12
+ return;
13
+ }
14
+ if (typeof Buffer !== "undefined") try {
15
+ return Buffer.from(value, "base64").toString("utf8");
16
+ } catch {
17
+ return;
18
+ }
19
+ };
20
+ //#endregion
21
+ export { decodeBase64, isValidBase64 };
@@ -0,0 +1,42 @@
1
+ import { copyProp } from "./properties.mjs";
2
+ //#region src/utils/clone.ts
3
+ const shallowClone = (src) => {
4
+ if (src == null || typeof src !== "object") return src;
5
+ let res;
6
+ if (Array.isArray(src)) {
7
+ res = [];
8
+ for (let i = 0; i < src.length; i++) res[i] = src[i];
9
+ } else {
10
+ res = {};
11
+ const keys = Object.keys(src).sort();
12
+ for (const key of keys) copyProp(src, res, key);
13
+ }
14
+ return res;
15
+ };
16
+ const deepClone = (src, maxDepth = 100) => {
17
+ let vidx = 0;
18
+ const visited = /* @__PURE__ */ new Map();
19
+ const cloned = [];
20
+ const cloneDeepInner = (src, _depth) => {
21
+ if (typeof src !== "object" || src === null) return src;
22
+ if (_depth >= maxDepth) throw new Error(`Maximum recursion depth (${maxDepth}) exceeded in deepClone. If your schema or data is deeply nested and valid, increase the maxRecursionDepth option.`);
23
+ let res;
24
+ const cidx = visited.get(src);
25
+ if (cidx !== void 0) return cloned[cidx];
26
+ visited.set(src, vidx++);
27
+ if (Array.isArray(src)) {
28
+ res = [];
29
+ cloned.push(res);
30
+ for (let i = 0; i < src.length; i++) res[i] = cloneDeepInner(src[i], _depth + 1);
31
+ } else {
32
+ res = {};
33
+ cloned.push(res);
34
+ const keys = Object.keys(src).sort();
35
+ for (const key of keys) copyProp(src, res, key, (v) => cloneDeepInner(v, _depth + 1));
36
+ }
37
+ return res;
38
+ };
39
+ return cloneDeepInner(src, 0);
40
+ };
41
+ //#endregion
42
+ export { deepClone, shallowClone };
@@ -0,0 +1,16 @@
1
+ //#region src/utils/constants.ts
2
+ /**
3
+ * Maximum allowed value for {@link ZSchemaOptions.asyncTimeout} in milliseconds.
4
+ * Values exceeding this limit are clamped during option normalization to
5
+ * prevent resource exhaustion (CWE-400).
6
+ */
7
+ const MAX_ASYNC_TIMEOUT = 6e4;
8
+ /**
9
+ * Maximum allowed length for a JSON Schema `pattern` regular expression string.
10
+ * Patterns exceeding this limit are rejected by {@link compileSchemaRegex} to
11
+ * mitigate Regular Expression Denial-of-Service (CWE-1333) and regex injection
12
+ * (CWE-95).
13
+ */
14
+ const MAX_SCHEMA_REGEX_LENGTH = 1e4;
15
+ //#endregion
16
+ export { MAX_ASYNC_TIMEOUT, MAX_SCHEMA_REGEX_LENGTH };
@@ -0,0 +1,19 @@
1
+ //#region src/utils/date.ts
2
+ const isLeapYear = (year) => year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
3
+ const getDaysInMonth = (year, month) => {
4
+ switch (month) {
5
+ case 2: return isLeapYear(year) ? 29 : 28;
6
+ case 4:
7
+ case 6:
8
+ case 9:
9
+ case 11: return 30;
10
+ default: return 31;
11
+ }
12
+ };
13
+ const isValidRfc3339Date = (year, month, day) => {
14
+ if (month < 1 || month > 12) return false;
15
+ const maxDay = getDaysInMonth(year, month);
16
+ return day >= 1 && day <= maxDay;
17
+ };
18
+ //#endregion
19
+ export { isValidRfc3339Date };
@@ -0,0 +1,73 @@
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 splitHostnameLabels = (hostname) => {
7
+ if (hostname.length === 0 || hostname.length > 255) return null;
8
+ if (hostname.startsWith(".") || hostname.endsWith(".")) return null;
9
+ const labels = hostname.split(".");
10
+ if (labels.some((label) => label.length === 0 || label.length > 63)) return null;
11
+ return labels;
12
+ };
13
+ const isAsciiHostnameLabel = (label) => /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(label);
14
+ const isGreek = (char) => /\p{Script=Greek}/u.test(char);
15
+ const isHebrew = (char) => /\p{Script=Hebrew}/u.test(char);
16
+ const hasCjkKanaOrHan = (input) => /[\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Han}]/u.test(input);
17
+ const toUnicodeLabel = (label) => {
18
+ if (!/^xn--/i.test(label)) return label;
19
+ try {
20
+ return punycode.toUnicode(label.toLowerCase());
21
+ } catch (_e) {
22
+ return null;
23
+ }
24
+ };
25
+ const isValidIdnUnicodeLabel = (label) => {
26
+ if (label.startsWith("-") || label.endsWith("-")) return false;
27
+ if (label.length >= 4 && label[2] === "-" && label[3] === "-" && !/^xn--/i.test(label)) return false;
28
+ if (/^\p{M}/u.test(label)) return false;
29
+ if (/[\u302e\u302f\u0640\u07fa]/u.test(label)) return false;
30
+ for (let idx = 0; idx < label.length; idx++) {
31
+ const char = label[idx];
32
+ if (char === "·") {
33
+ if (idx === 0 || idx === label.length - 1 || label[idx - 1] !== "l" || label[idx + 1] !== "l") return false;
34
+ }
35
+ if (char === "͵") {
36
+ if (idx === label.length - 1 || !isGreek(label[idx + 1])) return false;
37
+ }
38
+ if (char === "׳" || char === "״") {
39
+ if (idx === 0 || !isHebrew(label[idx - 1])) return false;
40
+ }
41
+ if (char === "‍") {
42
+ if (idx === 0 || label[idx - 1] !== "्") return false;
43
+ }
44
+ }
45
+ if (label.includes("・") && !hasCjkKanaOrHan(label.replace(/\u30fb/g, ""))) return false;
46
+ const hasArabicIndic = /[\u0660-\u0669]/.test(label);
47
+ const hasExtendedArabicIndic = /[\u06f0-\u06f9]/.test(label);
48
+ if (hasArabicIndic && hasExtendedArabicIndic) return false;
49
+ return true;
50
+ };
51
+ const isValidHostname = (hostname) => {
52
+ if (IDN_SEPARATOR_TEST_REGEX.test(hostname) || /[^\x00-\x7F]/.test(hostname)) return false;
53
+ if (isIPModule.default(hostname, 4)) return false;
54
+ const labels = splitHostnameLabels(hostname);
55
+ if (labels === null) return false;
56
+ for (const label of labels) {
57
+ if (!isAsciiHostnameLabel(label)) return false;
58
+ const unicodeLabel = toUnicodeLabel(label);
59
+ if (unicodeLabel === null || !isValidIdnUnicodeLabel(unicodeLabel)) return false;
60
+ }
61
+ return true;
62
+ };
63
+ const isValidIdnHostname = (hostname) => {
64
+ const labels = splitHostnameLabels(hostname.replace(IDN_SEPARATOR_REGEX, "."));
65
+ if (labels === null) return false;
66
+ for (const label of labels) {
67
+ const unicodeLabel = toUnicodeLabel(label);
68
+ if (unicodeLabel === null || !isValidIdnUnicodeLabel(unicodeLabel)) return false;
69
+ }
70
+ return true;
71
+ };
72
+ //#endregion
73
+ export { isValidHostname, isValidIdnHostname };
@@ -0,0 +1,34 @@
1
+ import { isObject } from "./what-is.mjs";
2
+ //#region src/utils/json.ts
3
+ const areEqual = (json1, json2, options, _depth = 0) => {
4
+ const caseInsensitiveComparison = options?.caseInsensitiveComparison || false;
5
+ const maxDepth = options?.maxDepth ?? 100;
6
+ if (json1 === json2) return true;
7
+ if (caseInsensitiveComparison === true && typeof json1 === "string" && typeof json2 === "string" && json1.toUpperCase() === json2.toUpperCase()) return true;
8
+ 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
+ let i, len;
10
+ if (Array.isArray(json1) && Array.isArray(json2)) {
11
+ if (json1.length !== json2.length) return false;
12
+ len = json1.length;
13
+ for (i = 0; i < len; i++) if (!areEqual(json1[i], json2[i], options, _depth + 1)) return false;
14
+ return true;
15
+ }
16
+ if (isObject(json1) && isObject(json2)) {
17
+ const keys1 = sortedKeys(json1);
18
+ if (!areEqual(keys1, sortedKeys(json2), options, _depth + 1)) return false;
19
+ len = keys1.length;
20
+ for (i = 0; i < len; i++) if (!areEqual(json1[keys1[i]], json2[keys1[i]], options, _depth + 1)) return false;
21
+ return true;
22
+ }
23
+ return false;
24
+ };
25
+ const decodeJSONPointer = (str) => {
26
+ return decodeURIComponent(str).replace(/~[0-1]/g, (x) => x === "~1" ? "/" : "~");
27
+ };
28
+ const sortedKeys = (obj) => Object.keys(obj).sort();
29
+ const get = (obj, path) => {
30
+ if (typeof path === "string") path = path.split(".");
31
+ return path.reduce((acc, key) => acc && acc[key] !== void 0 ? acc[key] : void 0, obj);
32
+ };
33
+ //#endregion
34
+ export { areEqual, decodeJSONPointer, get, sortedKeys };
@@ -0,0 +1,11 @@
1
+ //#region src/utils/properties.ts
2
+ function copyProp(from, to, key, fn) {
3
+ if (Object.hasOwn(from, key)) Object.defineProperty(to, key, {
4
+ value: fn ? fn(from[key]) : from[key],
5
+ enumerable: true,
6
+ writable: true,
7
+ configurable: true
8
+ });
9
+ }
10
+ //#endregion
11
+ export { copyProp };
@@ -0,0 +1,49 @@
1
+ import { MAX_SCHEMA_REGEX_LENGTH } from "./constants.mjs";
2
+ import isSafeRegex from "safe-regex2";
3
+ //#region src/utils/schema-regex.ts
4
+ function compileSchemaRegex(pattern) {
5
+ if (pattern.length > 1e4) return {
6
+ ok: false,
7
+ error: {
8
+ pattern,
9
+ message: `Pattern length ${pattern.length} exceeds maximum allowed length of ${MAX_SCHEMA_REGEX_LENGTH}`
10
+ }
11
+ };
12
+ if (!isSafeRegex(pattern)) return {
13
+ ok: false,
14
+ error: {
15
+ pattern,
16
+ message: "Pattern rejected as potentially unsafe (ReDoS)"
17
+ }
18
+ };
19
+ if (/\\[pP]{/.test(pattern) || /[\u{10000}-\u{10FFFF}]/u.test(pattern) || /\\uD[89AB][0-9A-Fa-f]{2}\\uD[CDEF][0-9A-Fa-f]{2}/.test(pattern)) try {
20
+ return {
21
+ ok: true,
22
+ value: new RegExp(pattern, "u")
23
+ };
24
+ } catch (e) {
25
+ return {
26
+ ok: false,
27
+ error: {
28
+ pattern,
29
+ message: e && e.message ? e.message : "Invalid regular expression"
30
+ }
31
+ };
32
+ }
33
+ else try {
34
+ return {
35
+ ok: true,
36
+ value: new RegExp(pattern)
37
+ };
38
+ } catch (e) {
39
+ return {
40
+ ok: false,
41
+ error: {
42
+ pattern,
43
+ message: e && e.message ? e.message : "Invalid regular expression"
44
+ }
45
+ };
46
+ }
47
+ }
48
+ //#endregion
49
+ export { compileSchemaRegex };
@@ -0,0 +1,5 @@
1
+ //#region src/utils/symbols.ts
2
+ const jsonSymbol = Symbol.for("z-schema/json");
3
+ const schemaSymbol = Symbol.for("z-schema/schema");
4
+ //#endregion
5
+ export { jsonSymbol, schemaSymbol };
@@ -0,0 +1,42 @@
1
+ //#region src/utils/time.ts
2
+ const toUtcTime = (hour, minute, offsetSign, offsetHour, offsetMinute) => {
3
+ const localTotalMinutes = hour * 60 + minute;
4
+ const offsetTotalMinutes = offsetHour * 60 + offsetMinute;
5
+ const normalizedUtcTotalMinutes = ((offsetSign === "+" ? localTotalMinutes - offsetTotalMinutes : localTotalMinutes + offsetTotalMinutes) % 1440 + 1440) % 1440;
6
+ return {
7
+ hour: Math.floor(normalizedUtcTotalMinutes / 60),
8
+ minute: normalizedUtcTotalMinutes % 60
9
+ };
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;
12
+ const parseRfc3339Time = (time) => {
13
+ const matches = RFC3339_TIME_REGEX.exec(time);
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);
18
+ if (hour > 23 || minute > 59 || second > 60) return null;
19
+ let utcHour = hour;
20
+ let utcMinute = minute;
21
+ if (matches[5].toLowerCase() !== "z") {
22
+ const offsetMatches = /^([+-])([0-9]{2}):([0-9]{2})$/.exec(matches[5]);
23
+ if (offsetMatches === null) return null;
24
+ const offsetSign = offsetMatches[1];
25
+ const offsetHour = parseInt(offsetMatches[2], 10);
26
+ const offsetMinute = parseInt(offsetMatches[3], 10);
27
+ if (offsetHour > 23 || offsetMinute > 59) return null;
28
+ const utc = toUtcTime(hour, minute, offsetSign, offsetHour, offsetMinute);
29
+ utcHour = utc.hour;
30
+ utcMinute = utc.minute;
31
+ }
32
+ if (second === 60 && (utcHour !== 23 || utcMinute !== 59)) return null;
33
+ return {
34
+ hour,
35
+ minute,
36
+ second,
37
+ utcHour,
38
+ utcMinute
39
+ };
40
+ };
41
+ //#endregion
42
+ export { parseRfc3339Time };
@@ -0,0 +1,12 @@
1
+ //#region src/utils/unicode.ts
2
+ /**
3
+ * Returns the number of Unicode code points in the string.
4
+ * Uses the built-in string iterator which correctly handles surrogate pairs.
5
+ */
6
+ function unicodeLength(str) {
7
+ let count = 0;
8
+ for (const _cp of str) count++;
9
+ return count;
10
+ }
11
+ //#endregion
12
+ export { unicodeLength };
@@ -0,0 +1,12 @@
1
+ //#region src/utils/uri.ts
2
+ const getQueryPath = (uri) => {
3
+ const io = uri.indexOf("#");
4
+ return io === -1 ? void 0 : uri.slice(io + 1);
5
+ };
6
+ const getRemotePath = (uri) => {
7
+ const io = uri.indexOf("#");
8
+ return io === -1 ? uri : uri.slice(0, io);
9
+ };
10
+ const isAbsoluteUri = (uri) => /^[a-zA-Z][a-zA-Z\d+.-]*:/.test(uri);
11
+ //#endregion
12
+ export { getQueryPath, getRemotePath, isAbsoluteUri };
@@ -0,0 +1,23 @@
1
+ //#region src/utils/what-is.ts
2
+ const whatIs = (what) => {
3
+ if (typeof what === "object") {
4
+ if (what === null) return "null";
5
+ if (Array.isArray(what)) return "array";
6
+ return "object";
7
+ }
8
+ if (typeof what === "number") {
9
+ if (Number.isFinite(what)) if (what % 1 === 0) return "integer";
10
+ else return "number";
11
+ if (Number.isNaN(what)) return "not-a-number";
12
+ return "unknown-number";
13
+ }
14
+ return typeof what;
15
+ };
16
+ function isObject(value) {
17
+ return typeof value === "object" && value !== null && !Array.isArray(value);
18
+ }
19
+ function isInteger(value) {
20
+ return typeof value === "number" && Number.isFinite(value) && value % 1 === 0;
21
+ }
22
+ //#endregion
23
+ export { isInteger, isObject, whatIs };