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,30 +1,88 @@
1
1
  /**
2
2
  * @file compile/check-composite.ts
3
3
  * @brief Composite diagnostic validator snippets.
4
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
5
+ * stable across runtime and AOT emission.
4
6
  */
5
- import { ObjectModeTag, PresenceTag, SchemaTag } from "../kind/index.js";
6
- import { pushKeyset, pushLiteral, stringRef } from "./context.js";
7
- import { emitIssue, emitIssueExpr } from "./issue.js";
7
+ import { ArrayCheckTag, ObjectModeTag, PresenceTag, SchemaTag } from "../kind/index.js";
8
+ import { schemaCanAcceptUndefined } from "../schema/index.js";
9
+ import { pushLiteral, stringRef } from "./context.js";
10
+ import { emitIssue, emitIssueAtSegment, emitIssueAtTwoSegments, emitIssueExprAtSegment } from "./issue.js";
11
+ import { emitLeafCheckAtSegment, emitLeafCheckAtTwoSegments, emitUndefinedLeafCheckAtTwoSegments, emitUndefinedLeafCheckAtSegment } from "./check-scalar.js";
8
12
  import { stringLiteral } from "./names.js";
9
13
  /**
10
14
  * @brief emit array check.
15
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
16
+ * stable across runtime and AOT emission.
17
+ * @param item Schema applied to each logical array slot.
18
+ * @param value Generated expression for the candidate value.
19
+ * @param path Generated expression for the mutable diagnostic path.
20
+ * @param issues Generated expression for the diagnostic buffer.
21
+ * @param context Shared code-generation context.
22
+ * @param emitChild Fallback emitter for non-leaf child validators.
23
+ * @returns JavaScript source for array diagnostics.
11
24
  */
12
- export function emitArrayCheck(item, value, path, issues, context, emitChild) {
13
- const itemFunction = emitChild(item, context);
25
+ export function emitArrayCheck(schema, value, path, issues, context, emitChild) {
26
+ if (isUnsafeMode(context)) {
27
+ return emitUnsafeArrayCheck(schema, value, path, issues, context, emitChild);
28
+ }
29
+ const item = schema.item;
30
+ const itemValue = "av";
31
+ const itemLeaf = emitLeafCheckAtSegment(item, itemValue, path, "i", issues, context);
32
+ const missingLeaf = itemLeaf === undefined
33
+ ? undefined
34
+ : emitUndefinedLeafCheckAtSegment(item, path, "i", issues, context);
35
+ let missingCheck;
36
+ let itemCheck;
37
+ if (itemLeaf === undefined || missingLeaf === undefined) {
38
+ const itemFunction = emitChild(item, context);
39
+ missingCheck = `${path}.push(i);${itemFunction}(undefined,${path},${issues});${path}.pop();`;
40
+ itemCheck = `${path}.push(i);${itemFunction}(${itemValue},${path},${issues});${path}.pop();`;
41
+ }
42
+ else {
43
+ missingCheck = missingLeaf;
44
+ itemCheck = itemLeaf;
45
+ }
46
+ const presentCheck = itemCheck === ""
47
+ ? ""
48
+ : `const ${itemValue}=d.value;${itemCheck}`;
49
+ if (schemaCanAcceptUndefined(item)) {
50
+ /*
51
+ * Generated diagnostics mirror the interpreter: holes are valid only
52
+ * after the item schema admits undefined, while present accessors still
53
+ * produce a data-property issue instead of executing.
54
+ */
55
+ return [
56
+ `if(!Array.isArray(${value})){${emitIssue(issues, path, "expected_array", "array", `a(${value})`)}return;}`,
57
+ emitArrayLengthIssues(schema, value, path, issues),
58
+ `const xs=Object.getOwnPropertyNames(${value});`,
59
+ "for(let xi=0;xi<xs.length;xi+=1){",
60
+ "const key=xs[xi];",
61
+ `if(!ai(key,${value}.length))continue;`,
62
+ "const i=Number(key);",
63
+ `const d=gp(${value},key);`,
64
+ `if(d!==undefined&&!h.call(d,"value")){${emitIssueAtSegment(issues, path, "i", "expected_array", "data property", stringLiteral("accessor"))}}else if(d!==undefined){${presentCheck}}`,
65
+ "}"
66
+ ].join("");
67
+ }
14
68
  return [
15
69
  `if(!Array.isArray(${value})){${emitIssue(issues, path, "expected_array", "array", `a(${value})`)}return;}`,
70
+ emitArrayLengthIssues(schema, value, path, issues),
16
71
  `for(let i=0;i<${value}.length;i+=1){`,
17
72
  `const d=gp(${value},i);`,
18
- `${path}.push(i);`,
19
- `if(d!==undefined&&!h.call(d,"value")){${emitIssue(issues, path, "expected_array", "data property", stringLiteral("accessor"))}}else{${itemFunction}(d===undefined?undefined:d.value,${path},${issues});}`,
20
- `${path}.pop();`,
73
+ `if(d===undefined){${missingCheck}}else if(!h.call(d,"value")){${emitIssueAtSegment(issues, path, "i", "expected_array", "data property", stringLiteral("accessor"))}}else{${presentCheck}}`,
21
74
  "}"
22
75
  ].join("");
23
76
  }
24
77
  /**
25
78
  * @brief emit tuple check.
79
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
80
+ * stable across runtime and AOT emission.
26
81
  */
27
82
  export function emitTupleCheck(items, value, path, issues, context, emitChild) {
83
+ if (isUnsafeMode(context)) {
84
+ return emitUnsafeTupleCheck(items, value, path, issues, context, emitChild);
85
+ }
28
86
  const parts = [
29
87
  `if(!Array.isArray(${value})){${emitIssue(issues, path, "expected_tuple", "tuple", `a(${value})`)}return;}`,
30
88
  `if(${value}.length!==${String(items.length)}){${emitIssue(issues, path, "expected_tuple_length", `length ${String(items.length)}`, `"length "+String(${value}.length)`)}}`,
@@ -35,48 +93,497 @@ export function emitTupleCheck(items, value, path, issues, context, emitChild) {
35
93
  if (item === undefined) {
36
94
  continue;
37
95
  }
96
+ const indexExpression = String(index);
97
+ const itemValue = `tv${indexExpression}`;
98
+ const itemLeaf = emitLeafCheckAtSegment(item, itemValue, path, indexExpression, issues, context);
99
+ const missingLeaf = itemLeaf === undefined
100
+ ? undefined
101
+ : emitUndefinedLeafCheckAtSegment(item, path, indexExpression, issues, context);
102
+ let missingCheck;
103
+ let itemCheck;
104
+ if (itemLeaf === undefined || missingLeaf === undefined) {
105
+ const itemFunction = emitChild(item, context);
106
+ missingCheck = `${path}.push(${indexExpression});${itemFunction}(undefined,${path},${issues});${path}.pop();`;
107
+ itemCheck = `${path}.push(${indexExpression});${itemFunction}(${itemValue},${path},${issues});${path}.pop();`;
108
+ }
109
+ else {
110
+ missingCheck = missingLeaf;
111
+ itemCheck = itemLeaf;
112
+ }
113
+ const presentCheck = itemCheck === ""
114
+ ? ""
115
+ : `const ${itemValue}=d.value;${itemCheck}`;
116
+ parts.push(`if(${indexExpression}<n){const d=gp(${value},${indexExpression});if(d===undefined){${missingCheck}}else if(!h.call(d,"value")){${emitIssueAtSegment(issues, path, indexExpression, "expected_tuple", "data property", stringLiteral("accessor"))}}else{${presentCheck}}}`);
117
+ }
118
+ return parts.join("");
119
+ }
120
+ /**
121
+ * @brief Execute emit unsafe array check.
122
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
123
+ */
124
+ function emitUnsafeArrayCheck(schema, value, path, issues, context, emitChild) {
125
+ const item = schema.item;
126
+ const itemValue = "av";
127
+ const itemLeaf = emitLeafCheckAtSegment(item, itemValue, path, "i", issues, context);
128
+ let itemCheck;
129
+ if (itemLeaf === undefined) {
38
130
  const itemFunction = emitChild(item, context);
39
- parts.push(`if(${String(index)}<n){const d=gp(${value},${String(index)});${path}.push(${String(index)});if(d!==undefined&&!h.call(d,"value")){${emitIssue(issues, path, "expected_tuple", "data property", stringLiteral("accessor"))}}else{${itemFunction}(d===undefined?undefined:d.value,${path},${issues});}${path}.pop();}`);
131
+ itemCheck = `${path}.push(i);${itemFunction}(${itemValue},${path},${issues});${path}.pop();`;
132
+ }
133
+ else {
134
+ itemCheck = itemLeaf;
135
+ }
136
+ const parts = [
137
+ `if(!Array.isArray(${value})){${emitIssue(issues, path, "expected_array", "array", `a(${value})`)}return;}`
138
+ ];
139
+ parts.push(emitArrayLengthIssues(schema, value, path, issues));
140
+ if (itemCheck !== "") {
141
+ parts.push(`for(let i=0;i<${value}.length;i+=1){`, `const ${itemValue}=${value}[i];`, itemCheck, "}");
142
+ }
143
+ return parts.join("");
144
+ }
145
+ /**
146
+ * @brief Emit root-level array length diagnostics.
147
+ * @param schema Array schema with normalized checks.
148
+ * @param value Generated expression for the candidate array.
149
+ * @param path Generated expression for the current diagnostic path.
150
+ * @param issues Generated expression for the issue buffer.
151
+ * @returns JavaScript source that appends zero or more length issues.
152
+ */
153
+ function emitArrayLengthIssues(schema, value, path, issues) {
154
+ const chunks = [];
155
+ const checks = schema.checks;
156
+ for (let index = 0; index < checks.length; index += 1) {
157
+ const check = checks[index];
158
+ if (check === undefined) {
159
+ continue;
160
+ }
161
+ switch (check.tag) {
162
+ case ArrayCheckTag.Min:
163
+ chunks.push(`if(${value}.length<${String(check.value)}){${emitIssue(issues, path, "expected_min_length", `length >= ${String(check.value)}`, `"length "+String(${value}.length)`)}}`);
164
+ break;
165
+ case ArrayCheckTag.Max:
166
+ chunks.push(`if(${value}.length>${String(check.value)}){${emitIssue(issues, path, "expected_max_length", `length <= ${String(check.value)}`, `"length "+String(${value}.length)`)}}`);
167
+ break;
168
+ }
169
+ }
170
+ return chunks.join("");
171
+ }
172
+ /**
173
+ * @brief Emit one-segment array length diagnostics.
174
+ * @param schema Array schema with normalized checks.
175
+ * @param value Generated expression for the candidate array.
176
+ * @param path Generated expression for the current diagnostic path.
177
+ * @param segmentExpression Generated path segment for the array field.
178
+ * @param issues Generated expression for the issue buffer.
179
+ * @returns JavaScript source that appends zero or more length issues.
180
+ */
181
+ function emitArrayLengthIssuesAtSegment(schema, value, path, segmentExpression, issues) {
182
+ const chunks = [];
183
+ const checks = schema.checks;
184
+ for (let index = 0; index < checks.length; index += 1) {
185
+ const check = checks[index];
186
+ if (check === undefined) {
187
+ continue;
188
+ }
189
+ switch (check.tag) {
190
+ case ArrayCheckTag.Min:
191
+ chunks.push(`if(${value}.length<${String(check.value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_min_length", `length >= ${String(check.value)}`, `"length "+String(${value}.length)`)}}`);
192
+ break;
193
+ case ArrayCheckTag.Max:
194
+ chunks.push(`if(${value}.length>${String(check.value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_max_length", `length <= ${String(check.value)}`, `"length "+String(${value}.length)`)}}`);
195
+ break;
196
+ }
197
+ }
198
+ return chunks.join("");
199
+ }
200
+ /**
201
+ * @brief Execute emit unsafe tuple check.
202
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
203
+ */
204
+ function emitUnsafeTupleCheck(items, value, path, issues, context, emitChild) {
205
+ const parts = [
206
+ `if(!Array.isArray(${value})){${emitIssue(issues, path, "expected_tuple", "tuple", `a(${value})`)}return;}`,
207
+ `if(${value}.length!==${String(items.length)}){${emitIssue(issues, path, "expected_tuple_length", `length ${String(items.length)}`, `"length "+String(${value}.length)`)}}`,
208
+ `const n=${value}.length<${String(items.length)}?${value}.length:${String(items.length)};`
209
+ ];
210
+ for (let index = 0; index < items.length; index += 1) {
211
+ const item = items[index];
212
+ if (item === undefined) {
213
+ continue;
214
+ }
215
+ const indexExpression = String(index);
216
+ const itemValue = `tv${indexExpression}`;
217
+ const itemLeaf = emitLeafCheckAtSegment(item, itemValue, path, indexExpression, issues, context);
218
+ let itemCheck;
219
+ if (itemLeaf === undefined) {
220
+ const itemFunction = emitChild(item, context);
221
+ itemCheck = `${path}.push(${indexExpression});${itemFunction}(${itemValue},${path},${issues});${path}.pop();`;
222
+ }
223
+ else {
224
+ itemCheck = itemLeaf;
225
+ }
226
+ if (itemCheck !== "") {
227
+ parts.push(`if(${indexExpression}<n){const ${itemValue}=${value}[${indexExpression}];${itemCheck}}`);
228
+ }
229
+ }
230
+ return parts.join("");
231
+ }
232
+ /**
233
+ * @brief emit array check at one appended object-field segment.
234
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
235
+ * stable across runtime and AOT emission.
236
+ * @param item Schema applied to each logical array slot.
237
+ * @param value Generated expression for the candidate value.
238
+ * @param path Generated expression for the mutable diagnostic path.
239
+ * @param segmentExpression Generated parent path segment.
240
+ * @param issues Generated expression for the diagnostic buffer.
241
+ * @param context Shared code-generation context.
242
+ * @returns JavaScript source, or undefined when the caller must fall back.
243
+ */
244
+ function emitArrayCheckAtSegment(schema, value, path, segmentExpression, issues, context) {
245
+ if (isUnsafeMode(context)) {
246
+ return emitUnsafeArrayCheckAtSegment(schema, value, path, segmentExpression, issues, context);
40
247
  }
248
+ const item = schema.item;
249
+ const itemValue = "av";
250
+ const itemLeaf = emitLeafCheckAtTwoSegments(item, itemValue, path, segmentExpression, "i", issues, context);
251
+ const missingLeaf = itemLeaf === undefined
252
+ ? undefined
253
+ : emitUndefinedLeafCheckAtTwoSegments(item, path, segmentExpression, "i", issues, context);
254
+ if (itemLeaf === undefined || missingLeaf === undefined) {
255
+ return undefined;
256
+ }
257
+ const presentCheck = itemLeaf === ""
258
+ ? ""
259
+ : `const ${itemValue}=vd.value;${itemLeaf}`;
260
+ if (schemaCanAcceptUndefined(item)) {
261
+ /*
262
+ * The two-segment variant is used inside object fields. It keeps the
263
+ * parent key and array index inline so diagnostics avoid path-stack churn.
264
+ */
265
+ return [
266
+ `if(!Array.isArray(${value})){${emitIssueAtSegment(issues, path, segmentExpression, "expected_array", "array", `a(${value})`)}}else{`,
267
+ emitArrayLengthIssuesAtSegment(schema, value, path, segmentExpression, issues),
268
+ `const xs=Object.getOwnPropertyNames(${value});`,
269
+ "for(let xi=0;xi<xs.length;xi+=1){",
270
+ "const key=xs[xi];",
271
+ `if(!ai(key,${value}.length))continue;`,
272
+ "const i=Number(key);",
273
+ `const vd=gp(${value},key);`,
274
+ `if(vd!==undefined&&!h.call(vd,"value")){${emitIssueAtTwoSegments(issues, path, segmentExpression, "i", "expected_array", "data property", stringLiteral("accessor"))}}else if(vd!==undefined){${presentCheck}}`,
275
+ "}",
276
+ "}"
277
+ ].join("");
278
+ }
279
+ return [
280
+ `if(!Array.isArray(${value})){${emitIssueAtSegment(issues, path, segmentExpression, "expected_array", "array", `a(${value})`)}}else{`,
281
+ emitArrayLengthIssuesAtSegment(schema, value, path, segmentExpression, issues),
282
+ `for(let i=0;i<${value}.length;i+=1){`,
283
+ `const vd=gp(${value},i);`,
284
+ `if(vd===undefined){${missingLeaf}}else if(!h.call(vd,"value")){${emitIssueAtTwoSegments(issues, path, segmentExpression, "i", "expected_array", "data property", stringLiteral("accessor"))}}else{${presentCheck}}`,
285
+ "}",
286
+ "}"
287
+ ].join("");
288
+ }
289
+ /**
290
+ * @brief emit tuple check at one appended object-field segment.
291
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
292
+ * stable across runtime and AOT emission.
293
+ */
294
+ function emitTupleCheckAtSegment(items, value, path, segmentExpression, issues, context) {
295
+ if (isUnsafeMode(context)) {
296
+ return emitUnsafeTupleCheckAtSegment(items, value, path, segmentExpression, issues, context);
297
+ }
298
+ const parts = [
299
+ `if(!Array.isArray(${value})){${emitIssueAtSegment(issues, path, segmentExpression, "expected_tuple", "tuple", `a(${value})`)}}else{`,
300
+ `if(${value}.length!==${String(items.length)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_tuple_length", `length ${String(items.length)}`, `"length "+String(${value}.length)`)}}`,
301
+ `const n=${value}.length<${String(items.length)}?${value}.length:${String(items.length)};`
302
+ ];
303
+ for (let index = 0; index < items.length; index += 1) {
304
+ const item = items[index];
305
+ if (item === undefined) {
306
+ continue;
307
+ }
308
+ const indexExpression = String(index);
309
+ const itemValue = `tv${indexExpression}`;
310
+ const itemLeaf = emitLeafCheckAtTwoSegments(item, itemValue, path, segmentExpression, indexExpression, issues, context);
311
+ const missingLeaf = itemLeaf === undefined
312
+ ? undefined
313
+ : emitUndefinedLeafCheckAtTwoSegments(item, path, segmentExpression, indexExpression, issues, context);
314
+ if (itemLeaf === undefined || missingLeaf === undefined) {
315
+ return undefined;
316
+ }
317
+ const presentCheck = itemLeaf === ""
318
+ ? ""
319
+ : `const ${itemValue}=td.value;${itemLeaf}`;
320
+ parts.push(`if(${indexExpression}<n){const td=gp(${value},${indexExpression});if(td===undefined){${missingLeaf}}else if(!h.call(td,"value")){${emitIssueAtTwoSegments(issues, path, segmentExpression, indexExpression, "expected_tuple", "data property", stringLiteral("accessor"))}}else{${presentCheck}}}`);
321
+ }
322
+ parts.push("}");
323
+ return parts.join("");
324
+ }
325
+ /**
326
+ * @brief Execute emit unsafe array check at segment.
327
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
328
+ */
329
+ function emitUnsafeArrayCheckAtSegment(schema, value, path, segmentExpression, issues, context) {
330
+ const item = schema.item;
331
+ const itemLeaf = emitLeafCheckAtTwoSegments(item, "av", path, segmentExpression, "i", issues, context);
332
+ if (itemLeaf === undefined) {
333
+ return undefined;
334
+ }
335
+ const parts = [
336
+ `if(!Array.isArray(${value})){${emitIssueAtSegment(issues, path, segmentExpression, "expected_array", "array", `a(${value})`)}}`
337
+ ];
338
+ parts.push("else{", emitArrayLengthIssuesAtSegment(schema, value, path, segmentExpression, issues));
339
+ if (itemLeaf !== "") {
340
+ parts.push(`for(let i=0;i<${value}.length;i+=1){`, `const av=${value}[i];`, itemLeaf, "}");
341
+ }
342
+ parts.push("}");
343
+ return parts.join("");
344
+ }
345
+ /**
346
+ * @brief Execute emit unsafe tuple check at segment.
347
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
348
+ */
349
+ function emitUnsafeTupleCheckAtSegment(items, value, path, segmentExpression, issues, context) {
350
+ const parts = [
351
+ `if(!Array.isArray(${value})){${emitIssueAtSegment(issues, path, segmentExpression, "expected_tuple", "tuple", `a(${value})`)}}else{`,
352
+ `if(${value}.length!==${String(items.length)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_tuple_length", `length ${String(items.length)}`, `"length "+String(${value}.length)`)}}`,
353
+ `const n=${value}.length<${String(items.length)}?${value}.length:${String(items.length)};`
354
+ ];
355
+ for (let index = 0; index < items.length; index += 1) {
356
+ const item = items[index];
357
+ if (item === undefined) {
358
+ continue;
359
+ }
360
+ const indexExpression = String(index);
361
+ const itemValue = `tv${indexExpression}`;
362
+ const itemLeaf = emitLeafCheckAtTwoSegments(item, itemValue, path, segmentExpression, indexExpression, issues, context);
363
+ if (itemLeaf === undefined) {
364
+ return undefined;
365
+ }
366
+ if (itemLeaf !== "") {
367
+ parts.push(`if(${indexExpression}<n){const ${itemValue}=${value}[${indexExpression}];${itemLeaf}}`);
368
+ }
369
+ }
370
+ parts.push("}");
41
371
  return parts.join("");
42
372
  }
43
373
  /**
44
374
  * @brief emit record check.
375
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
376
+ * stable across runtime and AOT emission.
45
377
  */
46
378
  export function emitRecordCheck(item, value, path, issues, context, emitChild) {
47
- const itemFunction = emitChild(item, context);
379
+ if (isUnsafeMode(context)) {
380
+ return emitUnsafeRecordCheck(item, value, path, issues, context, emitChild);
381
+ }
382
+ const itemValue = "rv";
383
+ const itemLeaf = emitLeafCheckAtSegment(item, itemValue, path, "key", issues, context);
384
+ let itemCheck;
385
+ if (itemLeaf === undefined) {
386
+ const itemFunction = emitChild(item, context);
387
+ itemCheck = `${path}.push(key);${itemFunction}(${itemValue},${path},${issues});${path}.pop();`;
388
+ }
389
+ else {
390
+ itemCheck = itemLeaf;
391
+ }
392
+ const presentCheck = itemCheck === ""
393
+ ? ""
394
+ : `const ${itemValue}=d.value;${itemCheck}`;
395
+ return [
396
+ `if(${objectRejectExpression(value)}){${emitIssue(issues, path, "expected_record", "record", `a(${value})`)}return;}`,
397
+ `for(const key in ${value}){`,
398
+ `if(!h.call(${value},key))continue;`,
399
+ `const d=gp(${value},key);if(d===undefined||!h.call(d,"value")){${emitIssueAtSegment(issues, path, "key", "expected_record", "data property", stringLiteral("accessor or missing"))}}else{${presentCheck}}`,
400
+ "}"
401
+ ].join("");
402
+ }
403
+ /**
404
+ * @brief emit record check at one appended object-field segment.
405
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
406
+ * stable across runtime and AOT emission.
407
+ */
408
+ function emitRecordCheckAtSegment(item, value, path, segmentExpression, issues, context) {
409
+ if (isUnsafeMode(context)) {
410
+ return emitUnsafeRecordCheckAtSegment(item, value, path, segmentExpression, issues, context);
411
+ }
412
+ const itemValue = "rv";
413
+ const itemLeaf = emitLeafCheckAtTwoSegments(item, itemValue, path, segmentExpression, "key", issues, context);
414
+ if (itemLeaf === undefined) {
415
+ return undefined;
416
+ }
417
+ const presentCheck = itemLeaf === ""
418
+ ? ""
419
+ : `const ${itemValue}=rd.value;${itemLeaf}`;
48
420
  return [
49
- `if(!o(${value})){${emitIssue(issues, path, "expected_record", "record", `a(${value})`)}return;}`,
50
- `const ks=Object.keys(${value});`,
51
- "for(let i=0;i<ks.length;i+=1){",
52
- "const key=ks[i];",
53
- `if(key!==undefined){const d=g(${value},key);${path}.push(key);if(d===undefined){${emitIssue(issues, path, "expected_record", "data property", stringLiteral("accessor or missing"))}}else{${itemFunction}(d.value,${path},${issues});}${path}.pop();}`,
421
+ `if(${objectRejectExpression(value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_record", "record", `a(${value})`)}}else{`,
422
+ `for(const key in ${value}){`,
423
+ `if(!h.call(${value},key))continue;`,
424
+ `const rd=gp(${value},key);if(rd===undefined||!h.call(rd,"value")){${emitIssueAtTwoSegments(issues, path, segmentExpression, "key", "expected_record", "data property", stringLiteral("accessor or missing"))}}else{${presentCheck}}`,
425
+ "}",
54
426
  "}"
55
427
  ].join("");
56
428
  }
429
+ /**
430
+ * @brief Execute emit unsafe record check.
431
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
432
+ */
433
+ function emitUnsafeRecordCheck(item, value, path, issues, context, emitChild) {
434
+ const itemValue = "rv";
435
+ const itemLeaf = emitLeafCheckAtSegment(item, itemValue, path, "key", issues, context);
436
+ let itemCheck;
437
+ if (itemLeaf === undefined) {
438
+ const itemFunction = emitChild(item, context);
439
+ itemCheck = `${path}.push(key);${itemFunction}(${itemValue},${path},${issues});${path}.pop();`;
440
+ }
441
+ else {
442
+ itemCheck = itemLeaf;
443
+ }
444
+ const parts = [
445
+ `if(${objectRejectExpression(value)}){${emitIssue(issues, path, "expected_record", "record", `a(${value})`)}return;}`
446
+ ];
447
+ if (itemCheck !== "") {
448
+ parts.push(`for(const key in ${value}){`, isUncheckedMode(context) ? "" : `if(!h.call(${value},key))continue;`, `const ${itemValue}=${value}[key];`, itemCheck, "}");
449
+ }
450
+ return parts.join("");
451
+ }
452
+ /**
453
+ * @brief Execute emit unsafe record check at segment.
454
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
455
+ */
456
+ function emitUnsafeRecordCheckAtSegment(item, value, path, segmentExpression, issues, context) {
457
+ const itemLeaf = emitLeafCheckAtTwoSegments(item, "rv", path, segmentExpression, "key", issues, context);
458
+ if (itemLeaf === undefined) {
459
+ return undefined;
460
+ }
461
+ const parts = [
462
+ `if(${objectRejectExpression(value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_record", "record", `a(${value})`)}}`
463
+ ];
464
+ if (itemLeaf !== "") {
465
+ parts.push("else{", `for(const key in ${value}){`, isUncheckedMode(context) ? "" : `if(!h.call(${value},key))continue;`, `const rv=${value}[key];`, itemLeaf, "}", "}");
466
+ }
467
+ return parts.join("");
468
+ }
57
469
  /**
58
470
  * @brief emit object check.
471
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
472
+ * stable across runtime and AOT emission.
59
473
  */
60
474
  export function emitObjectCheck(schema, value, path, issues, context, emitChild) {
475
+ if (isUnsafeMode(context)) {
476
+ return emitUnsafeObjectCheck(schema, value, path, issues, context, emitChild);
477
+ }
61
478
  const parts = [
62
- `if(!o(${value})){${emitIssue(issues, path, "expected_object", "object", `a(${value})`)}return;}`
479
+ `if(${objectRejectExpression(value)}){${emitIssue(issues, path, "expected_object", "object", `a(${value})`)}return;}`
63
480
  ];
64
481
  const entries = schema.entries;
482
+ const keyExpressions = [];
65
483
  for (let index = 0; index < entries.length; index += 1) {
66
484
  const entry = entries[index];
67
485
  if (entry === undefined) {
68
486
  continue;
69
487
  }
70
488
  const key = stringRef(context, entry.key);
71
- const child = emitChild(entry.schema, context);
489
+ keyExpressions.push(key);
490
+ const itemValue = `v${String(index)}`;
491
+ const leaf = emitLeafCheckAtSegment(entry.schema, itemValue, path, key, issues, context);
492
+ const composite = leaf === undefined
493
+ ? emitCompositeCheckAtSegment(entry.schema, itemValue, path, key, issues, context)
494
+ : undefined;
495
+ let childCheck = leaf ?? composite;
496
+ if (childCheck === undefined) {
497
+ const child = emitChild(entry.schema, context);
498
+ childCheck = `${path}.push(${key});${child}(${itemValue},${path},${issues});${path}.pop();`;
499
+ }
500
+ const presentCheck = childCheck === ""
501
+ ? ""
502
+ : `const ${itemValue}=d.value;${childCheck}`;
72
503
  if (entry.presence === PresenceTag.Required) {
73
- parts.push(`{const d=g(${value},${key});if(d===undefined){${path}.push(${key});${emitIssue(issues, path, "expected_required_key", "present key", stringLiteral("missing"))}${path}.pop();}else{${path}.push(${key});${child}(d.value,${path},${issues});${path}.pop();}}`);
504
+ parts.push(`{const d=gp(${value},${key});if(d===undefined||!h.call(d,"value")){${emitIssueAtSegment(issues, path, key, "expected_required_key", "present key", stringLiteral("missing"))}}else{${presentCheck}}}`);
505
+ }
506
+ else {
507
+ parts.push(`if(h.call(${value},${key})){const d=gp(${value},${key});if(d===undefined||!h.call(d,"value")){${emitIssueAtSegment(issues, path, key, "expected_object", "data property", stringLiteral("accessor"))}}else{${presentCheck}}}`);
508
+ }
509
+ }
510
+ if (schema.catchall !== undefined) {
511
+ parts.push(emitObjectCatchallCheck(schema, value, path, issues, context, emitChild));
512
+ }
513
+ else if (schema.mode === ObjectModeTag.Strict) {
514
+ parts.push(`const xs=Object.getOwnPropertyNames(${value});const xn=xs.length;for(let i=0;i<xn;i+=1){const key=xs[i];if(!(${safeKeyMembershipExpression("key", keyExpressions)})){${emitIssueAtSegment(issues, path, "key", "unrecognized_key", "known key", stringLiteral("extra key"))}}}const ys=Object.getOwnPropertySymbols(${value});const yn=ys.length;for(let i=0;i<yn;i+=1){const key=ys[i];if(key!==undefined){${emitIssueAtSegment(issues, path, "String(key)", "unrecognized_key", "known key", stringLiteral("extra key"))}}}`);
515
+ }
516
+ return parts.join("");
517
+ }
518
+ /**
519
+ * @brief Emit diagnostic collection for object catchall keys.
520
+ */
521
+ function emitObjectCatchallCheck(schema, value, path, issues, context, emitChild) {
522
+ const catchall = schema.catchall;
523
+ if (catchall === undefined) {
524
+ return "";
525
+ }
526
+ const child = emitChild(catchall, context);
527
+ const membership = safeKeyMembershipExpression("key", objectKeyExpressions(schema, context));
528
+ return [
529
+ `const cx=Reflect.ownKeys(${value});`,
530
+ "const cn=cx.length;",
531
+ "for(let ci=0;ci<cn;ci+=1){",
532
+ "const key=cx[ci];",
533
+ `if(typeof key==="string"&&(${membership}))continue;`,
534
+ "const pk=typeof key===\"string\"?key:String(key);",
535
+ `const cd=gp(${value},key);`,
536
+ `if(cd===undefined||!h.call(cd,"value")){${emitIssueAtSegment(issues, path, "pk", "expected_object", "data property", stringLiteral("accessor"))}}else{`,
537
+ `${path}.push(pk);${child}(cd.value,${path},${issues});${path}.pop();`,
538
+ "}}"
539
+ ].join("");
540
+ }
541
+ /**
542
+ * @brief Convert object schema keys into side-table source expressions.
543
+ */
544
+ function objectKeyExpressions(schema, context) {
545
+ const keys = new Array(schema.keys.length);
546
+ for (let index = 0; index < schema.keys.length; index += 1) {
547
+ const key = schema.keys[index];
548
+ if (key !== undefined) {
549
+ keys[index] = stringRef(context, key);
550
+ }
551
+ }
552
+ return keys;
553
+ }
554
+ /**
555
+ * @brief Execute emit unsafe object check.
556
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
557
+ */
558
+ function emitUnsafeObjectCheck(schema, value, path, issues, context, emitChild) {
559
+ const parts = [
560
+ `if(${objectRejectExpression(value)}){${emitIssue(issues, path, "expected_object", "object", `a(${value})`)}return;}`
561
+ ];
562
+ const entries = schema.entries;
563
+ for (let index = 0; index < entries.length; index += 1) {
564
+ const entry = entries[index];
565
+ if (entry === undefined) {
566
+ continue;
567
+ }
568
+ const key = unsafeStringLiteralExpression(entry.key);
569
+ const itemValue = `v${String(index)}`;
570
+ const childCheck = emitObjectFieldCheck(entry.schema, itemValue, path, key, issues, context, emitChild);
571
+ parts.push(`{const ${itemValue}=${unsafePropertyReadExpression(value, entry.key)};`);
572
+ if (entry.presence === PresenceTag.Optional) {
573
+ parts.push(`if(${itemValue}!==undefined){${childCheck}}else if(h.call(${value},${key})){${childCheck}}`);
574
+ }
575
+ else if (schemaCanAcceptUndefined(entry.schema)) {
576
+ parts.push(`if(${itemValue}===undefined&&!h.call(${value},${key})){${emitIssueAtSegment(issues, path, key, "expected_required_key", "present key", stringLiteral("missing"))}}else{${childCheck}}`);
74
577
  }
75
578
  else {
76
- parts.push(`if(h.call(${value},${key})){const d=g(${value},${key});${path}.push(${key});if(d===undefined){${emitIssue(issues, path, "expected_object", "data property", stringLiteral("accessor"))}}else{${child}(d.value,${path},${issues});}${path}.pop();}`);
579
+ parts.push(childCheck);
77
580
  }
581
+ parts.push("}");
78
582
  }
79
- if (schema.mode === ObjectModeTag.Strict) {
583
+ if (schema.catchall !== undefined) {
584
+ parts.push(emitUnsafeObjectCatchallCheck(schema, value, path, issues, context, emitChild));
585
+ }
586
+ else if (schema.mode === ObjectModeTag.Strict && !isUncheckedMode(context)) {
80
587
  const keys = new Array(schema.entries.length);
81
588
  for (let index = 0; index < schema.entries.length; index += 1) {
82
589
  const entry = schema.entries[index];
@@ -84,22 +591,82 @@ export function emitObjectCheck(schema, value, path, issues, context, emitChild)
84
591
  keys[index] = entry.key;
85
592
  }
86
593
  }
87
- parts.push(`const xs=Reflect.ownKeys(${value});for(let i=0;i<xs.length;i+=1){const key=xs[i];if(key!==undefined&&(typeof key!=="string"||!k[${String(pushKeyset(context, keys))}].includes(key))){${path}.push(typeof key==="string"?key:String(key));${emitIssue(issues, path, "unrecognized_key", "known key", stringLiteral("extra key"))}${path}.pop();}}`);
594
+ parts.push(`for(const key in ${value}){if(h.call(${value},key)&&!(${unsafeKeyMembershipExpression("key", keys)})){${emitIssueAtSegment(issues, path, "key", "unrecognized_key", "known key", stringLiteral("extra key"))}}}`);
88
595
  }
89
596
  return parts.join("");
90
597
  }
598
+ /**
599
+ * @brief Emit unsafe diagnostic collection for object catchall keys.
600
+ */
601
+ function emitUnsafeObjectCatchallCheck(schema, value, path, issues, context, emitChild) {
602
+ const catchall = schema.catchall;
603
+ if (catchall === undefined) {
604
+ return "";
605
+ }
606
+ const child = emitChild(catchall, context);
607
+ const membership = unsafeKeyMembershipExpression("key", schema.keys);
608
+ return [
609
+ `const cx=Reflect.ownKeys(${value});`,
610
+ "const cn=cx.length;",
611
+ "for(let ci=0;ci<cn;ci+=1){",
612
+ "const key=cx[ci];",
613
+ `if(typeof key==="string"&&(${membership}))continue;`,
614
+ "const pk=typeof key===\"string\"?key:String(key);",
615
+ `${path}.push(pk);${child}(${value}[key],${path},${issues});${path}.pop();`,
616
+ "}"
617
+ ].join("");
618
+ }
619
+ /**
620
+ * @brief Execute emit object field check.
621
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
622
+ */
623
+ function emitObjectFieldCheck(schema, value, path, segmentExpression, issues, context, emitChild) {
624
+ const leaf = emitLeafCheckAtSegment(schema, value, path, segmentExpression, issues, context);
625
+ if (leaf !== undefined) {
626
+ return leaf;
627
+ }
628
+ const composite = emitCompositeCheckAtSegment(schema, value, path, segmentExpression, issues, context);
629
+ if (composite !== undefined) {
630
+ return composite;
631
+ }
632
+ const child = emitChild(schema, context);
633
+ return `${path}.push(${segmentExpression});${child}(${value},${path},${issues});${path}.pop();`;
634
+ }
635
+ /**
636
+ * @brief Execute emit composite check at segment.
637
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
638
+ */
639
+ function emitCompositeCheckAtSegment(schema, value, path, segmentExpression, issues, context) {
640
+ switch (schema.tag) {
641
+ case SchemaTag.Array:
642
+ return emitArrayCheckAtSegment(schema, value, path, segmentExpression, issues, context);
643
+ case SchemaTag.Tuple:
644
+ if (schema.rest !== undefined) {
645
+ return undefined;
646
+ }
647
+ return emitTupleCheckAtSegment(schema.items, value, path, segmentExpression, issues, context);
648
+ case SchemaTag.Record:
649
+ return emitRecordCheckAtSegment(schema.value, value, path, segmentExpression, issues, context);
650
+ default:
651
+ return undefined;
652
+ }
653
+ }
91
654
  /**
92
655
  * @brief emit discriminated union check.
656
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
657
+ * stable across runtime and AOT emission.
93
658
  */
94
659
  export function emitDiscriminatedUnionCheck(key, cases, value, path, issues, context, emitChild) {
660
+ if (isUnsafeMode(context)) {
661
+ return emitUnsafeDiscriminatedUnionCheck(key, cases, value, path, issues, context, emitChild);
662
+ }
95
663
  const keyRef = stringRef(context, key);
96
- const descriptor = `g(${value},${keyRef})`;
97
664
  const parts = [
98
- `if(!o(${value})){${emitIssue(issues, path, "expected_object", "object", `a(${value})`)}return;}`,
99
- `const dd=${descriptor};`,
100
- `if(dd===undefined){${path}.push(${keyRef});${emitIssue(issues, path, "expected_discriminant", "data property", stringLiteral("missing or accessor"))}${path}.pop();return;}`,
665
+ `if(${objectRejectExpression(value)}){${emitIssue(issues, path, "expected_object", "object", `a(${value})`)}return;}`,
666
+ `const dd=gp(${value},${keyRef});`,
667
+ `if(dd===undefined||!h.call(dd,"value")){${emitIssueAtSegment(issues, path, keyRef, "expected_discriminant", "data property", stringLiteral("missing or accessor"))}return;}`,
101
668
  "const dv=dd.value;",
102
- `if(typeof dv!=="string"){${path}.push(${keyRef});${emitIssue(issues, path, "expected_discriminant", "string discriminant", "a(dv)")}${path}.pop();return;}`
669
+ `if(typeof dv!=="string"){${emitIssueAtSegment(issues, path, keyRef, "expected_discriminant", "string discriminant", "a(dv)")}return;}`
103
670
  ];
104
671
  for (let index = 0; index < cases.length; index += 1) {
105
672
  const unionCase = cases[index];
@@ -112,6 +679,111 @@ export function emitDiscriminatedUnionCheck(key, cases, value, path, issues, con
112
679
  const check = emitChild(schema, context);
113
680
  parts.push(`if(Object.is(dv,l[${String(literalIndex)}])){${check}(${value},${path},${issues});return;}`);
114
681
  }
115
- parts.push(`${path}.push(${keyRef});${emitIssueExpr(issues, path, "expected_discriminant", stringLiteral("known discriminant"), "le(dv)")}${path}.pop();`);
682
+ parts.push(emitIssueExprAtSegment(issues, path, keyRef, "expected_discriminant", stringLiteral("known discriminant"), "le(dv)"));
683
+ return parts.join("");
684
+ }
685
+ /**
686
+ * @brief Execute emit unsafe discriminated union check.
687
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
688
+ */
689
+ function emitUnsafeDiscriminatedUnionCheck(key, cases, value, path, issues, context, emitChild) {
690
+ const keyRef = unsafeStringLiteralExpression(key);
691
+ const parts = [
692
+ `if(${objectRejectExpression(value)}){${emitIssue(issues, path, "expected_object", "object", `a(${value})`)}return;}`,
693
+ `const dv=${unsafePropertyReadExpression(value, key)};`,
694
+ `if(typeof dv!=="string"){${emitIssueAtSegment(issues, path, keyRef, "expected_discriminant", "string discriminant", "a(dv)")}return;}`
695
+ ];
696
+ for (let index = 0; index < cases.length; index += 1) {
697
+ const unionCase = cases[index];
698
+ if (unionCase === undefined) {
699
+ continue;
700
+ }
701
+ const literal = unionCase.literal;
702
+ const schema = unionCase.schema;
703
+ const check = emitChild(schema, context);
704
+ parts.push(`if(dv===${unsafeStringLiteralExpression(literal)}){${check}(${value},${path},${issues});return;}`);
705
+ }
706
+ parts.push(emitIssueExprAtSegment(issues, path, keyRef, "expected_discriminant", stringLiteral("known discriminant"), "le(dv)"));
116
707
  return parts.join("");
117
708
  }
709
+ /**
710
+ * @brief Execute object reject expression.
711
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
712
+ */
713
+ function objectRejectExpression(value) {
714
+ return `typeof ${value}!=="object"||${value}===null||Array.isArray(${value})`;
715
+ }
716
+ /**
717
+ * @brief Check unsafe mode.
718
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
719
+ */
720
+ function isUnsafeMode(context) {
721
+ return context.mode !== "safe";
722
+ }
723
+ /**
724
+ * @brief Check unchecked mode.
725
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
726
+ */
727
+ function isUncheckedMode(context) {
728
+ return context.mode === "unchecked";
729
+ }
730
+ /**
731
+ * @brief Execute unsafe property read expression.
732
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
733
+ */
734
+ function unsafePropertyReadExpression(objectExpression, key) {
735
+ if (isAsciiIdentifierName(key)) {
736
+ return `${objectExpression}.${key}`;
737
+ }
738
+ return `${objectExpression}[${unsafeStringLiteralExpression(key)}]`;
739
+ }
740
+ /**
741
+ * @brief Execute unsafe key membership expression.
742
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
743
+ */
744
+ function unsafeKeyMembershipExpression(key, keys) {
745
+ if (keys.length === 0) {
746
+ return "false";
747
+ }
748
+ const parts = new Array(keys.length);
749
+ for (let index = 0; index < keys.length; index += 1) {
750
+ const value = keys[index];
751
+ parts[index] = value === undefined
752
+ ? "false"
753
+ : `${key}===${unsafeStringLiteralExpression(value)}`;
754
+ }
755
+ return parts.join("||");
756
+ }
757
+ /**
758
+ * @brief Execute safe key membership expression.
759
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
760
+ */
761
+ function safeKeyMembershipExpression(key, keyExpressions) {
762
+ if (keyExpressions.length === 0) {
763
+ return "false";
764
+ }
765
+ const parts = new Array(keyExpressions.length);
766
+ for (let index = 0; index < keyExpressions.length; index += 1) {
767
+ const expression = keyExpressions[index];
768
+ parts[index] = expression === undefined
769
+ ? "false"
770
+ : `${key}===${expression}`;
771
+ }
772
+ return parts.join("||");
773
+ }
774
+ /**
775
+ * @brief Check ascii identifier name.
776
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
777
+ */
778
+ function isAsciiIdentifierName(value) {
779
+ return /^[A-Za-z_$][0-9A-Za-z_$]*$/u.test(value);
780
+ }
781
+ /**
782
+ * @brief Execute unsafe string literal expression.
783
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
784
+ */
785
+ function unsafeStringLiteralExpression(value) {
786
+ return JSON.stringify(value)
787
+ .replace(/\u2028/gu, "\\u2028")
788
+ .replace(/\u2029/gu, "\\u2029");
789
+ }