@divmain/jdm-asm 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (397) hide show
  1. package/.github/workflows/ci.yml +53 -0
  2. package/.oxfmtrc.json +16 -0
  3. package/.oxlintrc.json +183 -0
  4. package/AGENTS.md +81 -0
  5. package/README.md +769 -0
  6. package/asconfig.json +23 -0
  7. package/benchmarks/fixtures.ts +111 -0
  8. package/benchmarks/input-fixtures.ts +80 -0
  9. package/benchmarks/run.ts +913 -0
  10. package/benchmarks/worker-pool.ts +223 -0
  11. package/benchmarks/worker.ts +374 -0
  12. package/dist/index.d.ts +996 -0
  13. package/dist/index.js +12239 -0
  14. package/dist/index.js.map +1 -0
  15. package/package.json +49 -0
  16. package/scripts/run-all-tests.ts +220 -0
  17. package/src/compiler/EXPRESSION_SUBSETS.md +228 -0
  18. package/src/compiler/asc-compiler.ts +315 -0
  19. package/src/compiler/ast-types.ts +215 -0
  20. package/src/compiler/build.ts +56 -0
  21. package/src/compiler/cache.ts +414 -0
  22. package/src/compiler/code-generators.ts +211 -0
  23. package/src/compiler/codegen/index.ts +15 -0
  24. package/src/compiler/codegen/js-marshal.ts +999 -0
  25. package/src/compiler/codegen/js-validation.ts +243 -0
  26. package/src/compiler/codegen.ts +19 -0
  27. package/src/compiler/compile-time-validation.ts +507 -0
  28. package/src/compiler/cst-visitor.ts +434 -0
  29. package/src/compiler/errors.ts +227 -0
  30. package/src/compiler/expression-parser.ts +536 -0
  31. package/src/compiler/graph.ts +197 -0
  32. package/src/compiler/index.ts +199 -0
  33. package/src/compiler/input-validation.ts +33 -0
  34. package/src/compiler/marshal-gen.ts +21 -0
  35. package/src/compiler/nodes/context-resolvers.ts +197 -0
  36. package/src/compiler/nodes/decision-table.ts +507 -0
  37. package/src/compiler/nodes/decision.ts +292 -0
  38. package/src/compiler/nodes/expression-compiler.ts +526 -0
  39. package/src/compiler/nodes/expression.ts +425 -0
  40. package/src/compiler/nodes/function.ts +316 -0
  41. package/src/compiler/nodes/input.ts +60 -0
  42. package/src/compiler/nodes/switch.ts +547 -0
  43. package/src/compiler/optimizer.ts +948 -0
  44. package/src/compiler/orchestrator.ts +352 -0
  45. package/src/compiler/parser.ts +115 -0
  46. package/src/compiler/result-selection.ts +161 -0
  47. package/src/compiler/runtime/index.ts +26 -0
  48. package/src/compiler/runtime-codegen.ts +211 -0
  49. package/src/compiler/runtime-validation-codegen.ts +294 -0
  50. package/src/compiler/runtime.ts +452 -0
  51. package/src/compiler/schema.ts +245 -0
  52. package/src/compiler/switch-branch-detection.ts +92 -0
  53. package/src/compiler/types.ts +136 -0
  54. package/src/compiler/unary-ast-transforms.ts +148 -0
  55. package/src/compiler/unary-parser.ts +301 -0
  56. package/src/compiler/unary-transform.ts +161 -0
  57. package/src/compiler/utils.ts +27 -0
  58. package/src/compiler/virtual-fs.ts +90 -0
  59. package/src/compiler/wasm-instantiate.ts +127 -0
  60. package/src/index.ts +1 -0
  61. package/src/runtime/arrays.ts +579 -0
  62. package/src/runtime/context.ts +189 -0
  63. package/src/runtime/expressions.ts +1811 -0
  64. package/src/runtime/index.ts +8 -0
  65. package/src/runtime/memory.ts +607 -0
  66. package/src/runtime/strings.ts +260 -0
  67. package/src/runtime/tables.ts +96 -0
  68. package/src/runtime/tsconfig.json +4 -0
  69. package/src/runtime/values.ts +209 -0
  70. package/test-data/README.md +83 -0
  71. package/test-data/decision-tables/basic/8k.json +87992 -0
  72. package/test-data/decision-tables/basic/affiliate-commission-calculator.json +228 -0
  73. package/test-data/decision-tables/basic/airline-loyalty-points-calculations.json +285 -0
  74. package/test-data/decision-tables/basic/airline-upgrade-eligibility.json +466 -0
  75. package/test-data/decision-tables/basic/auto-insurance-premium-calculator.json +412 -0
  76. package/test-data/decision-tables/basic/booking-personalization-system.json +553 -0
  77. package/test-data/decision-tables/basic/care-team-assignment-system.json +585 -0
  78. package/test-data/decision-tables/basic/claim-validation-system.json +307 -0
  79. package/test-data/decision-tables/basic/clinical-lab-result-interpreter.json +433 -0
  80. package/test-data/decision-tables/basic/clinical-treatment-protocol.json +474 -0
  81. package/test-data/decision-tables/basic/credit-limit-adjustment.json +479 -0
  82. package/test-data/decision-tables/basic/customer-eligibility-engine.json +551 -0
  83. package/test-data/decision-tables/basic/customer-lifetime-value.json +200 -0
  84. package/test-data/decision-tables/basic/customer-onboarding-kyc-verification.json +611 -0
  85. package/test-data/decision-tables/basic/customer-service-escalation.json +191 -0
  86. package/test-data/decision-tables/basic/decision-table-discounts.json +168 -0
  87. package/test-data/decision-tables/basic/decision-table-shipping.json +398 -0
  88. package/test-data/decision-tables/basic/delivery-route-optimizer.json +271 -0
  89. package/test-data/decision-tables/basic/device-compatibility-checker.json +303 -0
  90. package/test-data/decision-tables/basic/disaster-relief-fund-allocation.json +296 -0
  91. package/test-data/decision-tables/basic/dynamic-fx-rate-pricing-system.json +237 -0
  92. package/test-data/decision-tables/basic/dynamic-marketplace-comission-calculator.json +242 -0
  93. package/test-data/decision-tables/basic/dynamic-shipping-cost-calculator.json +378 -0
  94. package/test-data/decision-tables/basic/dynamic-tarrif-engine.json +289 -0
  95. package/test-data/decision-tables/basic/dynamic-ticket-pricing.json +325 -0
  96. package/test-data/decision-tables/basic/empty-column-with-space.json +100 -0
  97. package/test-data/decision-tables/basic/empty-column-without-space.json +100 -0
  98. package/test-data/decision-tables/basic/environment-compliance-assessment.json +386 -0
  99. package/test-data/decision-tables/basic/expression-table-map.json +313 -0
  100. package/test-data/decision-tables/basic/flash-sale-eligibility.json +366 -0
  101. package/test-data/decision-tables/basic/flight-dispatch-decision-system.json +455 -0
  102. package/test-data/decision-tables/basic/flight-rebooking-fee-calculator.json +406 -0
  103. package/test-data/decision-tables/basic/government-assistance.json +299 -0
  104. package/test-data/decision-tables/basic/grant-funding-distribution.json +307 -0
  105. package/test-data/decision-tables/basic/hazardous-materials-management-system.json +414 -0
  106. package/test-data/decision-tables/basic/immigration-eligibility-evaluator.json +765 -0
  107. package/test-data/decision-tables/basic/import-duties-calculator.json +318 -0
  108. package/test-data/decision-tables/basic/insurance-agent-commission.json +228 -0
  109. package/test-data/decision-tables/basic/insurance-coverage-calculator.json +362 -0
  110. package/test-data/decision-tables/basic/insurance-underwriting-risk.json +321 -0
  111. package/test-data/decision-tables/basic/international-roaming-policy-manager.json +199 -0
  112. package/test-data/decision-tables/basic/legacy-plan-management.json +434 -0
  113. package/test-data/decision-tables/basic/marketplace-listing-verification-system.json +334 -0
  114. package/test-data/decision-tables/basic/medication-dosage-calculator.json +318 -0
  115. package/test-data/decision-tables/basic/merch-bags.json +171 -0
  116. package/test-data/decision-tables/basic/municipal-permit-evaluation-system.json +364 -0
  117. package/test-data/decision-tables/basic/mvno-partner-enablement.json +313 -0
  118. package/test-data/decision-tables/basic/partner-revenue-sharing.json +244 -0
  119. package/test-data/decision-tables/basic/payment-routing-and-fee-calculator.json +475 -0
  120. package/test-data/decision-tables/basic/policy-discount-calculator.json +307 -0
  121. package/test-data/decision-tables/basic/policy-eligibility-analyzer.json +299 -0
  122. package/test-data/decision-tables/basic/product-listing-scoring.json +358 -0
  123. package/test-data/decision-tables/basic/realtime-fraud-detection.json +235 -0
  124. package/test-data/decision-tables/basic/regional-compliance-manager.json +278 -0
  125. package/test-data/decision-tables/basic/returns-and-refund-policy.json +366 -0
  126. package/test-data/decision-tables/basic/returns-processing-system.json +448 -0
  127. package/test-data/decision-tables/basic/school-district-resource-allocation.json +282 -0
  128. package/test-data/decision-tables/basic/seat-map-optimization.json +325 -0
  129. package/test-data/decision-tables/basic/seller-fee-calculator.json +307 -0
  130. package/test-data/decision-tables/basic/service-level-agreement-enforcement.json +575 -0
  131. package/test-data/decision-tables/basic/smart-financial-product-matcher.json +249 -0
  132. package/test-data/decision-tables/basic/supply-chain-risk.json +316 -0
  133. package/test-data/decision-tables/basic/table-loop.json +93 -0
  134. package/test-data/decision-tables/basic/table.json +76 -0
  135. package/test-data/decision-tables/basic/traffic-violation-penalty-calculator.json +436 -0
  136. package/test-data/decision-tables/basic/transaction-compliance-classifier.json +525 -0
  137. package/test-data/decision-tables/basic/vehicle-claims-resolution.json +310 -0
  138. package/test-data/decision-tables/basic/warehouse-storage-location.json +345 -0
  139. package/test-data/decision-tables/hit-policy-collect/collect-multiple-matches.json +127 -0
  140. package/test-data/decision-tables/hit-policy-collect/collect-no-match.json +95 -0
  141. package/test-data/decision-tables/hit-policy-first/first-match.json +103 -0
  142. package/test-data/decision-tables/hit-policy-first/no-match.json +95 -0
  143. package/test-data/decision-tables/hit-policy-output-order/output-order-respected.json +94 -0
  144. package/test-data/decision-tables/hit-policy-output-order/string-output-order.json +94 -0
  145. package/test-data/decision-tables/hit-policy-priority/priority-respected.json +86 -0
  146. package/test-data/decision-tables/hit-policy-rule-order/rule-order-respected.json +94 -0
  147. package/test-data/decision-tables/hit-policy-unique/all-match-error.json +89 -0
  148. package/test-data/decision-tables/hit-policy-unique/multiple-match-error.json +89 -0
  149. package/test-data/decision-tables/hit-policy-unique/no-match.json +88 -0
  150. package/test-data/decision-tables/hit-policy-unique/unique-match.json +99 -0
  151. package/test-data/expressions/arithmetic/error-cyclic.json +114 -0
  152. package/test-data/expressions/arithmetic/error-missing-input.json +54 -0
  153. package/test-data/expressions/arithmetic/error-missing-output.json +54 -0
  154. package/test-data/expressions/arithmetic/expression-default.json +93 -0
  155. package/test-data/expressions/arithmetic/expression-fields.json +94 -0
  156. package/test-data/expressions/arithmetic/expression-loop.json +94 -0
  157. package/test-data/expressions/arithmetic/expression-passthrough.json +108 -0
  158. package/test-data/expressions/arithmetic/expression.json +69 -0
  159. package/test-data/expressions/arithmetic/nested-request.json +125 -0
  160. package/test-data/expressions/arithmetic/number-function.json +58 -0
  161. package/test-data/expressions/arithmetic/test-number-functions.json +68 -0
  162. package/test-data/expressions/functions/all.json +149 -0
  163. package/test-data/expressions/functions/avg.json +89 -0
  164. package/test-data/expressions/functions/filter.json +109 -0
  165. package/test-data/expressions/functions/flat.json +167 -0
  166. package/test-data/expressions/functions/map-strings.json +65 -0
  167. package/test-data/expressions/functions/map.json +73 -0
  168. package/test-data/expressions/functions/reduce.json +49 -0
  169. package/test-data/expressions/functions/some.json +175 -0
  170. package/test-data/expressions/functions/sort-strings.json +97 -0
  171. package/test-data/expressions/functions/sort.json +97 -0
  172. package/test-data/expressions/logical/logical-and.json +116 -0
  173. package/test-data/expressions/logical/logical-complex.json +260 -0
  174. package/test-data/expressions/logical/logical-not.json +111 -0
  175. package/test-data/expressions/logical/logical-or.json +123 -0
  176. package/test-data/expressions/string/string-comparison.json +128 -0
  177. package/test-data/expressions/string/string-concat.json +106 -0
  178. package/test-data/expressions/string/string-contains.json +125 -0
  179. package/test-data/expressions/string/string-endsWith.json +113 -0
  180. package/test-data/expressions/string/string-indexOf.json +131 -0
  181. package/test-data/expressions/string/string-join.json +92 -0
  182. package/test-data/expressions/string/string-lower.json +94 -0
  183. package/test-data/expressions/string/string-replace.json +130 -0
  184. package/test-data/expressions/string/string-split.json +101 -0
  185. package/test-data/expressions/string/string-startsWith.json +113 -0
  186. package/test-data/expressions/string/string-substring.json +138 -0
  187. package/test-data/expressions/string/string-trim.json +100 -0
  188. package/test-data/expressions/string/string-upper.json +94 -0
  189. package/test-data/other/custom.json +51 -0
  190. package/test-data/other/customer-input-schema.json +34 -0
  191. package/test-data/other/customer-output-schema.json +34 -0
  192. package/test-data/other/passthrough.json +31 -0
  193. package/test-data/sub-decisions/basic/$nodes-child.json +31 -0
  194. package/test-data/sub-decisions/basic/$nodes-parent.json +49 -0
  195. package/test-data/sub-decisions/basic/recursive-table1.json +49 -0
  196. package/test-data/sub-decisions/basic/recursive-table2.json +49 -0
  197. package/test-data/sub-decisions/complex-multi/approval-decision.json +31 -0
  198. package/test-data/sub-decisions/complex-multi/complex-dag.json +175 -0
  199. package/test-data/sub-decisions/complex-multi/credit-check.json +31 -0
  200. package/test-data/sub-decisions/complex-multi/customer-segmentation.json +31 -0
  201. package/test-data/sub-decisions/complex-multi/discount-eligibility.json +31 -0
  202. package/test-data/sub-decisions/complex-multi/eligibility-check.json +31 -0
  203. package/test-data/sub-decisions/complex-multi/final-offer.json +31 -0
  204. package/test-data/sub-decisions/complex-multi/income-verification.json +31 -0
  205. package/test-data/sub-decisions/complex-multi/linear-chain.json +121 -0
  206. package/test-data/sub-decisions/complex-multi/pricing-calculation.json +31 -0
  207. package/test-data/sub-decisions/complex-multi/product-eligibility.json +31 -0
  208. package/test-data/sub-decisions/complex-multi/risk-assessment.json +31 -0
  209. package/test-data/sub-decisions/complex-multi/shared-validation.json +31 -0
  210. package/test-data/sub-decisions/complex-multi/validation.json +31 -0
  211. package/test-data/sub-decisions/diamond/decision-a.json +31 -0
  212. package/test-data/sub-decisions/diamond/decision-b.json +31 -0
  213. package/test-data/sub-decisions/diamond/decision-c.json +31 -0
  214. package/test-data/sub-decisions/diamond/decision-shared.json +31 -0
  215. package/test-data/sub-decisions/diamond/diamond-pattern.json +109 -0
  216. package/test-data/sub-decisions/error-propagation/parent-calls-error.json +44 -0
  217. package/test-data/sub-decisions/error-propagation/sub-decision-with-error.json +60 -0
  218. package/test-data/switch-nodes/basic/account-dormancy-management.json +245 -0
  219. package/test-data/switch-nodes/basic/application-risk-assessment.json +474 -0
  220. package/test-data/switch-nodes/basic/cellular-data-rollover-system.json +281 -0
  221. package/test-data/switch-nodes/basic/clinical-pathway-selection.json +454 -0
  222. package/test-data/switch-nodes/basic/insurance-prior-authorization.json +467 -0
  223. package/test-data/switch-nodes/basic/last-mile-delivery-assignment.json +373 -0
  224. package/test-data/switch-nodes/basic/loan-approval.json +469 -0
  225. package/test-data/switch-nodes/basic/multi-switch.json +498 -0
  226. package/test-data/switch-nodes/basic/online-checkin-eligibility.json +285 -0
  227. package/test-data/switch-nodes/basic/order-consolidation-system.json +493 -0
  228. package/test-data/switch-nodes/basic/seller-approval-workflow.json +383 -0
  229. package/test-data/switch-nodes/basic/set-fee.json +243 -0
  230. package/test-data/switch-nodes/basic/shipping-carrier-selector.json +379 -0
  231. package/test-data/switch-nodes/basic/switch-node.json +167 -0
  232. package/test-data/switch-nodes/basic/switch-performance-2.json +1307 -0
  233. package/test-data/switch-nodes/basic/switch-performance.json +691 -0
  234. package/test-data/switch-nodes/basic/tax-exemption.json +295 -0
  235. package/test-data/switch-nodes/basic/warehouse-cross-docking.json +313 -0
  236. package/test-data/switch-nodes/default-cases/switch-with-default.json +134 -0
  237. package/test-data/zen-reference/$nodes-child.json +69 -0
  238. package/test-data/zen-reference/$nodes-parent.json +34 -0
  239. package/test-data/zen-reference/8k.json +87992 -0
  240. package/test-data/zen-reference/credit-analysis.json +324 -0
  241. package/test-data/zen-reference/custom.json +51 -0
  242. package/test-data/zen-reference/customer-input-schema.json +34 -0
  243. package/test-data/zen-reference/customer-output-schema.json +34 -0
  244. package/test-data/zen-reference/error-cyclic.json +114 -0
  245. package/test-data/zen-reference/error-missing-input.json +54 -0
  246. package/test-data/zen-reference/error-missing-output.json +54 -0
  247. package/test-data/zen-reference/expression.json +69 -0
  248. package/test-data/zen-reference/function-v2.json +48 -0
  249. package/test-data/zen-reference/function.json +46 -0
  250. package/test-data/zen-reference/graphs/account-dormancy-management.json +245 -0
  251. package/test-data/zen-reference/graphs/affiliate-commission-calculator.json +228 -0
  252. package/test-data/zen-reference/graphs/airline-loyalty-points-calculations.json +285 -0
  253. package/test-data/zen-reference/graphs/airline-upgrade-eligibility.json +466 -0
  254. package/test-data/zen-reference/graphs/aml.json +537 -0
  255. package/test-data/zen-reference/graphs/application-risk-assessment.json +474 -0
  256. package/test-data/zen-reference/graphs/auto-insurance-premium-calculator.json +412 -0
  257. package/test-data/zen-reference/graphs/booking-personalization-system.json +553 -0
  258. package/test-data/zen-reference/graphs/care-team-assignment-system.json +585 -0
  259. package/test-data/zen-reference/graphs/cellular-data-rollover-system.json +281 -0
  260. package/test-data/zen-reference/graphs/claim-validation-system.json +307 -0
  261. package/test-data/zen-reference/graphs/clinical-lab-result-interpreter.json +433 -0
  262. package/test-data/zen-reference/graphs/clinical-pathway-selection.json +454 -0
  263. package/test-data/zen-reference/graphs/clinical-treatment-protocol.json +474 -0
  264. package/test-data/zen-reference/graphs/company-analysis.json +390 -0
  265. package/test-data/zen-reference/graphs/credit-limit-adjustment.json +479 -0
  266. package/test-data/zen-reference/graphs/customer-eligibility-engine.json +551 -0
  267. package/test-data/zen-reference/graphs/customer-lifetime-value.json +200 -0
  268. package/test-data/zen-reference/graphs/customer-onboarding-kyc-verification.json +611 -0
  269. package/test-data/zen-reference/graphs/customer-service-escalation.json +191 -0
  270. package/test-data/zen-reference/graphs/decision-table-discounts.json +168 -0
  271. package/test-data/zen-reference/graphs/decision-table-shipping.json +398 -0
  272. package/test-data/zen-reference/graphs/delivery-route-optimizer.json +271 -0
  273. package/test-data/zen-reference/graphs/device-compatibility-checker.json +303 -0
  274. package/test-data/zen-reference/graphs/disaster-relief-fund-allocation.json +296 -0
  275. package/test-data/zen-reference/graphs/dynamic-fx-rate-pricing-system.json +237 -0
  276. package/test-data/zen-reference/graphs/dynamic-marketplace-comission-calculator.json +242 -0
  277. package/test-data/zen-reference/graphs/dynamic-shipping-cost-calculator.json +378 -0
  278. package/test-data/zen-reference/graphs/dynamic-tarrif-engine.json +289 -0
  279. package/test-data/zen-reference/graphs/dynamic-ticket-pricing.json +325 -0
  280. package/test-data/zen-reference/graphs/empty-column-with-space.json +100 -0
  281. package/test-data/zen-reference/graphs/empty-column-without-space.json +100 -0
  282. package/test-data/zen-reference/graphs/environment-compliance-assessment.json +386 -0
  283. package/test-data/zen-reference/graphs/expression-default.json +93 -0
  284. package/test-data/zen-reference/graphs/expression-fields.json +94 -0
  285. package/test-data/zen-reference/graphs/expression-loop.json +94 -0
  286. package/test-data/zen-reference/graphs/expression-passthrough.json +108 -0
  287. package/test-data/zen-reference/graphs/expression-table-map.json +313 -0
  288. package/test-data/zen-reference/graphs/flash-sale-eligibility.json +366 -0
  289. package/test-data/zen-reference/graphs/flight-dispatch-decision-system.json +455 -0
  290. package/test-data/zen-reference/graphs/flight-rebooking-fee-calculator.json +406 -0
  291. package/test-data/zen-reference/graphs/government-assistance.json +299 -0
  292. package/test-data/zen-reference/graphs/grant-funding-distribution.json +307 -0
  293. package/test-data/zen-reference/graphs/hazardous-materials-management-system.json +414 -0
  294. package/test-data/zen-reference/graphs/immigration-eligibility-evaluator.json +765 -0
  295. package/test-data/zen-reference/graphs/import-duties-calculator.json +318 -0
  296. package/test-data/zen-reference/graphs/insurance-agent-commission.json +228 -0
  297. package/test-data/zen-reference/graphs/insurance-breakdown.json +421 -0
  298. package/test-data/zen-reference/graphs/insurance-coverage-calculator.json +362 -0
  299. package/test-data/zen-reference/graphs/insurance-prior-authorization.json +467 -0
  300. package/test-data/zen-reference/graphs/insurance-underwriting-risk.json +321 -0
  301. package/test-data/zen-reference/graphs/international-roaming-policy-manager.json +199 -0
  302. package/test-data/zen-reference/graphs/last-mile-delivery-assignment.json +373 -0
  303. package/test-data/zen-reference/graphs/legacy-plan-management.json +434 -0
  304. package/test-data/zen-reference/graphs/loan-approval.json +469 -0
  305. package/test-data/zen-reference/graphs/marketplace-listing-verification-system.json +334 -0
  306. package/test-data/zen-reference/graphs/medication-dosage-calculator.json +318 -0
  307. package/test-data/zen-reference/graphs/merch-bags.json +171 -0
  308. package/test-data/zen-reference/graphs/multi-switch.json +498 -0
  309. package/test-data/zen-reference/graphs/municipal-permit-evaluation-system.json +364 -0
  310. package/test-data/zen-reference/graphs/mvno-partner-enablement.json +313 -0
  311. package/test-data/zen-reference/graphs/nested-request.json +125 -0
  312. package/test-data/zen-reference/graphs/online-checkin-eligibility.json +285 -0
  313. package/test-data/zen-reference/graphs/order-consolidation-system.json +493 -0
  314. package/test-data/zen-reference/graphs/partner-revenue-sharing.json +244 -0
  315. package/test-data/zen-reference/graphs/payment-routing-and-fee-calculator.json +475 -0
  316. package/test-data/zen-reference/graphs/policy-discount-calculator.json +307 -0
  317. package/test-data/zen-reference/graphs/policy-eligibility-analyzer.json +299 -0
  318. package/test-data/zen-reference/graphs/product-listing-scoring.json +358 -0
  319. package/test-data/zen-reference/graphs/realtime-fraud-detection.json +235 -0
  320. package/test-data/zen-reference/graphs/regional-compliance-manager.json +278 -0
  321. package/test-data/zen-reference/graphs/returns-and-refund-policy.json +366 -0
  322. package/test-data/zen-reference/graphs/returns-processing-system.json +448 -0
  323. package/test-data/zen-reference/graphs/school-district-resource-allocation.json +282 -0
  324. package/test-data/zen-reference/graphs/seat-map-optimization.json +325 -0
  325. package/test-data/zen-reference/graphs/seller-approval-workflow.json +383 -0
  326. package/test-data/zen-reference/graphs/seller-fee-calculator.json +307 -0
  327. package/test-data/zen-reference/graphs/service-level-agreement-enforcement.json +575 -0
  328. package/test-data/zen-reference/graphs/set-fee.json +243 -0
  329. package/test-data/zen-reference/graphs/shipping-carrier-selector.json +379 -0
  330. package/test-data/zen-reference/graphs/smart-financial-product-matcher.json +249 -0
  331. package/test-data/zen-reference/graphs/supply-chain-risk.json +316 -0
  332. package/test-data/zen-reference/graphs/table-loop.json +93 -0
  333. package/test-data/zen-reference/graphs/tax-exemption.json +295 -0
  334. package/test-data/zen-reference/graphs/traffic-violation-penalty-calculator.json +436 -0
  335. package/test-data/zen-reference/graphs/transaction-compliance-classifier.json +525 -0
  336. package/test-data/zen-reference/graphs/vehicle-claims-resolution.json +310 -0
  337. package/test-data/zen-reference/graphs/warehouse-cross-docking.json +313 -0
  338. package/test-data/zen-reference/graphs/warehouse-storage-location.json +345 -0
  339. package/test-data/zen-reference/http-function.json +34 -0
  340. package/test-data/zen-reference/infinite-function.json +46 -0
  341. package/test-data/zen-reference/js/imports.js +25 -0
  342. package/test-data/zen-reference/passthrough.json +31 -0
  343. package/test-data/zen-reference/recursive-table1.json +49 -0
  344. package/test-data/zen-reference/recursive-table2.json +49 -0
  345. package/test-data/zen-reference/sleep-function.json +34 -0
  346. package/test-data/zen-reference/switch-node.json +167 -0
  347. package/test-data/zen-reference/switch-performance-2.json +1307 -0
  348. package/test-data/zen-reference/switch-performance.json +691 -0
  349. package/test-data/zen-reference/table.json +76 -0
  350. package/tests/helpers/index.ts +73 -0
  351. package/tests/helpers/mock-context.ts +231 -0
  352. package/tests/helpers/round-trip.ts +398 -0
  353. package/tests/helpers/test-harness-comparison.ts +325 -0
  354. package/tests/helpers/test-harness-wasm.ts +710 -0
  355. package/tests/helpers/test-harness.ts +28 -0
  356. package/tests/helpers/wasm-test.ts +659 -0
  357. package/tests/integration/compilation-errors.test.ts +864 -0
  358. package/tests/integration/decision-tables.test.ts +531 -0
  359. package/tests/integration/edge-cases.test.ts +787 -0
  360. package/tests/integration/expressions.test.ts +513 -0
  361. package/tests/integration/function-node-integration.test.ts +182 -0
  362. package/tests/integration/sub-decisions.test.ts +108 -0
  363. package/tests/integration/switch-nodes.test.ts +399 -0
  364. package/tests/integration/unary-or-matching.test.ts +53 -0
  365. package/tests/integration/wasm-data-types.test.ts +398 -0
  366. package/tests/integration/wasm-errors.test.ts +199 -0
  367. package/tests/integration/wasm-execution.test.ts +348 -0
  368. package/tests/integration/wasm-memory.test.ts +228 -0
  369. package/tests/scripts/analyze-coverage.ts +166 -0
  370. package/tests/scripts/categorize-tests.ts +396 -0
  371. package/tests/scripts/coverage-analysis.ts +836 -0
  372. package/tests/unit/compiler/cache.test.ts +238 -0
  373. package/tests/unit/compiler/errors.test.ts +316 -0
  374. package/tests/unit/compiler/graph-scalability.test.ts +510 -0
  375. package/tests/unit/compiler/graph.test.ts +878 -0
  376. package/tests/unit/compiler/input-validation.test.ts +447 -0
  377. package/tests/unit/compiler/logical-and-parser.test.ts +143 -0
  378. package/tests/unit/compiler/logical-not-parser.test.ts +107 -0
  379. package/tests/unit/compiler/logical-or-parser.test.ts +236 -0
  380. package/tests/unit/compiler/marshal-gen/marshal-gen.test.ts +97 -0
  381. package/tests/unit/compiler/nodes/decision-table.test.ts +103 -0
  382. package/tests/unit/compiler/nodes/decision.test.ts +182 -0
  383. package/tests/unit/compiler/nodes/function-compile.test.ts +204 -0
  384. package/tests/unit/compiler/nodes/function.test.ts +176 -0
  385. package/tests/unit/compiler/nodes/input.test.ts +30 -0
  386. package/tests/unit/compiler/nodes/switch.test.ts +127 -0
  387. package/tests/unit/compiler/optimizer-cache.test.ts +327 -0
  388. package/tests/unit/compiler/optimizer-implementation.test.ts +625 -0
  389. package/tests/unit/compiler/parser.test.ts +508 -0
  390. package/tests/unit/compiler/runtime-error-cleanup.test.ts +426 -0
  391. package/tests/unit/compiler/runtime-validation.test.ts +303 -0
  392. package/tests/unit/compiler/runtime.test.ts +221 -0
  393. package/tests/unit/compiler/schema/schema.test.ts +248 -0
  394. package/tests/unit/compiler/unary-ast-transforms.test.ts +245 -0
  395. package/tsconfig.json +27 -0
  396. package/tsup.config.ts +11 -0
  397. package/vitest.config.ts +12 -0
@@ -0,0 +1,434 @@
1
+ import { parser } from './expression-parser';
2
+ import {
3
+ type ExpressionAST,
4
+ type StringLiteral,
5
+ type Interval,
6
+ type TemplateLiteral,
7
+ type ArrayLiteral,
8
+ type ObjectLiteral,
9
+ type BinaryOperator,
10
+ } from './ast-types';
11
+ import type { CstNode } from 'chevrotain';
12
+
13
+ const BaseCstVisitor = parser.getBaseCstVisitorConstructor();
14
+
15
+ /**
16
+ * Converts Chevrotain CST to our AST format.
17
+ */
18
+ class ExpressionAstBuilder extends BaseCstVisitor {
19
+ constructor() {
20
+ super();
21
+ this.validateVisitor();
22
+ }
23
+
24
+ expression(ctx: any): ExpressionAST {
25
+ const condition = this.visit(ctx.condition);
26
+
27
+ if (ctx.Question) {
28
+ return {
29
+ type: 'TernaryOp',
30
+ condition,
31
+ consequent: this.visit(ctx.consequent),
32
+ alternate: this.visit(ctx.alternate),
33
+ };
34
+ }
35
+
36
+ return condition;
37
+ }
38
+
39
+ nullCoalescingExpression(ctx: any): ExpressionAST {
40
+ let result = this.visit(ctx.lhs);
41
+
42
+ if (ctx.rhs) {
43
+ for (const rhsNode of ctx.rhs) {
44
+ result = {
45
+ type: 'BinaryOp',
46
+ op: '??',
47
+ left: result,
48
+ right: this.visit(rhsNode),
49
+ };
50
+ }
51
+ }
52
+
53
+ return result;
54
+ }
55
+
56
+ orExpression(ctx: any): ExpressionAST {
57
+ let result = this.visit(ctx.lhs);
58
+
59
+ if (ctx.rhs) {
60
+ for (const rhsNode of ctx.rhs) {
61
+ result = {
62
+ type: 'BinaryOp',
63
+ op: 'or',
64
+ left: result,
65
+ right: this.visit(rhsNode),
66
+ };
67
+ }
68
+ }
69
+
70
+ return result;
71
+ }
72
+
73
+ andExpression(ctx: any): ExpressionAST {
74
+ let result = this.visit(ctx.lhs);
75
+
76
+ if (ctx.rhs) {
77
+ for (const rhsNode of ctx.rhs) {
78
+ result = {
79
+ type: 'BinaryOp',
80
+ op: 'and',
81
+ left: result,
82
+ right: this.visit(rhsNode),
83
+ };
84
+ }
85
+ }
86
+
87
+ return result;
88
+ }
89
+
90
+ comparisonExpression(ctx: any): ExpressionAST {
91
+ const lhs = this.visit(ctx.lhs);
92
+
93
+ if (!ctx.rhs) {
94
+ return lhs;
95
+ }
96
+
97
+ // Determine operator
98
+ let op: BinaryOperator;
99
+ if (ctx.Eq) {
100
+ op = '==';
101
+ } else if (ctx.NotEq) {
102
+ op = '!=';
103
+ } else if (ctx.Lt) {
104
+ op = '<';
105
+ } else if (ctx.Gt) {
106
+ op = '>';
107
+ } else if (ctx.LtEq) {
108
+ op = '<=';
109
+ } else if (ctx.GtEq) {
110
+ op = '>=';
111
+ } else if (ctx.In) {
112
+ op = ctx.Not ? 'not in' : 'in';
113
+ } else {
114
+ throw new Error('Unknown comparison operator');
115
+ }
116
+
117
+ return {
118
+ type: 'BinaryOp',
119
+ op,
120
+ left: lhs,
121
+ right: this.visit(ctx.rhs),
122
+ };
123
+ }
124
+
125
+ additiveExpression(ctx: any): ExpressionAST {
126
+ return this.buildLeftAssociativeBinaryOp(ctx, ['Plus', 'Minus'], ['+', '-']);
127
+ }
128
+
129
+ multiplicativeExpression(ctx: any): ExpressionAST {
130
+ return this.buildLeftAssociativeBinaryOp(ctx, ['Mult', 'Div', 'Mod'], ['*', '/', '%']);
131
+ }
132
+
133
+ // Power is right-associative, handled differently via recursion in grammar
134
+ powerExpression(ctx: any): ExpressionAST {
135
+ const base = this.visit(ctx.base);
136
+
137
+ if (ctx.exponent) {
138
+ return {
139
+ type: 'BinaryOp',
140
+ op: '^',
141
+ left: base,
142
+ right: this.visit(ctx.exponent),
143
+ };
144
+ }
145
+
146
+ return base;
147
+ }
148
+
149
+ unaryExpression(ctx: any): ExpressionAST {
150
+ if (ctx.Not || ctx.NotNot) {
151
+ return { type: 'UnaryOp', op: 'not', operand: this.visit(ctx.operand) };
152
+ }
153
+ if (ctx.Minus) {
154
+ return { type: 'UnaryOp', op: '-', operand: this.visit(ctx.operand) };
155
+ }
156
+ return this.visit(ctx.postfixExpression);
157
+ }
158
+
159
+ postfixExpression(ctx: any): ExpressionAST {
160
+ let result = this.visit(ctx.primaryExpression);
161
+
162
+ // Collect all postfix operations with their source positions
163
+ type PostfixOp =
164
+ | { type: 'member'; offset: number; idx: number }
165
+ | { type: 'index'; offset: number; idx: number }
166
+ | { type: 'call'; offset: number; idx: number };
167
+
168
+ const ops: PostfixOp[] = [];
169
+
170
+ if (ctx.Dot) {
171
+ for (let i = 0; i < ctx.Dot.length; i++) {
172
+ ops.push({ type: 'member', offset: ctx.Dot[i].startOffset, idx: i });
173
+ }
174
+ }
175
+
176
+ if (ctx.LBracket) {
177
+ for (let i = 0; i < ctx.LBracket.length; i++) {
178
+ ops.push({ type: 'index', offset: ctx.LBracket[i].startOffset, idx: i });
179
+ }
180
+ }
181
+
182
+ if (ctx.LParen) {
183
+ for (let i = 0; i < ctx.LParen.length; i++) {
184
+ ops.push({ type: 'call', offset: ctx.LParen[i].startOffset, idx: i });
185
+ }
186
+ }
187
+
188
+ // Sort by source position to apply in correct order: Chevrotain collects each operator
189
+ // type separately, but the actual evaluation order depends on source position when multiple
190
+ // operator types can appear.
191
+ //
192
+ // We must sort by position to reconstruct left-to-right evaluation order
193
+ ops.sort((a, b) => a.offset - b.offset);
194
+
195
+ // Apply each operation in order
196
+ for (const op of ops) {
197
+ if (op.type === 'member') {
198
+ const prop = ctx.property[op.idx].image;
199
+ result = { type: 'MemberAccess', object: result, property: prop };
200
+ } else if (op.type === 'index') {
201
+ const indexExpr = ctx.index[op.idx];
202
+ result = { type: 'IndexAccess', object: result, index: this.visit(indexExpr) };
203
+ } else if (op.type === 'call') {
204
+ // Check if there's an argumentList for this call
205
+ const args =
206
+ ctx.argumentList && ctx.argumentList[op.idx] ? this.visit(ctx.argumentList[op.idx]) : [];
207
+ result = { type: 'FunctionCall', callee: result, args };
208
+ }
209
+ }
210
+
211
+ return result;
212
+ }
213
+
214
+ primaryExpression(ctx: any): ExpressionAST {
215
+ if (ctx.NumberLiteral) {
216
+ const raw = ctx.NumberLiteral[0].image.replace(/_/g, '');
217
+ return { type: 'NumberLiteral', value: parseFloat(raw) };
218
+ }
219
+ if (ctx.StringLiteral) {
220
+ const raw = ctx.StringLiteral[0].image;
221
+ const value = this.unescapeString(raw.slice(1, -1));
222
+ return { type: 'StringLiteral', value };
223
+ }
224
+ if (ctx.True) {
225
+ return { type: 'BooleanLiteral', value: true };
226
+ }
227
+ if (ctx.False) {
228
+ return { type: 'BooleanLiteral', value: false };
229
+ }
230
+ if (ctx.Null) {
231
+ return { type: 'NullLiteral' };
232
+ }
233
+ if (ctx.Hash) {
234
+ return { type: 'HashRef' };
235
+ }
236
+ if (ctx.Dollar) {
237
+ return { type: 'DollarRef' };
238
+ }
239
+ if (ctx.Identifier) {
240
+ return { type: 'Identifier', name: ctx.Identifier[0].image };
241
+ }
242
+ if (ctx.arrayLiteralExpression) {
243
+ return this.visit(ctx.arrayLiteralExpression);
244
+ }
245
+ if (ctx.objectLiteralExpression) {
246
+ return this.visit(ctx.objectLiteralExpression);
247
+ }
248
+ if (ctx.expression) {
249
+ return this.visit(ctx.expression);
250
+ }
251
+ if (ctx.intervalExpression) {
252
+ return this.visit(ctx.intervalExpression);
253
+ }
254
+ if (ctx.templateLiteral) {
255
+ return this.visit(ctx.templateLiteral);
256
+ }
257
+
258
+ throw new Error('Unknown primary expression');
259
+ }
260
+
261
+ intervalExpression(ctx: any): Interval {
262
+ const startBracket = ctx.startBracket[0];
263
+ const endBracket = ctx.endBracket[0];
264
+
265
+ return {
266
+ type: 'Interval',
267
+ start: this.visit(ctx.start) as ExpressionAST,
268
+ end: this.visit(ctx.end) as ExpressionAST,
269
+ startInclusive: startBracket.tokenType.name === 'LBracket',
270
+ endInclusive: endBracket.tokenType.name === 'RBracket',
271
+ };
272
+ }
273
+
274
+ arrayLiteralExpression(ctx: any): ArrayLiteral {
275
+ if (!ctx.argumentList) {
276
+ return { type: 'ArrayLiteral', elements: [] };
277
+ }
278
+ const args = this.visit(ctx.argumentList);
279
+ return { type: 'ArrayLiteral', elements: args as ExpressionAST[] };
280
+ }
281
+
282
+ objectLiteralExpression(ctx: any): ObjectLiteral {
283
+ if (!ctx.objectPropertyList) {
284
+ return { type: 'ObjectLiteral', properties: [] };
285
+ }
286
+ const props = this.visit(ctx.objectPropertyList);
287
+ return {
288
+ type: 'ObjectLiteral',
289
+ properties: props as Array<{ key: string; value: ExpressionAST }>,
290
+ };
291
+ }
292
+
293
+ objectPropertyList(ctx: any): Array<{ key: string; value: ExpressionAST }> {
294
+ return ctx.prop.map(
295
+ (propNode: CstNode) => this.visit(propNode) as { key: string; value: ExpressionAST },
296
+ );
297
+ }
298
+
299
+ objectProperty(ctx: any): { key: string; value: ExpressionAST } {
300
+ const keyToken = ctx.key[0];
301
+ const key =
302
+ keyToken.tokenType.name === 'StringLiteral'
303
+ ? this.unescapeString(keyToken.image.slice(1, -1))
304
+ : keyToken.image;
305
+ const value = this.visit(ctx.value) as ExpressionAST;
306
+ return { key, value };
307
+ }
308
+
309
+ templateLiteral(ctx: any): TemplateLiteral | StringLiteral {
310
+ // Handle simple template with no substitution
311
+ if (ctx.TemplateNoSub) {
312
+ const raw = ctx.TemplateNoSub[0].image;
313
+ return { type: 'StringLiteral', value: this.unescapeString(raw.slice(1, -1)) };
314
+ }
315
+
316
+ // Handle template with interpolation
317
+ const parts: Array<{ text: string } | { expr: ExpressionAST }> = [];
318
+
319
+ // Extract text from TemplateHead (remove ` and ${)
320
+ const headRaw = ctx.TemplateHead[0].image;
321
+ const headText = this.unescapeString(headRaw.slice(1, -2));
322
+ if (headText) {
323
+ parts.push({ text: headText });
324
+ }
325
+
326
+ // Add expressions and middle parts
327
+ for (let i = 0; i < ctx.expr.length; i++) {
328
+ parts.push({ expr: this.visit(ctx.expr[i]) as ExpressionAST });
329
+
330
+ if (ctx.TemplateMiddle && ctx.TemplateMiddle[i]) {
331
+ const midRaw = ctx.TemplateMiddle[i].image;
332
+ const midText = this.unescapeString(midRaw.slice(1, -2));
333
+ if (midText) {
334
+ parts.push({ text: midText });
335
+ }
336
+ }
337
+ }
338
+
339
+ // Extract text from TemplateTail (remove } and `)
340
+ const tailRaw = ctx.TemplateTail[0].image;
341
+ const tailText = this.unescapeString(tailRaw.slice(1, -1));
342
+ if (tailText) {
343
+ parts.push({ text: tailText });
344
+ }
345
+
346
+ // Template literals with no interpolation (just text) can be converted to simple string
347
+ // literals, avoiding runtime template processing overhead.
348
+ if (parts.every((p) => 'text' in p)) {
349
+ const combined = parts.map((p) => (p as { text: string }).text).join('');
350
+ return { type: 'StringLiteral', value: combined };
351
+ }
352
+
353
+ return { type: 'TemplateLiteral', parts };
354
+ }
355
+
356
+ argumentList(ctx: any): ExpressionAST[] {
357
+ return ctx.arg.map((argNode: CstNode) => this.visit(argNode) as ExpressionAST);
358
+ }
359
+
360
+ /**
361
+ * Helper to unescape string literals.
362
+ * Handles basic escape sequences like \n, \t, \", \', \\, etc.
363
+ */
364
+ private unescapeString(s: string): string {
365
+ return s
366
+ .replace(/\\n/g, '\n')
367
+ .replace(/\\t/g, '\t')
368
+ .replace(/\\r/g, '\r')
369
+ .replace(/\\'/g, "'")
370
+ .replace(/"/g, '"')
371
+ .replace(/\\\\/g, '\\');
372
+ }
373
+
374
+ /**
375
+ * Helper for left-associative binary operators.
376
+ * Collects all operator tokens, sorts them by position, and pairs them with RHS operands.
377
+ */
378
+ private buildLeftAssociativeBinaryOp(
379
+ ctx: any,
380
+ tokenNames: string[],
381
+ ops: BinaryOperator[],
382
+ ): ExpressionAST {
383
+ let result = this.visit(ctx.lhs) as ExpressionAST;
384
+
385
+ if (!ctx.rhs) {
386
+ // No right-hand side: return just the left expression
387
+ return result;
388
+ }
389
+
390
+ // Collect all operator tokens with their corresponding operator symbol
391
+ const operatorTokens: Array<{ op: BinaryOperator; offset: number }> = [];
392
+ for (let j = 0; j < tokenNames.length; j++) {
393
+ const tokens = ctx[tokenNames[j]];
394
+ if (tokens) {
395
+ for (const token of tokens) {
396
+ operatorTokens.push({ op: ops[j], offset: token.startOffset });
397
+ }
398
+ }
399
+ }
400
+
401
+ // Sort operators by their position in the source
402
+ operatorTokens.sort((a, b) => a.offset - b.offset);
403
+
404
+ // Build the expression tree left-to-right
405
+ for (let i = 0; i < ctx.rhs.length; i++) {
406
+ const op = operatorTokens[i]?.op;
407
+ if (!op) {
408
+ throw new Error(`Operator not found for ${tokenNames.join(', ')}`);
409
+ }
410
+
411
+ result = {
412
+ type: 'BinaryOp',
413
+ op,
414
+ left: result,
415
+ right: this.visit(ctx.rhs[i]) as ExpressionAST,
416
+ };
417
+ }
418
+
419
+ return result;
420
+ }
421
+ }
422
+
423
+ export const astBuilder = new ExpressionAstBuilder();
424
+
425
+ /**
426
+ * Convert a CST (Concrete Syntax Tree) to an AST (Abstract Syntax Tree).
427
+ * CST contains low-level parsing artifacts; AST simplifies structure for compilation
428
+ *
429
+ * @param cst - The CST from the Chevrotain parser
430
+ * @returns The AST node
431
+ */
432
+ export function cstToAst(cst: CstNode): ExpressionAST {
433
+ return astBuilder.visit(cst);
434
+ }
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Error handling infrastructure for the JDM compiler.
3
+ *
4
+ * This module provides:
5
+ * - CompilationError: The main error class for all compilation failures
6
+ * - ErrorCode: A comprehensive enumeration of all possible error types
7
+ * - SourceLocation: Detailed location information for error reporting
8
+ * - ErrorCollector: Aggregates non-fatal expression errors for batch reporting
9
+ */
10
+
11
+ /**
12
+ * Detailed source location for error reporting.
13
+ */
14
+ export interface SourceLocation {
15
+ /** ID of the node where the error occurred */
16
+ nodeId?: string;
17
+ /** Name of the node where the error occurred */
18
+ nodeName?: string;
19
+ /** Field name within the node */
20
+ field?: string;
21
+ /** Line number in source JDM */
22
+ line?: number;
23
+ /** Column number in source JDM */
24
+ column?: number;
25
+ }
26
+
27
+ /**
28
+ * Enumeration of all possible compilation error codes.
29
+ *
30
+ * Errors are categorized into three types:
31
+ * - Structural errors: Critical JDM structure issues that fail compilation immediately
32
+ * - Feature errors: Unsupported features that cannot be handled
33
+ * - Expression errors: Issues in expression parsing that can be collected and reported together
34
+ */
35
+ export enum ErrorCode {
36
+ // Structural errors (fail immediately)
37
+ INVALID_JSON = 'INVALID_JSON',
38
+ INVALID_NODE_STRUCTURE = 'INVALID_NODE_STRUCTURE',
39
+ MISSING_INPUT_NODE = 'MISSING_INPUT_NODE',
40
+ MISSING_OUTPUT_NODE = 'MISSING_OUTPUT_NODE',
41
+ MULTIPLE_INPUT_NODES = 'MULTIPLE_INPUT_NODES',
42
+ CYCLE_DETECTED = 'CYCLE_DETECTED',
43
+ INVALID_EDGE = 'INVALID_EDGE',
44
+
45
+ // Feature errors (fail immediately)
46
+ UNSUPPORTED_FUNCTION_NODE = 'UNSUPPORTED_FUNCTION_NODE',
47
+ UNSUPPORTED_EXPRESSION = 'UNSUPPORTED_EXPRESSION',
48
+
49
+ // Expression errors (collected, reported together)
50
+ PARSE_ERROR = 'PARSE_ERROR',
51
+ UNKNOWN_FUNCTION = 'UNKNOWN_FUNCTION',
52
+ TYPE_MISMATCH = 'TYPE_MISMATCH',
53
+ UNKNOWN_FIELD = 'UNKNOWN_FIELD',
54
+
55
+ // Schema errors
56
+ SCHEMA_MISMATCH = 'SCHEMA_MISMATCH',
57
+ INVALID_SCHEMA = 'INVALID_SCHEMA',
58
+ }
59
+
60
+ /**
61
+ * Custom error class for compilation failures.
62
+ *
63
+ * Provides structured error information including error code, source location,
64
+ * and additional context for debugging.
65
+ */
66
+ export class CompilationError extends Error {
67
+ readonly name = 'CompilationError';
68
+
69
+ constructor(
70
+ message: string,
71
+ public readonly code: ErrorCode,
72
+ public readonly location?: SourceLocation,
73
+ public readonly context?: Record<string, unknown>,
74
+ ) {
75
+ super(message);
76
+ // Exclude the CompilationError constructor frame from the stack trace.
77
+ // Without this, stack traces would include an unhelpful constructor frame,
78
+ // making it harder to identify the actual error source in compiled code.
79
+ // Only available on V8-based engines (Node.js, Chrome, Edge).
80
+ if (Error.captureStackTrace) {
81
+ Error.captureStackTrace(this, CompilationError);
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Get a formatted error message with location information.
87
+ */
88
+ getFormattedMessage(): string {
89
+ const parts: string[] = [];
90
+
91
+ if (this.location) {
92
+ const locParts: string[] = [];
93
+ if (this.location.nodeName) {
94
+ locParts.push(this.location.nodeName);
95
+ }
96
+ if (this.location.nodeId) {
97
+ locParts.push(`(id: ${this.location.nodeId})`);
98
+ }
99
+ if (this.location.field) {
100
+ locParts.push(`.${this.location.field}`);
101
+ }
102
+ // Combine line and column: @10:5
103
+ if (this.location.line !== undefined && this.location.column !== undefined) {
104
+ locParts.push(`@${this.location.line}:${this.location.column}`);
105
+ } else if (this.location.line !== undefined) {
106
+ locParts.push(`@${this.location.line}`);
107
+ } else if (this.location.column !== undefined) {
108
+ locParts.push(`:${this.location.column}`);
109
+ }
110
+
111
+ if (locParts.length > 0) {
112
+ parts.push(`[${locParts.join(' ')}]`);
113
+ }
114
+ }
115
+
116
+ parts.push(`[${this.code}]`);
117
+ parts.push(this.message);
118
+
119
+ return parts.join(' ');
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Collector for non-fatal errors during expression parsing.
125
+ *
126
+ * This allows the parser to continue and collect multiple errors rather than
127
+ * failing on the first one, providing a better user experience by reporting
128
+ * all issues at once.
129
+ *
130
+ * @example
131
+ * const collector = new ErrorCollector();
132
+ * collector.add(new CompilationError('Undefined variable', ErrorCode.UNKNOWN_FIELD, { nodeName: 'AgeCheck' }));
133
+ * collector.add(new CompilationError('Type mismatch', ErrorCode.TYPE_MISMATCH, { nodeName: 'AgeCheck' }));
134
+ * collector.throwIfErrors(); // Throws with aggregated message
135
+ */
136
+ export class ErrorCollector {
137
+ private errors: CompilationError[] = [];
138
+
139
+ /**
140
+ * Add an error to the collector.
141
+ */
142
+ add(error: CompilationError): void {
143
+ this.errors.push(error);
144
+ }
145
+
146
+ /**
147
+ * Check if any errors have been collected.
148
+ */
149
+ hasErrors(): boolean {
150
+ return this.errors.length > 0;
151
+ }
152
+
153
+ /**
154
+ * Throw if there are any collected errors.
155
+ *
156
+ * Single errors throw directly to preserve original context and stack trace. Multiple
157
+ * errors are aggregated into one with numbered list, so developers see all problems at
158
+ * once instead of fixing issues one-by-one through repeated compile attempts.
159
+ */
160
+ throwIfErrors(): void {
161
+ if (this.errors.length === 0) {
162
+ return;
163
+ }
164
+
165
+ if (this.errors.length === 1) {
166
+ throw this.errors[0];
167
+ }
168
+
169
+ const message =
170
+ `${this.errors.length} compilation errors:\n` +
171
+ this.errors
172
+ .map((e, i) => {
173
+ const prefix = ` ${i + 1}. ${e.code}`;
174
+ const formatted = e.getFormattedMessage();
175
+ // getFormattedMessage() includes [CODE] prefix, but we already show the code in
176
+ // our numbered list, so strip it to avoid "1. CODE: [CODE] message"
177
+ const rest = formatted.replace(`[${e.code}]`, '').trim();
178
+ return `${prefix}${rest ? ': ' + rest : ''}`;
179
+ })
180
+ .join('\n');
181
+
182
+ // Use the location from the first error as the aggregated error's location
183
+ const firstErrorLocation = this.errors[0].location;
184
+ throw new CompilationError(message, ErrorCode.PARSE_ERROR, firstErrorLocation);
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Type guard to check if an error is a CompilationError.
190
+ */
191
+ export function isCompilationError(error: unknown): error is CompilationError {
192
+ return error instanceof CompilationError;
193
+ }
194
+
195
+ /**
196
+ * Type guard to check if an error code is a structural error.
197
+ */
198
+ export function isStructuralError(code: ErrorCode): boolean {
199
+ return [
200
+ ErrorCode.INVALID_JSON,
201
+ ErrorCode.INVALID_NODE_STRUCTURE,
202
+ ErrorCode.MISSING_INPUT_NODE,
203
+ ErrorCode.MISSING_OUTPUT_NODE,
204
+ ErrorCode.MULTIPLE_INPUT_NODES,
205
+ ErrorCode.CYCLE_DETECTED,
206
+ ErrorCode.INVALID_EDGE,
207
+ ].includes(code);
208
+ }
209
+
210
+ /**
211
+ * Type guard to check if an error code is a feature error.
212
+ */
213
+ export function isFeatureError(code: ErrorCode): boolean {
214
+ return [ErrorCode.UNSUPPORTED_FUNCTION_NODE, ErrorCode.UNSUPPORTED_EXPRESSION].includes(code);
215
+ }
216
+
217
+ /**
218
+ * Type guard to check if an error code is an expression error.
219
+ */
220
+ export function isExpressionError(code: ErrorCode): boolean {
221
+ return [
222
+ ErrorCode.PARSE_ERROR,
223
+ ErrorCode.UNKNOWN_FUNCTION,
224
+ ErrorCode.TYPE_MISMATCH,
225
+ ErrorCode.UNKNOWN_FIELD,
226
+ ].includes(code);
227
+ }