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,20 +1,35 @@
1
1
  /**
2
2
  * @file compile/check-scalar.ts
3
3
  * @brief Scalar 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 { NumberCheckTag, SchemaTag, StringCheckTag } from "../kind/index.js";
6
- import { UUID_PATTERN } from "../schema/index.js";
7
+ import { DateCheckTag, NumberCheckTag, SchemaTag, StringCheckTag } from "../kind/index.js";
8
+ import { EMAIL_PATTERN, IPV4_PATTERN, IPV6_PATTERN, ISO_DATETIME_PATTERN, ISO_DATE_PATTERN, ULID_PATTERN, URL_PATTERN, UUID_PATTERN } from "../schema/index.js";
7
9
  import { pushLiteral } from "./context.js";
8
- import { emitIssue, emitIssueExpr, emitPatternIssue } from "./issue.js";
10
+ import { emitIssue, emitIssueAtSegment, emitIssueAtTwoSegments, emitIssueExpr, emitIssueExprAtSegment, emitIssueExprAtTwoSegments, emitPatternIssueAtSegment, emitPatternIssueAtTwoSegments, emitPatternIssue } from "./issue.js";
9
11
  import { stringLiteral } from "./names.js";
12
+ import { emitUnion } from "./predicate.js";
10
13
  /**
11
14
  * @brief emit string check.
15
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
16
+ * stable across runtime and AOT emission.
17
+ * @param schema String schema with scalar checks.
18
+ * @param value Generated expression for the candidate value.
19
+ * @param path Generated expression for the current diagnostic path.
20
+ * @param issues Generated expression for the issue buffer.
21
+ * @param context Shared code-generation context.
22
+ * @returns JavaScript source for root string diagnostics.
12
23
  */
13
24
  export function emitStringCheck(schema, value, path, issues, context) {
14
25
  const parts = [
15
26
  `if(typeof ${value}!=="string"){${emitIssue(issues, path, "expected_string", "string", `a(${value})`)}return;}`
16
27
  ];
17
28
  const checks = schema.checks;
29
+ /*
30
+ * Constraint diagnostics run only after the type guard returns. This avoids
31
+ * meaningless length or pattern reads on non-string values.
32
+ */
18
33
  for (let index = 0; index < checks.length; index += 1) {
19
34
  const check = checks[index];
20
35
  if (check === undefined) {
@@ -33,18 +48,374 @@ export function emitStringCheck(schema, value, path, issues, context) {
33
48
  case StringCheckTag.Uuid:
34
49
  parts.push(emitPatternIssue(value, path, issues, UUID_PATTERN, "uuid", context));
35
50
  break;
51
+ case StringCheckTag.Email:
52
+ parts.push(emitPatternIssue(value, path, issues, EMAIL_PATTERN, "email", context));
53
+ break;
54
+ case StringCheckTag.Url:
55
+ parts.push(emitPatternIssue(value, path, issues, URL_PATTERN, "url", context));
56
+ break;
57
+ case StringCheckTag.IsoDate:
58
+ parts.push(emitPatternIssue(value, path, issues, ISO_DATE_PATTERN, "iso_date", context));
59
+ break;
60
+ case StringCheckTag.IsoDateTime:
61
+ parts.push(emitPatternIssue(value, path, issues, ISO_DATETIME_PATTERN, "iso_datetime", context));
62
+ break;
63
+ case StringCheckTag.Ulid:
64
+ parts.push(emitPatternIssue(value, path, issues, ULID_PATTERN, "ulid", context));
65
+ break;
66
+ case StringCheckTag.Ipv4:
67
+ parts.push(emitPatternIssue(value, path, issues, IPV4_PATTERN, "ipv4", context));
68
+ break;
69
+ case StringCheckTag.Ipv6:
70
+ parts.push(emitPatternIssue(value, path, issues, IPV6_PATTERN, "ipv6", context));
71
+ break;
72
+ }
73
+ }
74
+ return parts.join("");
75
+ }
76
+ /**
77
+ * @brief Emit Date diagnostics.
78
+ * @param value Generated expression for the candidate value.
79
+ * @param path Generated expression for the current diagnostic path.
80
+ * @param issues Generated expression for the issue buffer.
81
+ * @returns JavaScript source for root Date diagnostics.
82
+ */
83
+ export function emitDateCheck(schema, value, path, issues) {
84
+ const invalid = `!dg(${value})`;
85
+ const checks = schema.checks;
86
+ if (checks.length === 0) {
87
+ return `if(${invalid}){${emitIssue(issues, path, "expected_date", "valid Date", `a(${value})`)}}`;
88
+ }
89
+ const parts = [`if(${invalid}){${emitIssue(issues, path, "expected_date", "valid Date", `a(${value})`)}}else{`];
90
+ for (let index = 0; index < checks.length; index += 1) {
91
+ const check = checks[index];
92
+ if (check === undefined) {
93
+ continue;
94
+ }
95
+ const actual = `new Date(dt(${value})).toISOString()`;
96
+ switch (check.tag) {
97
+ case DateCheckTag.Min:
98
+ parts.push(`if(dt(${value})<${String(check.value)}){${emitIssue(issues, path, "expected_gte", `>= ${new Date(check.value).toISOString()}`, actual)}}`);
99
+ break;
100
+ case DateCheckTag.Max:
101
+ parts.push(`if(dt(${value})>${String(check.value)}){${emitIssue(issues, path, "expected_lte", `<= ${new Date(check.value).toISOString()}`, actual)}}`);
102
+ break;
103
+ }
104
+ }
105
+ parts.push("}");
106
+ return parts.join("");
107
+ }
108
+ /**
109
+ * @brief emit leaf check at one appended path segment.
110
+ * @details This path is used by object-field diagnostics to avoid building a
111
+ * mutable path frame and calling a child collector for scalar schemas.
112
+ * @param schema Candidate leaf schema.
113
+ * @param value Generated expression for the candidate value.
114
+ * @param path Generated expression for the current diagnostic path.
115
+ * @param segmentExpression Generated expression for the appended path segment.
116
+ * @param issues Generated expression for the issue buffer.
117
+ * @param context Shared code-generation context.
118
+ * @returns Inline diagnostic source, or undefined when a full child collector is required.
119
+ */
120
+ export function emitLeafCheckAtSegment(schema, value, path, segmentExpression, issues, context) {
121
+ switch (schema.tag) {
122
+ case SchemaTag.Unknown:
123
+ return "";
124
+ case SchemaTag.Never:
125
+ return emitIssueAtSegment(issues, path, segmentExpression, "expected_never", "never", `a(${value})`);
126
+ case SchemaTag.String:
127
+ return emitStringCheckAtSegment(schema, value, path, segmentExpression, issues, context);
128
+ case SchemaTag.Number:
129
+ return emitNumberCheckAtSegment(schema, value, path, segmentExpression, issues);
130
+ case SchemaTag.Date:
131
+ if (schema.checks.length !== 0) {
132
+ return undefined;
133
+ }
134
+ return `if(!dg(${value})){${emitIssueAtSegment(issues, path, segmentExpression, "expected_date", "valid Date", `a(${value})`)}}`;
135
+ case SchemaTag.BigInt:
136
+ return `if(typeof ${value}!=="bigint"){${emitIssueAtSegment(issues, path, segmentExpression, "expected_bigint", "bigint", `a(${value})`)}}`;
137
+ case SchemaTag.Symbol:
138
+ return `if(typeof ${value}!=="symbol"){${emitIssueAtSegment(issues, path, segmentExpression, "expected_symbol", "symbol", `a(${value})`)}}`;
139
+ case SchemaTag.Boolean:
140
+ return `if(typeof ${value}!=="boolean"){${emitIssueAtSegment(issues, path, segmentExpression, "expected_boolean", "boolean", `a(${value})`)}}`;
141
+ case SchemaTag.Literal:
142
+ return emitLiteralCheckAtSegment(schema.value, value, path, segmentExpression, issues, context);
143
+ case SchemaTag.Union:
144
+ /*
145
+ * Primitive unions are cheap enough to inline. Complex union branches
146
+ * already delegate through emitUnion and child predicate helpers.
147
+ */
148
+ return `if(!${emitUnion(schema.options, value, context)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_union", "union", `a(${value})`)}}`;
149
+ default:
150
+ return undefined;
151
+ }
152
+ }
153
+ /**
154
+ * @brief emit leaf check for a proven undefined value at one path segment.
155
+ * @details Array and tuple holes are known to be undefined. Emitting only the
156
+ * reachable type or literal issue keeps generated collectors smaller and avoids
157
+ * cold constraint branches that V8 still has to parse.
158
+ * @param schema Candidate leaf schema.
159
+ * @param path Generated expression for the current diagnostic path.
160
+ * @param segmentExpression Generated expression for the appended path segment.
161
+ * @param issues Generated expression for the issue buffer.
162
+ * @param context Shared code-generation context.
163
+ * @returns Inline diagnostic source, or undefined when a full child collector is required.
164
+ */
165
+ export function emitUndefinedLeafCheckAtSegment(schema, path, segmentExpression, issues, context) {
166
+ switch (schema.tag) {
167
+ case SchemaTag.Unknown:
168
+ return "";
169
+ case SchemaTag.Never:
170
+ return emitIssueAtSegment(issues, path, segmentExpression, "expected_never", "never", stringLiteral("undefined"));
171
+ case SchemaTag.String:
172
+ return emitIssueAtSegment(issues, path, segmentExpression, "expected_string", "string", stringLiteral("undefined"));
173
+ case SchemaTag.Number:
174
+ return emitIssueAtSegment(issues, path, segmentExpression, "expected_number", "number", stringLiteral("undefined"));
175
+ case SchemaTag.Date:
176
+ return emitIssueAtSegment(issues, path, segmentExpression, "expected_date", "valid Date", stringLiteral("undefined"));
177
+ case SchemaTag.BigInt:
178
+ return emitIssueAtSegment(issues, path, segmentExpression, "expected_bigint", "bigint", stringLiteral("undefined"));
179
+ case SchemaTag.Symbol:
180
+ return emitIssueAtSegment(issues, path, segmentExpression, "expected_symbol", "symbol", stringLiteral("undefined"));
181
+ case SchemaTag.Boolean:
182
+ return emitIssueAtSegment(issues, path, segmentExpression, "expected_boolean", "boolean", stringLiteral("undefined"));
183
+ case SchemaTag.Literal:
184
+ return emitUndefinedLiteralCheckAtSegment(schema.value, path, segmentExpression, issues, context);
185
+ default:
186
+ return undefined;
187
+ }
188
+ }
189
+ /**
190
+ * @brief emit leaf check at two appended path segments.
191
+ * @details Used by object-field array/record diagnostics to avoid push/pop path
192
+ * mutation when both parent key and child key are known in generated source.
193
+ * @param schema Candidate leaf schema.
194
+ * @param value Generated expression for the candidate value.
195
+ * @param path Generated expression for the current diagnostic path.
196
+ * @param firstSegmentExpression Generated expression for the parent segment.
197
+ * @param secondSegmentExpression Generated expression for the child segment.
198
+ * @param issues Generated expression for the issue buffer.
199
+ * @param context Shared code-generation context.
200
+ * @returns Inline diagnostic source, or undefined when a full child collector is required.
201
+ */
202
+ export function emitLeafCheckAtTwoSegments(schema, value, path, firstSegmentExpression, secondSegmentExpression, issues, context) {
203
+ switch (schema.tag) {
204
+ case SchemaTag.Unknown:
205
+ return "";
206
+ case SchemaTag.Never:
207
+ return emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_never", "never", `a(${value})`);
208
+ case SchemaTag.String:
209
+ return emitStringCheckAtTwoSegments(schema, value, path, firstSegmentExpression, secondSegmentExpression, issues, context);
210
+ case SchemaTag.Number:
211
+ return emitNumberCheckAtTwoSegments(schema, value, path, firstSegmentExpression, secondSegmentExpression, issues);
212
+ case SchemaTag.Date:
213
+ if (schema.checks.length !== 0) {
214
+ return undefined;
215
+ }
216
+ return `if(!dg(${value})){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_date", "valid Date", `a(${value})`)}}`;
217
+ case SchemaTag.BigInt:
218
+ return `if(typeof ${value}!=="bigint"){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_bigint", "bigint", `a(${value})`)}}`;
219
+ case SchemaTag.Symbol:
220
+ return `if(typeof ${value}!=="symbol"){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_symbol", "symbol", `a(${value})`)}}`;
221
+ case SchemaTag.Boolean:
222
+ return `if(typeof ${value}!=="boolean"){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_boolean", "boolean", `a(${value})`)}}`;
223
+ case SchemaTag.Literal:
224
+ return emitLiteralCheckAtTwoSegments(schema.value, value, path, firstSegmentExpression, secondSegmentExpression, issues, context);
225
+ case SchemaTag.Union:
226
+ return `if(!${emitUnion(schema.options, value, context)}){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_union", "union", `a(${value})`)}}`;
227
+ default:
228
+ return undefined;
229
+ }
230
+ }
231
+ /**
232
+ * @brief emit leaf check for a proven undefined value at two path segments.
233
+ * @details Array and tuple holes under object fields are known to be undefined,
234
+ * so the emitter can skip value reads and emit only reachable leaf issues.
235
+ * @param schema Candidate leaf schema.
236
+ * @param path Generated expression for the current diagnostic path.
237
+ * @param firstSegmentExpression Generated expression for the parent segment.
238
+ * @param secondSegmentExpression Generated expression for the child segment.
239
+ * @param issues Generated expression for the issue buffer.
240
+ * @param context Shared code-generation context.
241
+ * @returns Inline diagnostic source, or undefined when a full child collector is required.
242
+ */
243
+ export function emitUndefinedLeafCheckAtTwoSegments(schema, path, firstSegmentExpression, secondSegmentExpression, issues, context) {
244
+ switch (schema.tag) {
245
+ case SchemaTag.Unknown:
246
+ return "";
247
+ case SchemaTag.Never:
248
+ return emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_never", "never", stringLiteral("undefined"));
249
+ case SchemaTag.String:
250
+ return emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_string", "string", stringLiteral("undefined"));
251
+ case SchemaTag.Number:
252
+ return emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_number", "number", stringLiteral("undefined"));
253
+ case SchemaTag.Date:
254
+ return emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_date", "valid Date", stringLiteral("undefined"));
255
+ case SchemaTag.BigInt:
256
+ return emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_bigint", "bigint", stringLiteral("undefined"));
257
+ case SchemaTag.Symbol:
258
+ return emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_symbol", "symbol", stringLiteral("undefined"));
259
+ case SchemaTag.Boolean:
260
+ return emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_boolean", "boolean", stringLiteral("undefined"));
261
+ case SchemaTag.Literal:
262
+ return emitUndefinedLiteralCheckAtTwoSegments(schema.value, path, firstSegmentExpression, secondSegmentExpression, issues, context);
263
+ default:
264
+ return undefined;
265
+ }
266
+ }
267
+ /**
268
+ * @brief emit string check at one appended path segment.
269
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
270
+ * stable across runtime and AOT emission.
271
+ * @param schema String schema with scalar checks.
272
+ * @param value Generated expression for the candidate value.
273
+ * @param path Generated expression for the current diagnostic path.
274
+ * @param segmentExpression Generated expression for the appended path segment.
275
+ * @param issues Generated expression for the issue buffer.
276
+ * @param context Shared code-generation context.
277
+ * @returns JavaScript source for one-segment string diagnostics.
278
+ */
279
+ function emitStringCheckAtSegment(schema, value, path, segmentExpression, issues, context) {
280
+ const checks = schema.checks;
281
+ if (checks.length === 0) {
282
+ /*
283
+ * No constraints means no else block is needed. The generated collector
284
+ * stays as a single type branch.
285
+ */
286
+ return `if(typeof ${value}!=="string"){${emitIssueAtSegment(issues, path, segmentExpression, "expected_string", "string", `a(${value})`)}}`;
287
+ }
288
+ const parts = [
289
+ `if(typeof ${value}!=="string"){${emitIssueAtSegment(issues, path, segmentExpression, "expected_string", "string", `a(${value})`)}}else{`
290
+ ];
291
+ for (let index = 0; index < checks.length; index += 1) {
292
+ const check = checks[index];
293
+ if (check === undefined) {
294
+ continue;
295
+ }
296
+ switch (check.tag) {
297
+ case StringCheckTag.Min:
298
+ parts.push(`if(${value}.length<${String(check.value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_min_length", `length >= ${String(check.value)}`, `"length "+String(${value}.length)`)}}`);
299
+ break;
300
+ case StringCheckTag.Max:
301
+ parts.push(`if(${value}.length>${String(check.value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_max_length", `length <= ${String(check.value)}`, `"length "+String(${value}.length)`)}}`);
302
+ break;
303
+ case StringCheckTag.Regex:
304
+ parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, check.regex, check.name, context));
305
+ break;
306
+ case StringCheckTag.Uuid:
307
+ parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, UUID_PATTERN, "uuid", context));
308
+ break;
309
+ case StringCheckTag.Email:
310
+ parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, EMAIL_PATTERN, "email", context));
311
+ break;
312
+ case StringCheckTag.Url:
313
+ parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, URL_PATTERN, "url", context));
314
+ break;
315
+ case StringCheckTag.IsoDate:
316
+ parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, ISO_DATE_PATTERN, "iso_date", context));
317
+ break;
318
+ case StringCheckTag.IsoDateTime:
319
+ parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, ISO_DATETIME_PATTERN, "iso_datetime", context));
320
+ break;
321
+ case StringCheckTag.Ulid:
322
+ parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, ULID_PATTERN, "ulid", context));
323
+ break;
324
+ case StringCheckTag.Ipv4:
325
+ parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, IPV4_PATTERN, "ipv4", context));
326
+ break;
327
+ case StringCheckTag.Ipv6:
328
+ parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, IPV6_PATTERN, "ipv6", context));
329
+ break;
330
+ }
331
+ }
332
+ parts.push("}");
333
+ return parts.join("");
334
+ }
335
+ /**
336
+ * @brief emit string check at two appended path segments.
337
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
338
+ * stable across runtime and AOT emission.
339
+ * @param schema String schema with scalar checks.
340
+ * @param value Generated expression for the candidate value.
341
+ * @param path Generated expression for the current diagnostic path.
342
+ * @param firstSegmentExpression Generated expression for the parent segment.
343
+ * @param secondSegmentExpression Generated expression for the child segment.
344
+ * @param issues Generated expression for the issue buffer.
345
+ * @param context Shared code-generation context.
346
+ * @returns JavaScript source for two-segment string diagnostics.
347
+ */
348
+ function emitStringCheckAtTwoSegments(schema, value, path, firstSegmentExpression, secondSegmentExpression, issues, context) {
349
+ const checks = schema.checks;
350
+ if (checks.length === 0) {
351
+ return `if(typeof ${value}!=="string"){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_string", "string", `a(${value})`)}}`;
352
+ }
353
+ const parts = [
354
+ `if(typeof ${value}!=="string"){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_string", "string", `a(${value})`)}}else{`
355
+ ];
356
+ for (let index = 0; index < checks.length; index += 1) {
357
+ const check = checks[index];
358
+ if (check === undefined) {
359
+ continue;
360
+ }
361
+ switch (check.tag) {
362
+ case StringCheckTag.Min:
363
+ parts.push(`if(${value}.length<${String(check.value)}){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_min_length", `length >= ${String(check.value)}`, `"length "+String(${value}.length)`)}}`);
364
+ break;
365
+ case StringCheckTag.Max:
366
+ parts.push(`if(${value}.length>${String(check.value)}){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_max_length", `length <= ${String(check.value)}`, `"length "+String(${value}.length)`)}}`);
367
+ break;
368
+ case StringCheckTag.Regex:
369
+ parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, check.regex, check.name, context));
370
+ break;
371
+ case StringCheckTag.Uuid:
372
+ parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, UUID_PATTERN, "uuid", context));
373
+ break;
374
+ case StringCheckTag.Email:
375
+ parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, EMAIL_PATTERN, "email", context));
376
+ break;
377
+ case StringCheckTag.Url:
378
+ parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, URL_PATTERN, "url", context));
379
+ break;
380
+ case StringCheckTag.IsoDate:
381
+ parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, ISO_DATE_PATTERN, "iso_date", context));
382
+ break;
383
+ case StringCheckTag.IsoDateTime:
384
+ parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, ISO_DATETIME_PATTERN, "iso_datetime", context));
385
+ break;
386
+ case StringCheckTag.Ulid:
387
+ parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, ULID_PATTERN, "ulid", context));
388
+ break;
389
+ case StringCheckTag.Ipv4:
390
+ parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, IPV4_PATTERN, "ipv4", context));
391
+ break;
392
+ case StringCheckTag.Ipv6:
393
+ parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, IPV6_PATTERN, "ipv6", context));
394
+ break;
36
395
  }
37
396
  }
397
+ parts.push("}");
38
398
  return parts.join("");
39
399
  }
40
400
  /**
41
401
  * @brief emit number check.
402
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
403
+ * stable across runtime and AOT emission.
404
+ * @param schema Number schema with scalar checks.
405
+ * @param value Generated expression for the candidate value.
406
+ * @param path Generated expression for the current diagnostic path.
407
+ * @param issues Generated expression for the issue buffer.
408
+ * @returns JavaScript source for root number diagnostics.
42
409
  */
43
410
  export function emitNumberCheck(schema, value, path, issues) {
44
411
  const parts = [
45
412
  `if(typeof ${value}!=="number"||!Number.isFinite(${value})){${emitIssue(issues, path, "expected_number", "number", `a(${value})`)}return;}`
46
413
  ];
47
414
  const checks = schema.checks;
415
+ /*
416
+ * Bounds and integer diagnostics are emitted only after the finite-number
417
+ * guard, so generated code never compares non-number values to bounds.
418
+ */
48
419
  for (let index = 0; index < checks.length; index += 1) {
49
420
  const check = checks[index];
50
421
  if (check === undefined) {
@@ -60,14 +431,210 @@ export function emitNumberCheck(schema, value, path, issues) {
60
431
  case NumberCheckTag.Lte:
61
432
  parts.push(`if(${value}>${String(check.value)}){${emitIssue(issues, path, "expected_lte", `<= ${String(check.value)}`, `String(${value})`)}}`);
62
433
  break;
434
+ case NumberCheckTag.Gt:
435
+ parts.push(`if(${value}<=${String(check.value)}){${emitIssue(issues, path, "expected_gt", `> ${String(check.value)}`, `String(${value})`)}}`);
436
+ break;
437
+ case NumberCheckTag.Lt:
438
+ parts.push(`if(${value}>=${String(check.value)}){${emitIssue(issues, path, "expected_lt", `< ${String(check.value)}`, `String(${value})`)}}`);
439
+ break;
440
+ case NumberCheckTag.MultipleOf:
441
+ parts.push(`if(${value}%${String(check.value)}!==0){${emitIssue(issues, path, "expected_multiple_of", `multiple of ${String(check.value)}`, `String(${value})`)}}`);
442
+ break;
443
+ }
444
+ }
445
+ return parts.join("");
446
+ }
447
+ /**
448
+ * @brief emit number check at one appended path segment.
449
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
450
+ * stable across runtime and AOT emission.
451
+ * @param schema Number schema with scalar checks.
452
+ * @param value Generated expression for the candidate value.
453
+ * @param path Generated expression for the current diagnostic path.
454
+ * @param segmentExpression Generated expression for the appended path segment.
455
+ * @param issues Generated expression for the issue buffer.
456
+ * @returns JavaScript source for one-segment number diagnostics.
457
+ */
458
+ function emitNumberCheckAtSegment(schema, value, path, segmentExpression, issues) {
459
+ const checks = schema.checks;
460
+ if (checks.length === 0) {
461
+ /*
462
+ * Plain number schemas need only the finite-number guard. Emitting an
463
+ * else block would add cold code with no diagnostic work.
464
+ */
465
+ return `if(typeof ${value}!=="number"||!Number.isFinite(${value})){${emitIssueAtSegment(issues, path, segmentExpression, "expected_number", "number", `a(${value})`)}}`;
466
+ }
467
+ const parts = [
468
+ `if(typeof ${value}!=="number"||!Number.isFinite(${value})){${emitIssueAtSegment(issues, path, segmentExpression, "expected_number", "number", `a(${value})`)}}else{`
469
+ ];
470
+ for (let index = 0; index < checks.length; index += 1) {
471
+ const check = checks[index];
472
+ if (check === undefined) {
473
+ continue;
474
+ }
475
+ switch (check.tag) {
476
+ case NumberCheckTag.Integer:
477
+ parts.push(`if(!Number.isInteger(${value})){${emitIssueExprAtSegment(issues, path, segmentExpression, "expected_integer", stringLiteral("integer"), stringLiteral("number"))}}`);
478
+ break;
479
+ case NumberCheckTag.Gte:
480
+ parts.push(`if(${value}<${String(check.value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_gte", `>= ${String(check.value)}`, `String(${value})`)}}`);
481
+ break;
482
+ case NumberCheckTag.Lte:
483
+ parts.push(`if(${value}>${String(check.value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_lte", `<= ${String(check.value)}`, `String(${value})`)}}`);
484
+ break;
485
+ case NumberCheckTag.Gt:
486
+ parts.push(`if(${value}<=${String(check.value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_gt", `> ${String(check.value)}`, `String(${value})`)}}`);
487
+ break;
488
+ case NumberCheckTag.Lt:
489
+ parts.push(`if(${value}>=${String(check.value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_lt", `< ${String(check.value)}`, `String(${value})`)}}`);
490
+ break;
491
+ case NumberCheckTag.MultipleOf:
492
+ parts.push(`if(${value}%${String(check.value)}!==0){${emitIssueAtSegment(issues, path, segmentExpression, "expected_multiple_of", `multiple of ${String(check.value)}`, `String(${value})`)}}`);
493
+ break;
63
494
  }
64
495
  }
496
+ parts.push("}");
497
+ return parts.join("");
498
+ }
499
+ /**
500
+ * @brief emit number check at two appended path segments.
501
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
502
+ * stable across runtime and AOT emission.
503
+ * @param schema Number schema with scalar checks.
504
+ * @param value Generated expression for the candidate value.
505
+ * @param path Generated expression for the current diagnostic path.
506
+ * @param firstSegmentExpression Generated expression for the parent segment.
507
+ * @param secondSegmentExpression Generated expression for the child segment.
508
+ * @param issues Generated expression for the issue buffer.
509
+ * @returns JavaScript source for two-segment number diagnostics.
510
+ */
511
+ function emitNumberCheckAtTwoSegments(schema, value, path, firstSegmentExpression, secondSegmentExpression, issues) {
512
+ const checks = schema.checks;
513
+ if (checks.length === 0) {
514
+ return `if(typeof ${value}!=="number"||!Number.isFinite(${value})){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_number", "number", `a(${value})`)}}`;
515
+ }
516
+ const parts = [
517
+ `if(typeof ${value}!=="number"||!Number.isFinite(${value})){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_number", "number", `a(${value})`)}}else{`
518
+ ];
519
+ for (let index = 0; index < checks.length; index += 1) {
520
+ const check = checks[index];
521
+ if (check === undefined) {
522
+ continue;
523
+ }
524
+ switch (check.tag) {
525
+ case NumberCheckTag.Integer:
526
+ parts.push(`if(!Number.isInteger(${value})){${emitIssueExprAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_integer", stringLiteral("integer"), stringLiteral("number"))}}`);
527
+ break;
528
+ case NumberCheckTag.Gte:
529
+ parts.push(`if(${value}<${String(check.value)}){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_gte", `>= ${String(check.value)}`, `String(${value})`)}}`);
530
+ break;
531
+ case NumberCheckTag.Lte:
532
+ parts.push(`if(${value}>${String(check.value)}){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_lte", `<= ${String(check.value)}`, `String(${value})`)}}`);
533
+ break;
534
+ case NumberCheckTag.Gt:
535
+ parts.push(`if(${value}<=${String(check.value)}){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_gt", `> ${String(check.value)}`, `String(${value})`)}}`);
536
+ break;
537
+ case NumberCheckTag.Lt:
538
+ parts.push(`if(${value}>=${String(check.value)}){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_lt", `< ${String(check.value)}`, `String(${value})`)}}`);
539
+ break;
540
+ case NumberCheckTag.MultipleOf:
541
+ parts.push(`if(${value}%${String(check.value)}!==0){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_multiple_of", `multiple of ${String(check.value)}`, `String(${value})`)}}`);
542
+ break;
543
+ }
544
+ }
545
+ parts.push("}");
65
546
  return parts.join("");
66
547
  }
67
548
  /**
68
549
  * @brief emit literal check.
550
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
551
+ * stable across runtime and AOT emission.
552
+ * @param value Literal expected by the schema.
553
+ * @param checked Generated expression for the candidate value.
554
+ * @param path Generated expression for the current diagnostic path.
555
+ * @param issues Generated expression for the issue buffer.
556
+ * @param context Shared code-generation context.
557
+ * @returns JavaScript source for root literal diagnostics.
69
558
  */
70
559
  export function emitLiteralCheck(value, checked, path, issues, context) {
71
560
  const index = pushLiteral(context, value);
561
+ /*
562
+ * Object.is preserves JavaScript literal edge cases such as NaN and -0.
563
+ * The expected value stays in the literal side table rather than source text.
564
+ */
72
565
  return `if(!Object.is(${checked},l[${String(index)}])){${emitIssueExpr(issues, path, "expected_literal", `le(l[${String(index)}])`, `a(${checked})`)}}`;
73
566
  }
567
+ /**
568
+ * @brief emit literal check at one appended path segment.
569
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
570
+ * stable across runtime and AOT emission.
571
+ * @param value Literal expected by the schema.
572
+ * @param checked Generated expression for the candidate value.
573
+ * @param path Generated expression for the current diagnostic path.
574
+ * @param segmentExpression Generated expression for the appended path segment.
575
+ * @param issues Generated expression for the issue buffer.
576
+ * @param context Shared code-generation context.
577
+ * @returns JavaScript source for one-segment literal diagnostics.
578
+ */
579
+ function emitLiteralCheckAtSegment(value, checked, path, segmentExpression, issues, context) {
580
+ const index = pushLiteral(context, value);
581
+ return `if(!Object.is(${checked},l[${String(index)}])){${emitIssueExprAtSegment(issues, path, segmentExpression, "expected_literal", `le(l[${String(index)}])`, `a(${checked})`)}}`;
582
+ }
583
+ /**
584
+ * @brief emit literal check at two appended path segments.
585
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
586
+ * stable across runtime and AOT emission.
587
+ * @param value Literal expected by the schema.
588
+ * @param checked Generated expression for the candidate value.
589
+ * @param path Generated expression for the current diagnostic path.
590
+ * @param firstSegmentExpression Generated expression for the parent segment.
591
+ * @param secondSegmentExpression Generated expression for the child segment.
592
+ * @param issues Generated expression for the issue buffer.
593
+ * @param context Shared code-generation context.
594
+ * @returns JavaScript source for two-segment literal diagnostics.
595
+ */
596
+ function emitLiteralCheckAtTwoSegments(value, checked, path, firstSegmentExpression, secondSegmentExpression, issues, context) {
597
+ const index = pushLiteral(context, value);
598
+ return `if(!Object.is(${checked},l[${String(index)}])){${emitIssueExprAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_literal", `le(l[${String(index)}])`, `a(${checked})`)}}`;
599
+ }
600
+ /**
601
+ * @brief emit undefined literal check at one appended path segment.
602
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
603
+ * stable across runtime and AOT emission.
604
+ * @param value Literal expected by the schema.
605
+ * @param path Generated expression for the current diagnostic path.
606
+ * @param segmentExpression Generated expression for the appended path segment.
607
+ * @param issues Generated expression for the issue buffer.
608
+ * @param context Shared code-generation context.
609
+ * @returns Empty source when undefined is the expected literal, otherwise an issue.
610
+ */
611
+ function emitUndefinedLiteralCheckAtSegment(value, path, segmentExpression, issues, context) {
612
+ if (value === undefined) {
613
+ /*
614
+ * A sparse hole has already produced the exact expected literal. There is
615
+ * no diagnostic work left to emit.
616
+ */
617
+ return "";
618
+ }
619
+ const index = pushLiteral(context, value);
620
+ return emitIssueExprAtSegment(issues, path, segmentExpression, "expected_literal", `le(l[${String(index)}])`, stringLiteral("undefined"));
621
+ }
622
+ /**
623
+ * @brief emit undefined literal check at two appended path segments.
624
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
625
+ * stable across runtime and AOT emission.
626
+ * @param value Literal expected by the schema.
627
+ * @param path Generated expression for the current diagnostic path.
628
+ * @param firstSegmentExpression Generated expression for the parent segment.
629
+ * @param secondSegmentExpression Generated expression for the child segment.
630
+ * @param issues Generated expression for the issue buffer.
631
+ * @param context Shared code-generation context.
632
+ * @returns Empty source when undefined is the expected literal, otherwise an issue.
633
+ */
634
+ function emitUndefinedLiteralCheckAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, context) {
635
+ if (value === undefined) {
636
+ return "";
637
+ }
638
+ const index = pushLiteral(context, value);
639
+ return emitIssueExprAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_literal", `le(l[${String(index)}])`, stringLiteral("undefined"));
640
+ }
@@ -1,15 +1,27 @@
1
1
  /**
2
2
  * @file compile/check.ts
3
3
  * @brief Diagnostic validator function table emitter.
4
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
5
+ * stable across runtime and AOT emission.
4
6
  */
5
7
  import type { Schema } from "../schema/index.js";
6
8
  import type { EmitContext } from "./types.js";
7
9
  /**
8
10
  * @brief emit check function.
11
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
12
+ * stable across runtime and AOT emission.
13
+ * @param schema Schema whose diagnostics should be emitted.
14
+ * @param context Shared code-generation context.
15
+ * @returns Generated diagnostic function name.
16
+ * @invariant The same schema object maps to one diagnostic function per bundle.
9
17
  */
10
18
  export declare function emitCheckFunction(schema: Schema, context: EmitContext): string;
11
19
  /**
12
20
  * @brief emit check functions.
21
+ * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
22
+ * stable across runtime and AOT emission.
23
+ * @param context Shared code-generation context with accumulated check sources.
24
+ * @returns Concatenated JavaScript function declarations.
13
25
  */
14
26
  export declare function emitCheckFunctions(context: EmitContext): string;
15
27
  //# sourceMappingURL=check.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/compile/check.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAgBjD,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,YAAY,CAAC;AAE9D;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,MAAM,CAc9E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAU/D"}
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/compile/check.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAiBjD,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,YAAY,CAAC;AAE9D;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,MAAM,CAkB9E;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAU/D"}