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