typesea 0.1.0 → 0.2.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 (285) hide show
  1. package/CHANGELOG.md +67 -6
  2. package/README.md +98 -17
  3. package/dist/adapters/index.d.ts +50 -8
  4. package/dist/adapters/index.d.ts.map +1 -1
  5. package/dist/adapters/index.js +169 -48
  6. package/dist/aot/index.d.ts +18 -2
  7. package/dist/aot/index.d.ts.map +1 -1
  8. package/dist/aot/index.js +93 -14
  9. package/dist/async/index.d.ts +28 -56
  10. package/dist/async/index.d.ts.map +1 -1
  11. package/dist/async/index.js +94 -37
  12. package/dist/builders/composite.d.ts +37 -6
  13. package/dist/builders/composite.d.ts.map +1 -1
  14. package/dist/builders/composite.js +84 -10
  15. package/dist/builders/index.d.ts +2 -0
  16. package/dist/builders/index.d.ts.map +1 -1
  17. package/dist/builders/index.js +2 -0
  18. package/dist/builders/modifier.d.ts +30 -5
  19. package/dist/builders/modifier.d.ts.map +1 -1
  20. package/dist/builders/modifier.js +38 -5
  21. package/dist/builders/object/guard.d.ts +18 -22
  22. package/dist/builders/object/guard.d.ts.map +1 -1
  23. package/dist/builders/object/guard.js +26 -26
  24. package/dist/builders/object/index.d.ts +2 -0
  25. package/dist/builders/object/index.d.ts.map +1 -1
  26. package/dist/builders/object/index.js +2 -0
  27. package/dist/builders/object/schema.d.ts +55 -9
  28. package/dist/builders/object/schema.d.ts.map +1 -1
  29. package/dist/builders/object/schema.js +92 -15
  30. package/dist/builders/object/types.d.ts +5 -31
  31. package/dist/builders/object/types.d.ts.map +1 -1
  32. package/dist/builders/object/types.js +2 -0
  33. package/dist/builders/scalar.d.ts +29 -8
  34. package/dist/builders/scalar.d.ts.map +1 -1
  35. package/dist/builders/scalar.js +33 -8
  36. package/dist/builders/table.d.ts +4 -0
  37. package/dist/builders/table.d.ts.map +1 -1
  38. package/dist/builders/table.js +4 -0
  39. package/dist/builders/types.d.ts +14 -4
  40. package/dist/builders/types.d.ts.map +1 -1
  41. package/dist/builders/types.js +2 -0
  42. package/dist/compile/check-composite.d.ts +22 -1
  43. package/dist/compile/check-composite.d.ts.map +1 -1
  44. package/dist/compile/check-composite.js +564 -24
  45. package/dist/compile/check-scalar.d.ts +78 -0
  46. package/dist/compile/check-scalar.d.ts.map +1 -1
  47. package/dist/compile/check-scalar.js +432 -1
  48. package/dist/compile/check.d.ts +12 -0
  49. package/dist/compile/check.d.ts.map +1 -1
  50. package/dist/compile/check.js +37 -0
  51. package/dist/compile/context.d.ts +47 -9
  52. package/dist/compile/context.d.ts.map +1 -1
  53. package/dist/compile/context.js +51 -8
  54. package/dist/compile/graph-predicate.d.ts +4 -2
  55. package/dist/compile/graph-predicate.d.ts.map +1 -1
  56. package/dist/compile/graph-predicate.js +1907 -171
  57. package/dist/compile/guard.d.ts +15 -24
  58. package/dist/compile/guard.d.ts.map +1 -1
  59. package/dist/compile/guard.js +158 -74
  60. package/dist/compile/index.d.ts +3 -1
  61. package/dist/compile/index.d.ts.map +1 -1
  62. package/dist/compile/index.js +2 -0
  63. package/dist/compile/issue.d.ts +110 -0
  64. package/dist/compile/issue.d.ts.map +1 -1
  65. package/dist/compile/issue.js +184 -1
  66. package/dist/compile/names.d.ts +12 -2
  67. package/dist/compile/names.d.ts.map +1 -1
  68. package/dist/compile/names.js +19 -3
  69. package/dist/compile/predicate.d.ts +24 -0
  70. package/dist/compile/predicate.d.ts.map +1 -1
  71. package/dist/compile/predicate.js +131 -5
  72. package/dist/compile/runtime.d.ts +80 -12
  73. package/dist/compile/runtime.d.ts.map +1 -1
  74. package/dist/compile/runtime.js +25 -6
  75. package/dist/compile/source.d.ts +10 -2
  76. package/dist/compile/source.d.ts.map +1 -1
  77. package/dist/compile/source.js +361 -26
  78. package/dist/compile/types.d.ts +20 -0
  79. package/dist/compile/types.d.ts.map +1 -1
  80. package/dist/compile/types.js +2 -0
  81. package/dist/decoder/index.d.ts +32 -46
  82. package/dist/decoder/index.d.ts.map +1 -1
  83. package/dist/decoder/index.js +102 -38
  84. package/dist/evaluate/check-composite.d.ts +59 -0
  85. package/dist/evaluate/check-composite.d.ts.map +1 -1
  86. package/dist/evaluate/check-composite.js +151 -3
  87. package/dist/evaluate/check-scalar.d.ts +16 -0
  88. package/dist/evaluate/check-scalar.d.ts.map +1 -1
  89. package/dist/evaluate/check-scalar.js +32 -0
  90. package/dist/evaluate/check.d.ts +7 -0
  91. package/dist/evaluate/check.d.ts.map +1 -1
  92. package/dist/evaluate/check.js +43 -0
  93. package/dist/evaluate/index.d.ts +2 -0
  94. package/dist/evaluate/index.d.ts.map +1 -1
  95. package/dist/evaluate/index.js +2 -0
  96. package/dist/evaluate/issue.d.ts +11 -1
  97. package/dist/evaluate/issue.d.ts.map +1 -1
  98. package/dist/evaluate/issue.js +15 -1
  99. package/dist/evaluate/predicate.d.ts +16 -5
  100. package/dist/evaluate/predicate.d.ts.map +1 -1
  101. package/dist/evaluate/predicate.js +20 -5
  102. package/dist/evaluate/shared.d.ts +59 -13
  103. package/dist/evaluate/shared.d.ts.map +1 -1
  104. package/dist/evaluate/shared.js +66 -8
  105. package/dist/evaluate/state.d.ts +35 -13
  106. package/dist/evaluate/state.d.ts.map +1 -1
  107. package/dist/evaluate/state.js +35 -2
  108. package/dist/guard/base.d.ts +79 -29
  109. package/dist/guard/base.d.ts.map +1 -1
  110. package/dist/guard/base.js +91 -29
  111. package/dist/guard/error.d.ts +10 -5
  112. package/dist/guard/error.d.ts.map +1 -1
  113. package/dist/guard/error.js +10 -5
  114. package/dist/guard/index.d.ts +2 -0
  115. package/dist/guard/index.d.ts.map +1 -1
  116. package/dist/guard/index.js +2 -0
  117. package/dist/guard/number.d.ts +26 -11
  118. package/dist/guard/number.d.ts.map +1 -1
  119. package/dist/guard/number.js +30 -11
  120. package/dist/guard/props.d.ts +27 -3
  121. package/dist/guard/props.d.ts.map +1 -1
  122. package/dist/guard/props.js +27 -3
  123. package/dist/guard/read.d.ts +62 -9
  124. package/dist/guard/read.d.ts.map +1 -1
  125. package/dist/guard/read.js +83 -10
  126. package/dist/guard/registry.d.ts +12 -2
  127. package/dist/guard/registry.d.ts.map +1 -1
  128. package/dist/guard/registry.js +15 -3
  129. package/dist/guard/string.d.ts +33 -13
  130. package/dist/guard/string.d.ts.map +1 -1
  131. package/dist/guard/string.js +37 -13
  132. package/dist/guard/types.d.ts +92 -40
  133. package/dist/guard/types.d.ts.map +1 -1
  134. package/dist/guard/types.js +2 -0
  135. package/dist/index.d.ts +1 -1
  136. package/dist/index.d.ts.map +1 -1
  137. package/dist/internal/index.d.ts +42 -6
  138. package/dist/internal/index.d.ts.map +1 -1
  139. package/dist/internal/index.js +51 -8
  140. package/dist/ir/builder.d.ts +16 -126
  141. package/dist/ir/builder.d.ts.map +1 -1
  142. package/dist/ir/builder.js +77 -137
  143. package/dist/ir/freeze.d.ts +4 -0
  144. package/dist/ir/freeze.d.ts.map +1 -1
  145. package/dist/ir/freeze.js +59 -0
  146. package/dist/ir/index.d.ts +3 -1
  147. package/dist/ir/index.d.ts.map +1 -1
  148. package/dist/ir/index.js +2 -0
  149. package/dist/ir/regexp.d.ts +2 -0
  150. package/dist/ir/regexp.d.ts.map +1 -1
  151. package/dist/ir/regexp.js +2 -0
  152. package/dist/ir/types.d.ts +90 -55
  153. package/dist/ir/types.d.ts.map +1 -1
  154. package/dist/ir/types.js +2 -0
  155. package/dist/ir/validate.d.ts +8 -1
  156. package/dist/ir/validate.d.ts.map +1 -1
  157. package/dist/ir/validate.js +477 -61
  158. package/dist/issue/index.d.ts +41 -9
  159. package/dist/issue/index.d.ts.map +1 -1
  160. package/dist/issue/index.js +61 -11
  161. package/dist/json-schema/emit-combinator.d.ts +44 -4
  162. package/dist/json-schema/emit-combinator.d.ts.map +1 -1
  163. package/dist/json-schema/emit-combinator.js +44 -4
  164. package/dist/json-schema/emit-composite.d.ts +10 -0
  165. package/dist/json-schema/emit-composite.d.ts.map +1 -1
  166. package/dist/json-schema/emit-composite.js +15 -1
  167. package/dist/json-schema/emit-scalar.d.ts +26 -3
  168. package/dist/json-schema/emit-scalar.d.ts.map +1 -1
  169. package/dist/json-schema/emit-scalar.js +70 -9
  170. package/dist/json-schema/emit-types.d.ts +11 -1
  171. package/dist/json-schema/emit-types.d.ts.map +1 -1
  172. package/dist/json-schema/emit-types.js +2 -0
  173. package/dist/json-schema/emit.d.ts +12 -1
  174. package/dist/json-schema/emit.d.ts.map +1 -1
  175. package/dist/json-schema/emit.js +12 -1
  176. package/dist/json-schema/freeze.d.ts +13 -2
  177. package/dist/json-schema/freeze.d.ts.map +1 -1
  178. package/dist/json-schema/freeze.js +41 -8
  179. package/dist/json-schema/index.d.ts +16 -2
  180. package/dist/json-schema/index.d.ts.map +1 -1
  181. package/dist/json-schema/index.js +23 -3
  182. package/dist/json-schema/issue.d.ts +4 -1
  183. package/dist/json-schema/issue.d.ts.map +1 -1
  184. package/dist/json-schema/issue.js +4 -1
  185. package/dist/json-schema/read.d.ts +24 -3
  186. package/dist/json-schema/read.d.ts.map +1 -1
  187. package/dist/json-schema/read.js +59 -12
  188. package/dist/json-schema/types.d.ts +38 -15
  189. package/dist/json-schema/types.d.ts.map +1 -1
  190. package/dist/json-schema/types.js +2 -0
  191. package/dist/kind/index.d.ts +15 -28
  192. package/dist/kind/index.d.ts.map +1 -1
  193. package/dist/kind/index.js +15 -10
  194. package/dist/lower/index.d.ts +6 -1
  195. package/dist/lower/index.d.ts.map +1 -1
  196. package/dist/lower/index.js +411 -44
  197. package/dist/message/index.d.ts +46 -10
  198. package/dist/message/index.d.ts.map +1 -1
  199. package/dist/message/index.js +88 -17
  200. package/dist/optimize/algebraic.d.ts +54 -0
  201. package/dist/optimize/algebraic.d.ts.map +1 -0
  202. package/dist/optimize/algebraic.js +314 -0
  203. package/dist/optimize/compact.d.ts +8 -1
  204. package/dist/optimize/compact.d.ts.map +1 -1
  205. package/dist/optimize/compact.js +13 -2
  206. package/dist/optimize/domain.d.ts +16 -0
  207. package/dist/optimize/domain.d.ts.map +1 -0
  208. package/dist/optimize/domain.js +615 -0
  209. package/dist/optimize/fold-boolean.d.ts +17 -2
  210. package/dist/optimize/fold-boolean.d.ts.map +1 -1
  211. package/dist/optimize/fold-boolean.js +59 -14
  212. package/dist/optimize/fold-common.d.ts +43 -8
  213. package/dist/optimize/fold-common.d.ts.map +1 -1
  214. package/dist/optimize/fold-common.js +37 -6
  215. package/dist/optimize/fold-constraints.d.ts +33 -0
  216. package/dist/optimize/fold-constraints.d.ts.map +1 -0
  217. package/dist/optimize/fold-constraints.js +484 -0
  218. package/dist/optimize/fold-scalar.d.ts +98 -13
  219. package/dist/optimize/fold-scalar.d.ts.map +1 -1
  220. package/dist/optimize/fold-scalar.js +98 -13
  221. package/dist/optimize/fold.d.ts +8 -1
  222. package/dist/optimize/fold.d.ts.map +1 -1
  223. package/dist/optimize/fold.js +22 -2
  224. package/dist/optimize/index.d.ts +9 -1
  225. package/dist/optimize/index.d.ts.map +1 -1
  226. package/dist/optimize/index.js +18 -3
  227. package/dist/optimize/map-node.d.ts +3 -1
  228. package/dist/optimize/map-node.d.ts.map +1 -1
  229. package/dist/optimize/map-node.js +45 -3
  230. package/dist/optimize/peephole.d.ts +16 -0
  231. package/dist/optimize/peephole.d.ts.map +1 -0
  232. package/dist/optimize/peephole.js +254 -0
  233. package/dist/optimize/remap.d.ts +2 -0
  234. package/dist/optimize/remap.d.ts.map +1 -1
  235. package/dist/optimize/remap.js +2 -0
  236. package/dist/optimize/rewrite.d.ts +13 -8
  237. package/dist/optimize/rewrite.d.ts.map +1 -1
  238. package/dist/optimize/rewrite.js +13 -8
  239. package/dist/plan/cache.d.ts +9 -3
  240. package/dist/plan/cache.d.ts.map +1 -1
  241. package/dist/plan/cache.js +21 -5
  242. package/dist/plan/index.d.ts +2 -0
  243. package/dist/plan/index.d.ts.map +1 -1
  244. package/dist/plan/index.js +2 -0
  245. package/dist/plan/predicate.d.ts +2 -0
  246. package/dist/plan/predicate.d.ts.map +1 -1
  247. package/dist/plan/predicate.js +268 -29
  248. package/dist/plan/schema-predicate.d.ts +6 -0
  249. package/dist/plan/schema-predicate.d.ts.map +1 -1
  250. package/dist/plan/schema-predicate.js +117 -13
  251. package/dist/plan/types.d.ts +2 -0
  252. package/dist/plan/types.d.ts.map +1 -1
  253. package/dist/plan/types.js +2 -0
  254. package/dist/result/index.d.ts +19 -5
  255. package/dist/result/index.d.ts.map +1 -1
  256. package/dist/result/index.js +10 -2
  257. package/dist/schema/common.d.ts +69 -6
  258. package/dist/schema/common.d.ts.map +1 -1
  259. package/dist/schema/common.js +104 -10
  260. package/dist/schema/freeze.d.ts +4 -0
  261. package/dist/schema/freeze.d.ts.map +1 -1
  262. package/dist/schema/freeze.js +18 -0
  263. package/dist/schema/index.d.ts +3 -0
  264. package/dist/schema/index.d.ts.map +1 -1
  265. package/dist/schema/index.js +3 -0
  266. package/dist/schema/lazy.d.ts +4 -0
  267. package/dist/schema/lazy.d.ts.map +1 -1
  268. package/dist/schema/lazy.js +4 -0
  269. package/dist/schema/literal.d.ts +7 -1
  270. package/dist/schema/literal.d.ts.map +1 -1
  271. package/dist/schema/literal.js +7 -1
  272. package/dist/schema/types.d.ts +20 -96
  273. package/dist/schema/types.d.ts.map +1 -1
  274. package/dist/schema/types.js +5 -1
  275. package/dist/schema/undefined.d.ts +17 -0
  276. package/dist/schema/undefined.d.ts.map +1 -0
  277. package/dist/schema/undefined.js +72 -0
  278. package/dist/schema/validate.d.ts +8 -1
  279. package/dist/schema/validate.d.ts.map +1 -1
  280. package/dist/schema/validate.js +146 -55
  281. package/docs/api.md +57 -0
  282. package/docs/assets/benchmark-headline.svg +163 -0
  283. package/docs/engine-notes.md +58 -15
  284. package/docs/index.html +130 -110
  285. package/package.json +65 -65
@@ -1,53 +1,117 @@
1
1
  /**
2
2
  * @file validate.ts
3
3
  * @brief Runtime validation for graph objects.
4
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
5
+ * node ids and valid dependency edges.
4
6
  */
5
- import { NodeTag } from "../kind/index.js";
7
+ import { NodeTag, ObjectModeTag, PresenceTag } from "../kind/index.js";
6
8
  import { isLiteralValue, isSchemaValue } from "../schema/index.js";
7
9
  import { isPlainRegExp } from "./regexp.js";
8
10
  /**
9
- * @brief is graph value.
11
+ * @brief Validate an unknown value as a frozen-style Sea-of-Nodes graph.
12
+ * @param value Candidate graph object supplied to graph consumers.
13
+ * @returns True when the full graph has a dense arena and well-formed nodes.
14
+ * @details Graph objects can cross public introspection boundaries. Validation
15
+ * therefore rejects accessors, sparse arrays, and prototype-backed fields before
16
+ * optimization or freezing reads graph metadata.
10
17
  */
11
18
  export function isGraphValue(value) {
19
+ return isGraphValueInner(value, makeGraphValidationState());
20
+ }
21
+ const missingDataProperty = Symbol("typesea.ir.missingDataProperty");
22
+ /**
23
+ * @brief Allocate traversal state for one root graph validation.
24
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
25
+ * node ids and valid dependency edges.
26
+ * @returns Empty active and completed graph sets.
27
+ */
28
+ function makeGraphValidationState() {
29
+ return {
30
+ active: new WeakSet(),
31
+ done: new WeakSet()
32
+ };
33
+ }
34
+ /**
35
+ * @brief Validate one graph object and its nested child graphs.
36
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
37
+ * node ids and valid dependency edges.
38
+ * @param value Candidate graph object.
39
+ * @param state Shared recursion state.
40
+ * @returns True when entry/result ids and every arena node are valid.
41
+ */
42
+ function isGraphValueInner(value, state) {
12
43
  if (!isRecord(value)) {
13
44
  return false;
14
45
  }
15
- const nodes = value["nodes"];
46
+ if (state.done.has(value)) {
47
+ return true;
48
+ }
49
+ if (state.active.has(value)) {
50
+ return false;
51
+ }
52
+ state.active.add(value);
53
+ /*
54
+ * `nodes`, `entry`, and `result` must be own data slots. Optimizer callers
55
+ * may pass graph-like values, and bracket reads would otherwise consult a
56
+ * hostile prototype before the shape is trusted.
57
+ */
58
+ const nodes = readOwnDataProperty(value, "nodes");
16
59
  if (!isUnknownArray(nodes)) {
17
60
  return false;
18
61
  }
19
- if (!isNodeId(value["entry"], nodes.length) ||
20
- !isNodeId(value["result"], nodes.length)) {
62
+ const entryId = readOwnDataProperty(value, "entry");
63
+ const resultId = readOwnDataProperty(value, "result");
64
+ if (!isNodeId(entryId, nodes.length) ||
65
+ !isNodeId(resultId, nodes.length)) {
21
66
  return false;
22
67
  }
23
68
  for (let index = 0; index < nodes.length; index += 1) {
24
- if (!isGraphNodeValue(nodes[index], index, nodes.length)) {
69
+ if (!isGraphNodeValue(nodes[index], index, nodes.length, state)) {
25
70
  return false;
26
71
  }
27
72
  }
28
- const entry = nodes[value["entry"]];
29
- const result = nodes[value["result"]];
30
- return isRecord(entry) && entry["tag"] === NodeTag.Start &&
31
- isRecord(result) && result["tag"] === NodeTag.Return;
73
+ const entry = nodes[entryId];
74
+ const result = nodes[resultId];
75
+ const valid = isRecord(entry) &&
76
+ readOwnDataProperty(entry, "tag") === NodeTag.Start &&
77
+ isRecord(result) &&
78
+ readOwnDataProperty(result, "tag") === NodeTag.Return;
79
+ state.active.delete(value);
80
+ if (valid) {
81
+ state.done.add(value);
82
+ }
83
+ return valid;
32
84
  }
33
85
  /**
34
- * @brief is graph node value.
86
+ * @brief Validate one arena node at its expected id.
87
+ * @param value Candidate node object.
88
+ * @param index Arena slot the node occupies.
89
+ * @param nodeCount Total arena size for dependency bounds.
90
+ * @param state Shared recursion state for child graphs.
91
+ * @returns True when the node tag and payload agree with its dependency vector.
92
+ * @details Every node stores both `deps` and named edge fields. The redundant
93
+ * representation is checked here so later passes can trust either view.
35
94
  */
36
- function isGraphNodeValue(value, index, nodeCount) {
37
- if (!isRecord(value) || value["id"] !== index) {
95
+ function isGraphNodeValue(value, index, nodeCount, state) {
96
+ if (!isRecord(value) || readOwnDataProperty(value, "id") !== index) {
38
97
  return false;
39
98
  }
40
- const deps = value["deps"];
99
+ const deps = readOwnDataProperty(value, "deps");
41
100
  if (!isNodeIdArray(deps, nodeCount)) {
42
101
  return false;
43
102
  }
44
- switch (value["tag"]) {
103
+ const tag = readOwnDataProperty(value, "tag");
104
+ /*
105
+ * The tag switch is deliberately closed. Unknown node tags are rejected at
106
+ * the boundary so optimizer passes can stay exhaustive over NodeTag.
107
+ */
108
+ switch (tag) {
45
109
  case NodeTag.Start:
46
110
  case NodeTag.Param:
47
111
  case NodeTag.Const:
48
112
  return isLeafNodeValue(value, deps);
49
113
  case NodeTag.GetProp:
50
- return typeof value["key"] === "string" &&
114
+ return typeof readOwnDataProperty(value, "key") === "string" &&
51
115
  isSingleDepNode(value, deps, "object", nodeCount);
52
116
  case NodeTag.IsString:
53
117
  case NodeTag.IsNumber:
@@ -66,45 +130,56 @@ function isGraphNodeValue(value, index, nodeCount) {
66
130
  case NodeTag.Lte:
67
131
  return isTwoDepNode(value, deps, "left", "right", nodeCount);
68
132
  case NodeTag.StringMin:
69
- case NodeTag.StringMax:
70
- return typeof value["bound"] === "number" &&
71
- Number.isInteger(value["bound"]) &&
72
- value["bound"] >= 0 &&
133
+ case NodeTag.StringMax: {
134
+ const bound = readOwnDataProperty(value, "bound");
135
+ return typeof bound === "number" &&
136
+ Number.isInteger(bound) &&
137
+ bound >= 0 &&
73
138
  isSingleDepNode(value, deps, "value", nodeCount);
139
+ }
74
140
  case NodeTag.Regex:
75
- return isPlainRegExp(value["regex"]) &&
76
- typeof value["name"] === "string" &&
141
+ return isPlainRegExp(readOwnDataProperty(value, "regex")) &&
142
+ typeof readOwnDataProperty(value, "name") === "string" &&
77
143
  isSingleDepNode(value, deps, "value", nodeCount);
78
144
  case NodeTag.HasOwn:
79
145
  case NodeTag.HasOwnData:
80
- return typeof value["key"] === "string" &&
146
+ return typeof readOwnDataProperty(value, "key") === "string" &&
81
147
  isSingleDepNode(value, deps, "object", nodeCount);
82
148
  case NodeTag.StrictKeys:
83
- return isStringArray(value["keys"]) &&
149
+ return isStringArray(readOwnDataProperty(value, "keys")) &&
84
150
  isSingleDepNode(value, deps, "object", nodeCount);
85
151
  case NodeTag.ArrayEvery:
86
- return isSchemaValue(value["item"]) &&
152
+ return isSchemaValue(readOwnDataProperty(value, "item")) &&
153
+ isGraphValueInner(readOwnDataProperty(value, "itemGraph"), state) &&
87
154
  isSingleDepNode(value, deps, "value", nodeCount);
88
155
  case NodeTag.TupleItems:
89
- return isSchemaArray(value["items"]) &&
156
+ return isTupleItemGraphsAligned(value, state) &&
90
157
  isSingleDepNode(value, deps, "value", nodeCount);
91
158
  case NodeTag.RecordEvery:
92
- return isSchemaValue(value["item"]) &&
159
+ return isSchemaValue(readOwnDataProperty(value, "item")) &&
160
+ isGraphValueInner(readOwnDataProperty(value, "itemGraph"), state) &&
93
161
  isSingleDepNode(value, deps, "value", nodeCount);
94
162
  case NodeTag.DiscriminantDispatch:
95
- return typeof value["key"] === "string" &&
96
- isStringArray(value["literals"]) &&
97
- isSchemaArray(value["schemas"]) &&
98
- isDiscriminantLookup(value["lookup"], value["literals"]) &&
99
- value["literals"].length === value["schemas"].length &&
163
+ return isDiscriminantDispatchNode(value, state) &&
164
+ isSingleDepNode(value, deps, "value", nodeCount);
165
+ case NodeTag.ObjectShape:
166
+ return isObjectShapePayload(value, state) &&
167
+ isSingleDepNode(value, deps, "value", nodeCount);
168
+ case NodeTag.UnionDispatch:
169
+ return isUnionDispatchNode(value, state) &&
170
+ isSingleDepNode(value, deps, "value", nodeCount);
171
+ case NodeTag.PrimitiveUnion:
172
+ return isPrimitiveUnionNode(value, state) &&
100
173
  isSingleDepNode(value, deps, "value", nodeCount);
101
174
  case NodeTag.SchemaCheck:
102
- return isSchemaValue(value["schema"]) &&
175
+ return isSchemaValue(readOwnDataProperty(value, "schema")) &&
103
176
  isSingleDepNode(value, deps, "value", nodeCount);
104
177
  case NodeTag.And:
105
- case NodeTag.Or:
106
- return isNodeIdArray(value["values"], nodeCount) &&
107
- sameNodeIds(deps, value["values"]);
178
+ case NodeTag.Or: {
179
+ const values = readOwnDataProperty(value, "values");
180
+ return isNodeIdArray(values, nodeCount) &&
181
+ sameNodeIds(deps, values);
182
+ }
108
183
  case NodeTag.Return:
109
184
  return isTwoDepNode(value, deps, "control", "value", nodeCount);
110
185
  default:
@@ -112,43 +187,73 @@ function isGraphNodeValue(value, index, nodeCount) {
112
187
  }
113
188
  }
114
189
  /**
115
- * @brief is leaf node value.
190
+ * @brief Validate payloads for dependency-free nodes.
191
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
192
+ * node ids and valid dependency edges.
193
+ * @param value Candidate node record.
194
+ * @param deps Dependency vector already read from the node.
195
+ * @returns True when the leaf payload matches Start, Param, or Const.
116
196
  */
117
197
  function isLeafNodeValue(value, deps) {
118
198
  if (deps.length !== 0) {
119
199
  return false;
120
200
  }
121
- switch (value["tag"]) {
201
+ switch (readOwnDataProperty(value, "tag")) {
122
202
  case NodeTag.Start:
123
203
  return true;
124
204
  case NodeTag.Param:
125
- return typeof value["name"] === "string";
126
- case NodeTag.Const:
127
- return isLiteralValue(value["value"]);
205
+ return typeof readOwnDataProperty(value, "name") === "string";
206
+ case NodeTag.Const: {
207
+ const literal = readOwnDataProperty(value, "value");
208
+ return !isMissingDataProperty(literal) && isLiteralValue(literal);
209
+ }
128
210
  default:
129
211
  return false;
130
212
  }
131
213
  }
132
214
  /**
133
- * @brief is single dep node.
215
+ * @brief Validate a node whose named edge mirrors one dependency.
216
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
217
+ * node ids and valid dependency edges.
218
+ * @param value Candidate node record.
219
+ * @param deps Dependency vector from the same node.
220
+ * @param field Named edge field that must equal deps[0].
221
+ * @param nodeCount Total arena size for bounds.
222
+ * @returns True when the edge is in range and exactly mirrors the dependency.
134
223
  */
135
224
  function isSingleDepNode(value, deps, field, nodeCount) {
225
+ const fieldValue = readOwnDataProperty(value, field);
136
226
  return deps.length === 1 &&
137
- isNodeId(value[field], nodeCount) &&
138
- deps[0] === value[field];
227
+ isNodeId(fieldValue, nodeCount) &&
228
+ deps[0] === fieldValue;
139
229
  }
140
230
  /**
141
- * @brief is two dep node.
231
+ * @brief Validate a node whose named edges mirror two dependencies.
232
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
233
+ * node ids and valid dependency edges.
234
+ * @param value Candidate node record.
235
+ * @param deps Dependency vector from the same node.
236
+ * @param leftField First named edge field.
237
+ * @param rightField Second named edge field.
238
+ * @param nodeCount Total arena size for bounds.
239
+ * @returns True when both named edges are in range and mirror `deps`.
142
240
  */
143
241
  function isTwoDepNode(value, deps, leftField, rightField, nodeCount) {
242
+ const left = readOwnDataProperty(value, leftField);
243
+ const right = readOwnDataProperty(value, rightField);
144
244
  return deps.length === 2 &&
145
- isNodeId(value[leftField], nodeCount) &&
146
- isNodeId(value[rightField], nodeCount) &&
147
- deps[0] === value[leftField] &&
148
- deps[1] === value[rightField];
245
+ isNodeId(left, nodeCount) &&
246
+ isNodeId(right, nodeCount) &&
247
+ deps[0] === left &&
248
+ deps[1] === right;
149
249
  }
150
250
  /**
151
- * @brief is node id.
251
+ * @brief Validate a graph-local arena index.
252
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
253
+ * node ids and valid dependency edges.
254
+ * @param value Candidate node id.
255
+ * @param nodeCount Total arena size.
256
+ * @returns True when the id is an integer inside the arena.
152
257
  */
153
258
  function isNodeId(value, nodeCount) {
154
259
  return typeof value === "number" &&
@@ -157,7 +262,12 @@ function isNodeId(value, nodeCount) {
157
262
  value < nodeCount;
158
263
  }
159
264
  /**
160
- * @brief is node id array.
265
+ * @brief Validate a dense dependency vector.
266
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
267
+ * node ids and valid dependency edges.
268
+ * @param value Candidate dependency list.
269
+ * @param nodeCount Total arena size for every dependency.
270
+ * @returns True when every dependency points inside the arena.
161
271
  */
162
272
  function isNodeIdArray(value, nodeCount) {
163
273
  if (!isUnknownArray(value)) {
@@ -171,7 +281,12 @@ function isNodeIdArray(value, nodeCount) {
171
281
  return true;
172
282
  }
173
283
  /**
174
- * @brief same node ids.
284
+ * @brief Compare two dependency vectors without allocating.
285
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
286
+ * node ids and valid dependency edges.
287
+ * @param left First dependency vector.
288
+ * @param right Second dependency vector.
289
+ * @returns True when both vectors contain the same node ids in the same order.
175
290
  */
176
291
  function sameNodeIds(left, right) {
177
292
  if (left.length !== right.length) {
@@ -185,7 +300,11 @@ function sameNodeIds(left, right) {
185
300
  return true;
186
301
  }
187
302
  /**
188
- * @brief is string array.
303
+ * @brief Validate a dense vector of graph-owned strings.
304
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
305
+ * node ids and valid dependency edges.
306
+ * @param value Candidate string vector.
307
+ * @returns True when every slot is a string.
189
308
  */
190
309
  function isStringArray(value) {
191
310
  if (!isUnknownArray(value)) {
@@ -199,7 +318,11 @@ function isStringArray(value) {
199
318
  return true;
200
319
  }
201
320
  /**
202
- * @brief is schema array.
321
+ * @brief Validate a dense vector of embedded schema payloads.
322
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
323
+ * node ids and valid dependency edges.
324
+ * @param value Candidate schema vector.
325
+ * @returns True when every slot is accepted by schema validation.
203
326
  */
204
327
  function isSchemaArray(value) {
205
328
  if (!isUnknownArray(value)) {
@@ -213,7 +336,245 @@ function isSchemaArray(value) {
213
336
  return true;
214
337
  }
215
338
  /**
216
- * @brief is discriminant lookup.
339
+ * @brief Validate tuple item schemas and lowered child graphs as parallel arrays.
340
+ * @details IR helpers preserve Sea-of-Nodes invariants before graphs cross optimizer,
341
+ * compiler, or public introspection boundaries.
342
+ * @param value Candidate TupleItems node.
343
+ * @param state Shared recursion state for child graphs.
344
+ * @returns True when item schemas and item graphs have the same arity.
345
+ */
346
+ function isTupleItemGraphsAligned(value, state) {
347
+ const items = readOwnDataProperty(value, "items");
348
+ const itemGraphs = readOwnDataProperty(value, "itemGraphs");
349
+ return isSchemaArray(items) &&
350
+ isGraphArray(itemGraphs, state) &&
351
+ items.length === itemGraphs.length;
352
+ }
353
+ /**
354
+ * @brief Validate the dispatch table for discriminated-union graph nodes.
355
+ * @details IR helpers preserve Sea-of-Nodes invariants before graphs cross optimizer,
356
+ * compiler, or public introspection boundaries.
357
+ * @param value Candidate DiscriminantDispatch node.
358
+ * @param state Shared recursion state for child graphs.
359
+ * @returns True when literal, schema, graph, and lookup vectors agree.
360
+ */
361
+ function isDiscriminantDispatchNode(value, state) {
362
+ const key = readOwnDataProperty(value, "key");
363
+ const literals = readOwnDataProperty(value, "literals");
364
+ const schemas = readOwnDataProperty(value, "schemas");
365
+ const graphs = readOwnDataProperty(value, "graphs");
366
+ const lookup = readOwnDataProperty(value, "lookup");
367
+ return typeof key === "string" &&
368
+ isStringArray(literals) &&
369
+ isSchemaArray(schemas) &&
370
+ isGraphArray(graphs, state) &&
371
+ isDiscriminantLookup(lookup, literals) &&
372
+ literals.length === schemas.length &&
373
+ literals.length === graphs.length;
374
+ }
375
+ /**
376
+ * @brief Validate object-shape payload redundancy.
377
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
378
+ * node ids and valid dependency edges.
379
+ * @param value Candidate ObjectShape node.
380
+ * @param state Shared recursion state for property graphs.
381
+ * @returns True when entries, keys, mode, and all-required metadata agree.
382
+ */
383
+ function isObjectShapePayload(value, state) {
384
+ const entries = readOwnDataProperty(value, "entries");
385
+ const keys = readOwnDataProperty(value, "keys");
386
+ const mode = readOwnDataProperty(value, "mode");
387
+ const allRequired = readOwnDataProperty(value, "allRequired");
388
+ return isObjectShapeEntries(entries, state) &&
389
+ isStringArray(keys) &&
390
+ objectShapeEntriesMatchKeys(entries, keys) &&
391
+ isObjectModeTag(mode) &&
392
+ typeof allRequired === "boolean" &&
393
+ allRequired === objectShapeAllRequired(entries);
394
+ }
395
+ /**
396
+ * @brief Validate general union-dispatch payload vectors.
397
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
398
+ * node ids and valid dependency edges.
399
+ * @param value Candidate UnionDispatch node.
400
+ * @param state Shared recursion state for option graphs.
401
+ * @returns True when options, graphs, and masks have matching lengths.
402
+ */
403
+ function isUnionDispatchNode(value, state) {
404
+ const options = readOwnDataProperty(value, "options");
405
+ const graphs = readOwnDataProperty(value, "graphs");
406
+ const masks = readOwnDataProperty(value, "masks");
407
+ return isSchemaArray(options) &&
408
+ isGraphArray(graphs, state) &&
409
+ isUnionMaskArray(masks) &&
410
+ options.length === graphs.length &&
411
+ options.length === masks.length;
412
+ }
413
+ /**
414
+ * @brief Validate primitive-only union dispatch metadata.
415
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
416
+ * node ids and valid dependency edges.
417
+ * @param value Candidate PrimitiveUnion node.
418
+ * @param state Shared recursion state for option graphs.
419
+ * @returns True when primitive masks line up with option graphs.
420
+ */
421
+ function isPrimitiveUnionNode(value, state) {
422
+ const graphs = readOwnDataProperty(value, "graphs");
423
+ const masks = readOwnDataProperty(value, "masks");
424
+ return isGraphArray(graphs, state) &&
425
+ isPrimitiveUnionMaskArray(masks) &&
426
+ graphs.length === masks.length;
427
+ }
428
+ /**
429
+ * @brief Validate object property entries carried by an ObjectShape node.
430
+ * @details IR helpers preserve Sea-of-Nodes invariants before graphs cross optimizer,
431
+ * compiler, or public introspection boundaries.
432
+ * @param value Candidate entry vector.
433
+ * @param state Shared recursion state for entry graphs.
434
+ * @returns True when each entry owns key, schema, graph, and presence metadata.
435
+ */
436
+ function isObjectShapeEntries(value, state) {
437
+ if (!isUnknownArray(value)) {
438
+ return false;
439
+ }
440
+ for (let index = 0; index < value.length; index += 1) {
441
+ const entry = value[index];
442
+ if (!isRecord(entry)) {
443
+ return false;
444
+ }
445
+ if (typeof readOwnDataProperty(entry, "key") !== "string" ||
446
+ !isSchemaValue(readOwnDataProperty(entry, "schema")) ||
447
+ !isGraphValueInner(readOwnDataProperty(entry, "graph"), state) ||
448
+ !isPresenceTag(readOwnDataProperty(entry, "presence"))) {
449
+ return false;
450
+ }
451
+ }
452
+ return true;
453
+ }
454
+ /**
455
+ * @brief Validate a dense vector of child graphs.
456
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
457
+ * node ids and valid dependency edges.
458
+ * @param value Candidate child graph vector.
459
+ * @param state Shared recursion state.
460
+ * @returns True when every slot is a valid graph.
461
+ */
462
+ function isGraphArray(value, state) {
463
+ if (!isUnknownArray(value)) {
464
+ return false;
465
+ }
466
+ for (let index = 0; index < value.length; index += 1) {
467
+ if (!isGraphValueInner(value[index], state)) {
468
+ return false;
469
+ }
470
+ }
471
+ return true;
472
+ }
473
+ /**
474
+ * @brief Check that object-shape entries preserve key vector order.
475
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
476
+ * node ids and valid dependency edges.
477
+ * @param entries ObjectShape entries.
478
+ * @param keys Parallel key vector emitted by lowering.
479
+ * @returns True when each entry key matches the same index in `keys`.
480
+ */
481
+ function objectShapeEntriesMatchKeys(entries, keys) {
482
+ if (entries.length !== keys.length) {
483
+ return false;
484
+ }
485
+ for (let index = 0; index < entries.length; index += 1) {
486
+ const entry = entries[index];
487
+ if (!isRecord(entry) || readOwnDataProperty(entry, "key") !== keys[index]) {
488
+ return false;
489
+ }
490
+ }
491
+ return true;
492
+ }
493
+ /**
494
+ * @brief Recompute the all-required flag from object-shape entries.
495
+ * @param entries ObjectShape entries.
496
+ * @returns True when every property is required.
497
+ * @details The stored flag enables generated fast paths. Recomputing it during
498
+ * graph admission prevents a forged graph from lying about optionality.
499
+ */
500
+ function objectShapeAllRequired(entries) {
501
+ for (let index = 0; index < entries.length; index += 1) {
502
+ const entry = entries[index];
503
+ if (!isRecord(entry) ||
504
+ readOwnDataProperty(entry, "presence") !== PresenceTag.Required) {
505
+ return false;
506
+ }
507
+ }
508
+ return true;
509
+ }
510
+ /**
511
+ * @brief Validate the closed presence tag set used by object entries.
512
+ * @details IR helpers preserve Sea-of-Nodes invariants before graphs cross optimizer,
513
+ * compiler, or public introspection boundaries.
514
+ * @param value Candidate presence marker.
515
+ * @returns True for required or optional.
516
+ */
517
+ function isPresenceTag(value) {
518
+ return value === PresenceTag.Required || value === PresenceTag.Optional;
519
+ }
520
+ /**
521
+ * @brief Validate the closed object-mode tag set.
522
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
523
+ * node ids and valid dependency edges.
524
+ * @param value Candidate object mode.
525
+ * @returns True for passthrough or strict mode.
526
+ */
527
+ function isObjectModeTag(value) {
528
+ return value === ObjectModeTag.Passthrough || value === ObjectModeTag.Strict;
529
+ }
530
+ /**
531
+ * @brief Validate root-kind bit masks for union dispatch.
532
+ * @param value Candidate mask vector.
533
+ * @returns True when every mask is a small safe integer.
534
+ * @details The upper bound is intentionally tied to the current root-kind mask
535
+ * width so invalid high bits cannot steer optimizer logic.
536
+ */
537
+ function isUnionMaskArray(value) {
538
+ if (!isUnknownArray(value)) {
539
+ return false;
540
+ }
541
+ for (let index = 0; index < value.length; index += 1) {
542
+ const mask = value[index];
543
+ if (typeof mask !== "number" ||
544
+ !Number.isSafeInteger(mask) ||
545
+ mask < 0 ||
546
+ mask > 1023) {
547
+ return false;
548
+ }
549
+ }
550
+ return true;
551
+ }
552
+ /**
553
+ * @brief Validate masks restricted to primitive root kinds.
554
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
555
+ * node ids and valid dependency edges.
556
+ * @param value Candidate mask vector.
557
+ * @returns True when no object/function bits are present.
558
+ */
559
+ function isPrimitiveUnionMaskArray(value) {
560
+ if (!isUnionMaskArray(value)) {
561
+ return false;
562
+ }
563
+ for (let index = 0; index < value.length; index += 1) {
564
+ const mask = value[index];
565
+ if (typeof mask !== "number" || (mask & ~127) !== 0) {
566
+ return false;
567
+ }
568
+ }
569
+ return true;
570
+ }
571
+ /**
572
+ * @brief Validate literal-to-case-index lookup metadata.
573
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
574
+ * node ids and valid dependency edges.
575
+ * @param value Candidate lookup table.
576
+ * @param literals Parallel literal vector.
577
+ * @returns True when the table maps each literal to its vector index.
217
578
  */
218
579
  function isDiscriminantLookup(value, literals) {
219
580
  if (!isRecord(value)) {
@@ -226,14 +587,18 @@ function isDiscriminantLookup(value, literals) {
226
587
  for (let index = 0; index < literals.length; index += 1) {
227
588
  const literal = literals[index];
228
589
  if (typeof literal !== "string" ||
229
- value[literal] !== index) {
590
+ readOwnDataProperty(value, literal) !== index) {
230
591
  return false;
231
592
  }
232
593
  }
233
594
  return true;
234
595
  }
235
596
  /**
236
- * @brief is record.
597
+ * @brief Accept a graph metadata record with data-only own fields.
598
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
599
+ * node ids and valid dependency edges.
600
+ * @param value Candidate record.
601
+ * @returns True when no accessor fields or arrays are present.
237
602
  */
238
603
  function isRecord(value) {
239
604
  return typeof value === "object" &&
@@ -242,14 +607,22 @@ function isRecord(value) {
242
607
  hasOnlyDataProperties(value);
243
608
  }
244
609
  /**
245
- * @brief is unknown array.
610
+ * @brief Accept a dense graph metadata vector.
611
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
612
+ * node ids and valid dependency edges.
613
+ * @param value Candidate vector.
614
+ * @returns True when it has no accessors, inherited slots, or holes.
246
615
  */
247
616
  function isUnknownArray(value) {
248
- return Array.isArray(value) && hasOnlyDataProperties(value);
617
+ return Array.isArray(value) &&
618
+ hasOnlyDataProperties(value) &&
619
+ hasDenseDataSlots(value);
249
620
  }
250
621
  /**
251
- * @brief has only data properties.
252
- * @details Rejects accessor descriptors before graph internals read fields by key.
622
+ * @brief Reject accessor descriptors before graph internals read fields.
623
+ * @details IR helpers preserve Sea-of-Nodes invariants before graphs cross optimizer,
624
+ * compiler, or public introspection boundaries.
625
+ * @param value Object whose own descriptor table is inspected.
253
626
  * @returns True when every own property is backed by a data slot.
254
627
  */
255
628
  function hasOnlyDataProperties(value) {
@@ -269,3 +642,46 @@ function hasOnlyDataProperties(value) {
269
642
  }
270
643
  return true;
271
644
  }
645
+ /**
646
+ * @brief Require all array indexes to be own data slots.
647
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
648
+ * node ids and valid dependency edges.
649
+ * @param value Candidate graph vector.
650
+ * @returns True when each index from 0 to length - 1 exists as data.
651
+ */
652
+ function hasDenseDataSlots(value) {
653
+ for (let index = 0; index < value.length; index += 1) {
654
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
655
+ if (descriptor === undefined ||
656
+ !Object.prototype.hasOwnProperty.call(descriptor, "value")) {
657
+ return false;
658
+ }
659
+ }
660
+ return true;
661
+ }
662
+ /**
663
+ * @brief Read one own data slot from graph metadata.
664
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
665
+ * node ids and valid dependency edges.
666
+ * @param value Object being validated.
667
+ * @param key Field name or symbol to read.
668
+ * @returns Stored value or the missing-data sentinel.
669
+ */
670
+ function readOwnDataProperty(value, key) {
671
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
672
+ if (descriptor === undefined ||
673
+ !Object.prototype.hasOwnProperty.call(descriptor, "value")) {
674
+ return missingDataProperty;
675
+ }
676
+ return descriptor.value;
677
+ }
678
+ /**
679
+ * @brief Test for the graph metadata missing-data sentinel.
680
+ * @details Graph validation protects optimizer and compiler passes before they assume dense
681
+ * node ids and valid dependency edges.
682
+ * @param value Candidate value returned by readOwnDataProperty.
683
+ * @returns True when the field was absent or not a data descriptor.
684
+ */
685
+ function isMissingDataProperty(value) {
686
+ return value === missingDataProperty;
687
+ }