@json-schema-engine/core 0.0.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 (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +50 -0
  3. package/dist/coverage.d.ts +30 -0
  4. package/dist/coverage.d.ts.map +1 -0
  5. package/dist/coverage.js +81 -0
  6. package/dist/coverage.js.map +1 -0
  7. package/dist/cursor.d.ts +16 -0
  8. package/dist/cursor.d.ts.map +1 -0
  9. package/dist/cursor.js +28 -0
  10. package/dist/cursor.js.map +1 -0
  11. package/dist/dialect.d.ts +316 -0
  12. package/dist/dialect.d.ts.map +1 -0
  13. package/dist/dialect.js +135 -0
  14. package/dist/dialect.js.map +1 -0
  15. package/dist/engine.d.ts +203 -0
  16. package/dist/engine.d.ts.map +1 -0
  17. package/dist/engine.js +493 -0
  18. package/dist/engine.js.map +1 -0
  19. package/dist/index.d.ts +182 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +370 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/json.d.ts +49 -0
  24. package/dist/json.d.ts.map +1 -0
  25. package/dist/json.js +128 -0
  26. package/dist/json.js.map +1 -0
  27. package/dist/keywords/applicator.d.ts +57 -0
  28. package/dist/keywords/applicator.d.ts.map +1 -0
  29. package/dist/keywords/applicator.js +789 -0
  30. package/dist/keywords/applicator.js.map +1 -0
  31. package/dist/keywords/core.d.ts +42 -0
  32. package/dist/keywords/core.d.ts.map +1 -0
  33. package/dist/keywords/core.js +139 -0
  34. package/dist/keywords/core.js.map +1 -0
  35. package/dist/keywords/format.d.ts +43 -0
  36. package/dist/keywords/format.d.ts.map +1 -0
  37. package/dist/keywords/format.js +101 -0
  38. package/dist/keywords/format.js.map +1 -0
  39. package/dist/keywords/metaschemas2019.d.ts +3 -0
  40. package/dist/keywords/metaschemas2019.d.ts.map +1 -0
  41. package/dist/keywords/metaschemas2019.js +406 -0
  42. package/dist/keywords/metaschemas2019.js.map +1 -0
  43. package/dist/keywords/metaschemas2020.d.ts +3 -0
  44. package/dist/keywords/metaschemas2020.d.ts.map +1 -0
  45. package/dist/keywords/metaschemas2020.js +441 -0
  46. package/dist/keywords/metaschemas2020.js.map +1 -0
  47. package/dist/keywords/metaschemas6.d.ts +3 -0
  48. package/dist/keywords/metaschemas6.d.ts.map +1 -0
  49. package/dist/keywords/metaschemas6.js +221 -0
  50. package/dist/keywords/metaschemas6.js.map +1 -0
  51. package/dist/keywords/metaschemas7.d.ts +3 -0
  52. package/dist/keywords/metaschemas7.d.ts.map +1 -0
  53. package/dist/keywords/metaschemas7.js +248 -0
  54. package/dist/keywords/metaschemas7.js.map +1 -0
  55. package/dist/keywords/unevaluated.d.ts +14 -0
  56. package/dist/keywords/unevaluated.d.ts.map +1 -0
  57. package/dist/keywords/unevaluated.js +296 -0
  58. package/dist/keywords/unevaluated.js.map +1 -0
  59. package/dist/keywords/validation.d.ts +21 -0
  60. package/dist/keywords/validation.d.ts.map +1 -0
  61. package/dist/keywords/validation.js +332 -0
  62. package/dist/keywords/validation.js.map +1 -0
  63. package/dist/keywords/vocab2019.d.ts +36 -0
  64. package/dist/keywords/vocab2019.d.ts.map +1 -0
  65. package/dist/keywords/vocab2019.js +585 -0
  66. package/dist/keywords/vocab2019.js.map +1 -0
  67. package/dist/keywords/vocab2020.d.ts +20 -0
  68. package/dist/keywords/vocab2020.d.ts.map +1 -0
  69. package/dist/keywords/vocab2020.js +55 -0
  70. package/dist/keywords/vocab2020.js.map +1 -0
  71. package/dist/keywords/vocab7.d.ts +46 -0
  72. package/dist/keywords/vocab7.d.ts.map +1 -0
  73. package/dist/keywords/vocab7.js +305 -0
  74. package/dist/keywords/vocab7.js.map +1 -0
  75. package/dist/loader.d.ts +41 -0
  76. package/dist/loader.d.ts.map +1 -0
  77. package/dist/loader.js +13 -0
  78. package/dist/loader.js.map +1 -0
  79. package/dist/lowering.d.ts +371 -0
  80. package/dist/lowering.d.ts.map +1 -0
  81. package/dist/lowering.js +59 -0
  82. package/dist/lowering.js.map +1 -0
  83. package/dist/output.d.ts +251 -0
  84. package/dist/output.d.ts.map +1 -0
  85. package/dist/output.js +357 -0
  86. package/dist/output.js.map +1 -0
  87. package/dist/records.d.ts +71 -0
  88. package/dist/records.d.ts.map +1 -0
  89. package/dist/records.js +150 -0
  90. package/dist/records.js.map +1 -0
  91. package/dist/ref.d.ts +10 -0
  92. package/dist/ref.d.ts.map +1 -0
  93. package/dist/ref.js +5 -0
  94. package/dist/ref.js.map +1 -0
  95. package/dist/regex.d.ts +45 -0
  96. package/dist/regex.d.ts.map +1 -0
  97. package/dist/regex.js +163 -0
  98. package/dist/regex.js.map +1 -0
  99. package/dist/registry.d.ts +141 -0
  100. package/dist/registry.d.ts.map +1 -0
  101. package/dist/registry.js +407 -0
  102. package/dist/registry.js.map +1 -0
  103. package/dist/result.d.ts +109 -0
  104. package/dist/result.d.ts.map +1 -0
  105. package/dist/result.js +112 -0
  106. package/dist/result.js.map +1 -0
  107. package/dist/uri.d.ts +18 -0
  108. package/dist/uri.d.ts.map +1 -0
  109. package/dist/uri.js +27 -0
  110. package/dist/uri.js.map +1 -0
  111. package/dist/walk.d.ts +25 -0
  112. package/dist/walk.d.ts.map +1 -0
  113. package/dist/walk.js +65 -0
  114. package/dist/walk.js.map +1 -0
  115. package/package.json +32 -0
  116. package/src/coverage.ts +88 -0
  117. package/src/cursor.ts +42 -0
  118. package/src/dialect.ts +428 -0
  119. package/src/engine.ts +741 -0
  120. package/src/index.ts +699 -0
  121. package/src/json.ts +137 -0
  122. package/src/keywords/applicator.ts +895 -0
  123. package/src/keywords/core.ts +168 -0
  124. package/src/keywords/format.ts +143 -0
  125. package/src/keywords/metaschemas2019.ts +410 -0
  126. package/src/keywords/metaschemas2020.ts +443 -0
  127. package/src/keywords/metaschemas6.ts +226 -0
  128. package/src/keywords/metaschemas7.ts +253 -0
  129. package/src/keywords/unevaluated.ts +329 -0
  130. package/src/keywords/validation.ts +627 -0
  131. package/src/keywords/vocab2019.ts +676 -0
  132. package/src/keywords/vocab2020.ts +82 -0
  133. package/src/keywords/vocab7.ts +393 -0
  134. package/src/loader.ts +60 -0
  135. package/src/lowering.ts +414 -0
  136. package/src/output.ts +651 -0
  137. package/src/records.ts +226 -0
  138. package/src/ref.ts +14 -0
  139. package/src/regex.ts +171 -0
  140. package/src/registry.ts +481 -0
  141. package/src/result.ts +252 -0
  142. package/src/uri.ts +35 -0
  143. package/src/walk.ts +88 -0
package/src/json.ts ADDED
@@ -0,0 +1,137 @@
1
+ // JSON utilities. Discipline notes carried over from the F2 prototype
2
+ // (DESIGN.md §5): Object.hasOwn everywhere an instance or schema key is
3
+ // tested (`__proto__`/`toString`/`constructor` are legal property names);
4
+ // regex compiled in unicode mode with fallback; length in code points.
5
+
6
+ /** A JSON-representable value. */
7
+ export type JsonValue =
8
+ null | boolean | number | string | JsonValue[] | { [k: string]: JsonValue };
9
+
10
+ /** The seven JSON Schema primitive type names, including the `integer` subtype. */
11
+ export type JsonType =
12
+ "null" | "boolean" | "number" | "integer" | "string" | "array" | "object";
13
+
14
+ /** True for JSON objects, excluding arrays and `null`. */
15
+ export const isObject = (v: unknown): v is Record<string, JsonValue> =>
16
+ typeof v === "object" && v !== null && !Array.isArray(v);
17
+
18
+ /**
19
+ * The primitive type of an instance value. `"integer"` is a numeric subtype
20
+ * handled by the `type` keyword and is never returned here.
21
+ */
22
+ export function jsonTypeOf(v: JsonValue): Exclude<JsonType, "integer"> {
23
+ if (v === null) return "null";
24
+ if (Array.isArray(v)) return "array";
25
+ switch (typeof v) {
26
+ case "boolean":
27
+ return "boolean";
28
+ case "number":
29
+ return "number";
30
+ case "string":
31
+ return "string";
32
+ default:
33
+ return "object";
34
+ }
35
+ }
36
+
37
+ /**
38
+ * JSON equality per the spec: same type and value, object member order
39
+ * insignificant.
40
+ */
41
+ export function jsonEqual(a: JsonValue, b: JsonValue): boolean {
42
+ if (a === b) return true;
43
+ if (Array.isArray(a)) {
44
+ if (!Array.isArray(b) || a.length !== b.length) return false;
45
+ for (let i = 0; i < a.length; i++) {
46
+ if (!jsonEqual(a[i]!, b[i]!)) return false;
47
+ }
48
+ return true;
49
+ }
50
+ if (isObject(a)) {
51
+ if (!isObject(b)) return false;
52
+ const keys = Object.keys(a);
53
+ if (keys.length !== Object.keys(b).length) return false;
54
+ for (const k of keys) {
55
+ if (!Object.hasOwn(b, k) || !jsonEqual(a[k]!, b[k]!)) return false;
56
+ }
57
+ return true;
58
+ }
59
+ return false;
60
+ }
61
+
62
+ /**
63
+ * A canonical string key for JSON equality: two values share a key exactly
64
+ * when {@link jsonEqual} holds (object member order made insignificant by
65
+ * sorting keys). Used to bucket values for near-linear duplicate detection;
66
+ * callers confirm bucket collisions with {@link jsonEqual} since distinct
67
+ * values could, in principle, collide on the key.
68
+ */
69
+ export function canonicalKey(value: JsonValue): string {
70
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
71
+ if (Array.isArray(value)) return `[${value.map(canonicalKey).join(",")}]`;
72
+ const keys = Object.keys(value).sort();
73
+ return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalKey(value[k]!)}`).join(",")}}`;
74
+ }
75
+
76
+ /** String length in Unicode code points, per `minLength`/`maxLength`. */
77
+ export function codePointLength(s: string): number {
78
+ let n = 0;
79
+ for (let i = 0; i < s.length; i++) {
80
+ n++;
81
+ const c = s.charCodeAt(i);
82
+ if (c >= 0xd800 && c <= 0xdbff) i++;
83
+ }
84
+ return n;
85
+ }
86
+
87
+ /**
88
+ * Compiles an ECMA-262 regex in unicode mode where possible (required for
89
+ * `\p{...}` property escapes), falling back for patterns invalid under the
90
+ * `u` flag.
91
+ */
92
+ export function schemaRegExp(pattern: string): RegExp {
93
+ try {
94
+ return new RegExp(pattern, "u");
95
+ } catch {
96
+ return new RegExp(pattern);
97
+ }
98
+ }
99
+
100
+ /** Escapes a JSON Pointer segment (RFC 6901). */
101
+ export const escapeSegment = (s: string): string =>
102
+ s.replace(/~/g, "~0").replace(/\//g, "~1");
103
+
104
+ /** Unescapes a JSON Pointer segment (RFC 6901). */
105
+ export const unescapeSegment = (s: string): string =>
106
+ s.replace(/~1/g, "/").replace(/~0/g, "~");
107
+
108
+ /**
109
+ * The first jsonEqual-duplicate pair in `items` (by ascending index), or
110
+ * `null` when every item is distinct — `uniqueItems`' predicate, shared by
111
+ * both tiers. Buckets by {@link canonicalKey} for near-linear detection; a
112
+ * key collision is confirmed with {@link jsonEqual} so distinct values that
113
+ * happen to share a key are never misreported as duplicates.
114
+ */
115
+ export function firstDuplicatePair(
116
+ items: readonly JsonValue[],
117
+ ): readonly [number, number] | null {
118
+ const seen = new Map<string, number[]>();
119
+ for (let i = 0; i < items.length; i++) {
120
+ const key = canonicalKey(items[i]!);
121
+ const bucket = seen.get(key);
122
+ if (bucket === undefined) {
123
+ seen.set(key, [i]);
124
+ continue;
125
+ }
126
+ for (const j of bucket) {
127
+ if (jsonEqual(items[j]!, items[i]!)) return [j, i];
128
+ }
129
+ bucket.push(i);
130
+ }
131
+ return null;
132
+ }
133
+
134
+ /** True when `items` contains any jsonEqual-duplicate pair (`uniqueItems`'s compiled-tier predicate). */
135
+ export function hasDuplicateItems(items: readonly JsonValue[]): boolean {
136
+ return firstDuplicatePair(items) !== null;
137
+ }