@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.js","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"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"}
package/dist/uri.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ /** Thrown when a reference cannot be resolved to an absolute URI. */
2
+ export declare class UnresolvableRefError extends Error {
3
+ }
4
+ /**
5
+ * Resolves a reference URI against a base URI to an absolute URI.
6
+ * @throws UnresolvableRefError if the pair does not form a valid URI.
7
+ */
8
+ export declare function resolveUri(ref: string, base: string): string;
9
+ /** A URI split into its resource part and decoded fragment. */
10
+ export interface SplitUri {
11
+ /** URI without fragment. */
12
+ resource: string;
13
+ /** Decoded fragment, `null` if absent. */
14
+ fragment: string | null;
15
+ }
16
+ /** Splits a URI into its resource and decoded fragment parts. */
17
+ export declare function splitFragment(uri: string): SplitUri;
18
+ //# sourceMappingURL=uri.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uri.d.ts","sourceRoot":"","sources":["../src/uri.ts"],"names":[],"mappings":"AAEA,qEAAqE;AACrE,qBAAa,oBAAqB,SAAQ,KAAK;CAAG;AAElD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAM5D;AAED,+DAA+D;AAC/D,MAAM,WAAW,QAAQ;IACvB,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAQnD"}
package/dist/uri.js ADDED
@@ -0,0 +1,27 @@
1
+ // URI handling for schema identification and reference resolution.
2
+ /** Thrown when a reference cannot be resolved to an absolute URI. */
3
+ export class UnresolvableRefError extends Error {
4
+ }
5
+ /**
6
+ * Resolves a reference URI against a base URI to an absolute URI.
7
+ * @throws UnresolvableRefError if the pair does not form a valid URI.
8
+ */
9
+ export function resolveUri(ref, base) {
10
+ try {
11
+ return new URL(ref, base).href;
12
+ }
13
+ catch {
14
+ throw new UnresolvableRefError(`cannot resolve '${ref}' against '${base}'`);
15
+ }
16
+ }
17
+ /** Splits a URI into its resource and decoded fragment parts. */
18
+ export function splitFragment(uri) {
19
+ const i = uri.indexOf("#");
20
+ return i === -1
21
+ ? { resource: uri, fragment: null }
22
+ : {
23
+ resource: uri.slice(0, i),
24
+ fragment: decodeURIComponent(uri.slice(i + 1)),
25
+ };
26
+ }
27
+ //# sourceMappingURL=uri.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uri.js","sourceRoot":"","sources":["../src/uri.ts"],"names":[],"mappings":"AAAA,mEAAmE;AAEnE,qEAAqE;AACrE,MAAM,OAAO,oBAAqB,SAAQ,KAAK;CAAG;AAElD;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,IAAY;IAClD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,oBAAoB,CAAC,mBAAmB,GAAG,cAAc,IAAI,GAAG,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC;AAUD,iEAAiE;AACjE,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO,CAAC,KAAK,CAAC,CAAC;QACb,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE;QACnC,CAAC,CAAC;YACE,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;YACzB,QAAQ,EAAE,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;SAC/C,CAAC;AACR,CAAC"}
package/dist/walk.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ import { JsonValue } from "./json.js";
2
+ import { Dialect } from "./dialect.js";
3
+ /**
4
+ * One schema position visited by {@link walkSchema}.
5
+ */
6
+ export interface SchemaWalkVisit {
7
+ /** The value in schema position: an object or a boolean. */
8
+ readonly node: JsonValue;
9
+ /** JSON Pointer from the walk root. */
10
+ readonly pointer: string;
11
+ /** Applying keyword in the parent schema object; `null` at the root. */
12
+ readonly keyword: string | null;
13
+ }
14
+ /**
15
+ * Walks every schema position of `schema` reachable through the dialect's
16
+ * keyword facts (`analyze().subschemas`), visiting parents before children.
17
+ *
18
+ * Tolerant by design: values in schema position that are neither objects
19
+ * nor booleans are skipped, as are positions under keyword values whose
20
+ * `analyze()` rejects them — unknown keywords' values are never descended.
21
+ * Nesting beyond `maxDepth` still throws {@link MaxDepthExceededError}: the
22
+ * depth bound is a security posture, not a validity judgment.
23
+ */
24
+ export declare function walkSchema(schema: JsonValue, dialect: Pick<Dialect, "keywords">, visit: (v: SchemaWalkVisit) => void, maxDepth?: number): void;
25
+ //# sourceMappingURL=walk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walk.d.ts","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,SAAS,EAA2B,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,4DAA4D;IAC5D,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,uCAAuC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wEAAwE;IACxE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAClC,KAAK,EAAE,CAAC,CAAC,EAAE,eAAe,KAAK,IAAI,EACnC,QAAQ,GAAE,MAA0B,GACnC,IAAI,CAgDN"}
package/dist/walk.js ADDED
@@ -0,0 +1,65 @@
1
+ // Public schema-position walk (M8.6): the descent knowledge lives in each
2
+ // keyword's analyze() facts, so adapters and tools stop hardcoding their own
3
+ // applicator tables. Unlike the registry's registration walk (which owns
4
+ // base-URI rebasing, anchor indexing, and reference collection), this walk
5
+ // is deliberately tolerant: it runs on unvalidated input — e.g. a strict-
6
+ // mode check before registration — where a malformed keyword value must be
7
+ // skipped, not thrown. Registration keeps its InvalidSchemaError job.
8
+ import { isObject, escapeSegment } from "./json.js";
9
+ import { DEFAULT_MAX_DEPTH, MaxDepthExceededError } from "./registry.js";
10
+ /**
11
+ * Walks every schema position of `schema` reachable through the dialect's
12
+ * keyword facts (`analyze().subschemas`), visiting parents before children.
13
+ *
14
+ * Tolerant by design: values in schema position that are neither objects
15
+ * nor booleans are skipped, as are positions under keyword values whose
16
+ * `analyze()` rejects them — unknown keywords' values are never descended.
17
+ * Nesting beyond `maxDepth` still throws {@link MaxDepthExceededError}: the
18
+ * depth bound is a security posture, not a validity judgment.
19
+ */
20
+ export function walkSchema(schema, dialect, visit, maxDepth = DEFAULT_MAX_DEPTH) {
21
+ const step = (node, pointer, keyword, depth) => {
22
+ if (depth > maxDepth) {
23
+ throw new MaxDepthExceededError(`schema nesting exceeds maxDepth (${maxDepth}) at '#${pointer}'`);
24
+ }
25
+ if (typeof node === "boolean") {
26
+ visit({ node, pointer, keyword });
27
+ return;
28
+ }
29
+ if (!isObject(node))
30
+ return;
31
+ visit({ node, pointer, keyword });
32
+ for (const [name, value] of Object.entries(node)) {
33
+ const behavior = dialect.keywords.get(name)?.behavior;
34
+ if (!behavior?.analyze)
35
+ continue;
36
+ let positions;
37
+ try {
38
+ positions = behavior.analyze(value, { schema: node }).subschemas;
39
+ }
40
+ catch {
41
+ continue;
42
+ }
43
+ if (!positions)
44
+ continue;
45
+ for (const relPath of positions) {
46
+ let child = value;
47
+ let suffix = "/" + escapeSegment(name);
48
+ for (const seg of relPath) {
49
+ child =
50
+ child === null || typeof child !== "object"
51
+ ? undefined
52
+ : Array.isArray(child)
53
+ ? child[seg]
54
+ : child[seg];
55
+ suffix += "/" + escapeSegment(String(seg));
56
+ }
57
+ if (child !== undefined) {
58
+ step(child, pointer + suffix, name, depth + 1);
59
+ }
60
+ }
61
+ }
62
+ };
63
+ step(schema, "", null, 0);
64
+ }
65
+ //# sourceMappingURL=walk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walk.js","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,6EAA6E;AAC7E,yEAAyE;AACzE,2EAA2E;AAC3E,0EAA0E;AAC1E,2EAA2E;AAC3E,sEAAsE;AAEtE,OAAO,EAAa,QAAQ,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/D,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAczE;;;;;;;;;GASG;AACH,MAAM,UAAU,UAAU,CACxB,MAAiB,EACjB,OAAkC,EAClC,KAAmC,EACnC,WAAmB,iBAAiB;IAEpC,MAAM,IAAI,GAAG,CACX,IAAe,EACf,OAAe,EACf,OAAsB,EACtB,KAAa,EACP,EAAE;QACR,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;YACrB,MAAM,IAAI,qBAAqB,CAC7B,oCAAoC,QAAQ,UAAU,OAAO,GAAG,CACjE,CAAC;QACJ,CAAC;QACD,IAAI,OAAO,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,KAAK,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;YAClC,OAAO;QACT,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO;QAC5B,KAAK,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAElC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;YACtD,IAAI,CAAC,QAAQ,EAAE,OAAO;gBAAE,SAAS;YACjC,IAAI,SAAS,CAAC;YACd,IAAI,CAAC;gBACH,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC;YACnE,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YACD,IAAI,CAAC,SAAS;gBAAE,SAAS;YACzB,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE,CAAC;gBAChC,IAAI,KAAK,GAA0B,KAAK,CAAC;gBACzC,IAAI,MAAM,GAAG,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;gBACvC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;oBAC1B,KAAK;wBACH,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;4BACzC,CAAC,CAAC,SAAS;4BACX,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gCACpB,CAAC,CAAC,KAAK,CAAC,GAAa,CAAC;gCACtB,CAAC,CAAE,KAAmC,CAAC,GAAa,CAAC,CAAC;oBAC5D,MAAM,IAAI,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC7C,CAAC;gBACD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBACxB,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;gBACjD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IACF,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC5B,CAAC"}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@json-schema-engine/core",
3
+ "version": "0.0.1",
4
+ "description": "Interpreter core: registry, dialects, evaluation, annotations, and output rendering for draft 2020-12/2019-09/draft-07/draft-06",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "exports": {
8
+ ".": {
9
+ "jse-source": "./src/index.ts",
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "license": "MIT",
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "engines": {
19
+ "node": ">=22"
20
+ },
21
+ "types": "./dist/index.d.ts",
22
+ "files": [
23
+ "dist",
24
+ "src"
25
+ ],
26
+ "sideEffects": false,
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/handrews/json-schema-engine.git",
30
+ "directory": "packages/core"
31
+ }
32
+ }
@@ -0,0 +1,88 @@
1
+ // Compiled-tier port of the consumer keywords' channel-reading semantics
2
+ // (COMPILED-CONSUMERS.md). The runtime coverage channel is a flat array of
3
+ // RAW DEPENDENCY DATA — the same values `ctx.produce` yields — merged with
4
+ // mark/truncate at application boundaries by the serializer (phase B). These
5
+ // helpers fold that channel exactly as the interpreter's `unevaluated*`
6
+ // evaluate() folds visible dependency records, dispatching on VALUE SHAPE
7
+ // (the shape is unambiguous, so one mixed names+indexes channel is sound):
8
+ //
9
+ // - `string[]` evaluated property names (properties/patternProperties/
10
+ // additionalProperties/unevaluatedProperties values); folds
11
+ // into name coverage. Empty array is a no-op.
12
+ // - `true` full index coverage (items / contains-all /
13
+ // prefixItems-covered-whole-array / unevaluatedItems values).
14
+ // - `number` n prefix coverage of indexes 0..n, i.e. coveredPrefix = n+1
15
+ // (prefixItems' largest-applied-index value).
16
+ // - `number[]` individual covered indexes (contains' matched list).
17
+ //
18
+ // Name folding ignores non-`string[]` entries; index folding ignores
19
+ // `string[]` entries; `[]` is a no-op for both.
20
+
21
+ import { DependencyRecord } from "./engine.js";
22
+ import { Cursor } from "./cursor.js";
23
+
24
+ /**
25
+ * Folded name coverage: the set of evaluated property names. Ports
26
+ * `unevaluatedProperties.evaluate`'s seen-set union — every `string[]` entry
27
+ * contributes its names; other shapes are ignored.
28
+ */
29
+ export function foldNameCoverage(channel: readonly unknown[]): Set<string> {
30
+ const seen = new Set<string>();
31
+ for (const entry of channel) {
32
+ if (Array.isArray(entry)) {
33
+ for (const el of entry) {
34
+ if (typeof el === "string") seen.add(el);
35
+ }
36
+ }
37
+ }
38
+ return seen;
39
+ }
40
+
41
+ /**
42
+ * Folded index coverage over an array of the given length. Ports
43
+ * `unevaluatedItems.evaluate`'s coveredPrefix/coveredIdx computation: `true`
44
+ * covers the whole array, a `number` extends the covered prefix to value+1
45
+ * (max-folded), a `number[]` marks individual indexes.
46
+ */
47
+ export function foldIndexCoverage(
48
+ channel: readonly unknown[],
49
+ length: number,
50
+ ): { coveredPrefix: number; coveredIdx: Set<number> } {
51
+ let coveredPrefix = 0;
52
+ const coveredIdx = new Set<number>();
53
+ for (const entry of channel) {
54
+ if (entry === true) {
55
+ coveredPrefix = length;
56
+ } else if (typeof entry === "number") {
57
+ coveredPrefix = Math.max(coveredPrefix, entry + 1);
58
+ } else if (Array.isArray(entry)) {
59
+ // number[] (contains' matched list); string[] contributes no indexes.
60
+ for (const el of entry) {
61
+ if (typeof el === "number") coveredIdx.add(el);
62
+ }
63
+ }
64
+ }
65
+ return { coveredPrefix, coveredIdx };
66
+ }
67
+
68
+ /**
69
+ * Channel entries a fragment (interpreted island) contributes: the data of
70
+ * coverage-producer dependency records at the island's root cursor.
71
+ * `evaluateFragment` returns root-frame surviving records with cursor
72
+ * identity intact; filtering to the fragment's root `cursor` keeps coverage
73
+ * per-instance-location, and filtering to `coverageIds`
74
+ * (SchemaRegistry.coverageIds) keeps only the producers whose data the
75
+ * shape-dispatching folds above understand — other dependency data (an
76
+ * `if` outcome, say) never reaches the channel. Data passes through untouched.
77
+ */
78
+ export function harvestCoverage(
79
+ dependencies: readonly DependencyRecord[],
80
+ cursor: Cursor,
81
+ coverageIds: ReadonlySet<string>,
82
+ ): unknown[] {
83
+ const out: unknown[] = [];
84
+ for (const d of dependencies) {
85
+ if (d.cursor === cursor && coverageIds.has(d.behaviorId)) out.push(d.data);
86
+ }
87
+ return out;
88
+ }
package/src/cursor.ts ADDED
@@ -0,0 +1,42 @@
1
+ // Instance cursor: a parent-linked position in the instance document.
2
+ //
3
+ // Cursor identity carries semantic weight: in-place applicators ($ref, allOf,
4
+ // if, ...) apply subschemas to the *same* cursor object, while child
5
+ // applicators (properties, items, ...) create child cursors. The channel's
6
+ // visibility query keys on this identity (engine.ts). JSON Pointer strings
7
+ // are materialized lazily, only when output units escape.
8
+
9
+ import { JsonValue, escapeSegment } from "./json.js";
10
+
11
+ /** A parent-linked position in the instance document. */
12
+ export interface Cursor {
13
+ readonly value: JsonValue;
14
+ readonly parent: Cursor | null;
15
+ readonly segment: string | number | null;
16
+ /** Lazily cached JSON Pointer; use {@link instancePointer}. */
17
+ ptr?: string;
18
+ }
19
+
20
+ /** Creates a cursor at the instance document root. */
21
+ export const rootCursor = (value: JsonValue): Cursor => ({
22
+ value,
23
+ parent: null,
24
+ segment: null,
25
+ });
26
+
27
+ /** Creates a cursor for a named or indexed child of `parent`. */
28
+ export const childCursor = (
29
+ parent: Cursor,
30
+ segment: string | number,
31
+ value: JsonValue,
32
+ ): Cursor => ({ value, parent, segment });
33
+
34
+ /** Computes the JSON Pointer for a cursor's instance location, caching the result. */
35
+ export function instancePointer(cursor: Cursor): string {
36
+ if (cursor.ptr !== undefined) return cursor.ptr;
37
+ if (cursor.parent === null) return (cursor.ptr = "");
38
+ return (cursor.ptr =
39
+ instancePointer(cursor.parent) +
40
+ "/" +
41
+ escapeSegment(String(cursor.segment)));
42
+ }