@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,352 @@
1
+ /**
2
+ * Main compilation orchestrator for JDM decisions.
3
+ *
4
+ * This module coordinates the compilation pipeline, bringing together:
5
+ * - Graph building and topological ordering
6
+ * - Node compilation
7
+ * - Switch branch detection
8
+ * - Result selection
9
+ * - Memory layout code generation
10
+ *
11
+ * The orchestrator itself does minimal work - it delegates to specialized modules
12
+ * for each concern.
13
+ */
14
+
15
+ import type { JDMDecision, JDMNode } from './parser';
16
+ import type { CompilationContext, AssemblyScriptCode } from './types';
17
+ import { buildGraph, getEvaluationOrder } from './graph';
18
+ import { compileInputNode, compileOutputNode } from './nodes/input';
19
+ import { compileDecisionTableNode } from './nodes/decision-table';
20
+ import { compileSwitchNode } from './nodes/switch';
21
+ import { compileDecisionNode } from './nodes/decision';
22
+ import { compileExpressionNode } from './nodes/expression';
23
+ import { compileFunctionNode } from './nodes/function';
24
+ import { sanitizeId } from './utils';
25
+ import { validateAllInputReferences, validateAllOutputReferences } from './compile-time-validation';
26
+ import { generatePassThroughMergeCode, generateNestedPathAssignment } from './code-generators';
27
+ import { findSwitchBranchTargets } from './switch-branch-detection';
28
+ import {
29
+ selectResultNode,
30
+ generateResultCode,
31
+ generateFallbackResultCode,
32
+ } from './result-selection';
33
+
34
+ // ============================================================================
35
+ // Memory Layout Constants
36
+ // ============================================================================
37
+
38
+ /**
39
+ * Custom heap start offset in bytes (512KB).
40
+ *
41
+ * The custom heap starts at 512KB to avoid conflicts with:
42
+ * 1. AssemblyScript's internal runtime heap (~50KB - ~192KB)
43
+ * 2. Host-written input buffer region (192KB - 512KB, up to 320KB)
44
+ *
45
+ * This ensures clear separation of memory regions and prevents
46
+ * the AS runtime from interfering with our custom heap allocator.
47
+ * Host must grow memory to at least 768KB to use this layout.
48
+ */
49
+ const CUSTOM_HEAP_START_BYTES = 512 * 1024;
50
+
51
+ /**
52
+ * Compile a JDM decision to AssemblyScript code.
53
+ *
54
+ * This function orchestrates compilation of all nodes in the decision graph
55
+ * and generates the complete AssemblyScript module.
56
+ *
57
+ * @param jdm - The parsed JDM decision
58
+ * @param context - The compilation context
59
+ * @returns Generated AssemblyScript code
60
+ */
61
+ export function compileDecision(jdm: JDMDecision, context: CompilationContext): AssemblyScriptCode {
62
+ // Build the graph
63
+ const graph = buildGraph(jdm);
64
+
65
+ // Get nodes in topological order to ensure dependencies are compiled before dependents
66
+ const evaluationOrder = getEvaluationOrder(graph);
67
+
68
+ // Validate references if enabled
69
+ if (context.options.validate !== false) {
70
+ validateAllInputReferences(context);
71
+ validateAllOutputReferences(context);
72
+ }
73
+
74
+ // Create a node lookup for quick access
75
+ const nodeMap = new Map(jdm.nodes.map((n) => [n.id, n]));
76
+
77
+ // Compile each node based on its type
78
+ const compiledCode = compileNodes(evaluationOrder, nodeMap, context);
79
+
80
+ // Generate helper functions for higher-order operations
81
+ const helperFunctionsCode = Array.from(context.helperFunctions.values()).join('\n');
82
+
83
+ // Find nodes that are switch branch targets (should be skipped in main evaluation)
84
+ const switchBranchTargets = findSwitchBranchTargets(jdm);
85
+
86
+ // Generate evaluation code for each node in topological order
87
+ const evaluationCode = generateEvaluationCode(evaluationOrder, nodeMap, switchBranchTargets);
88
+
89
+ // Find output nodes (nodes with no outgoing edges)
90
+ const outputNodeIds = findOutputNodeIds(jdm);
91
+
92
+ // Find evaluated nodes (excluding input, output, and switch branch targets)
93
+ const evaluatedNodes = filterEvaluatedNodes(evaluationOrder, nodeMap, switchBranchTargets);
94
+
95
+ // Generate result selection code
96
+ const resultCode = generateResultSelectionCode(nodeMap, evaluatedNodes, outputNodeIds);
97
+
98
+ // Generate the complete AssemblyScript module
99
+ return generateModuleCode(helperFunctionsCode, compiledCode, evaluationCode, resultCode);
100
+ }
101
+
102
+ /**
103
+ * Compile all nodes in evaluation order.
104
+ */
105
+ function compileNodes(
106
+ evaluationOrder: string[],
107
+ nodeMap: Map<string, JDMNode>,
108
+ context: CompilationContext,
109
+ ): string {
110
+ let compiledCode = '';
111
+
112
+ for (const nodeId of evaluationOrder) {
113
+ const node = nodeMap.get(nodeId);
114
+ if (!node) {
115
+ continue;
116
+ }
117
+
118
+ const nodeType = node.type;
119
+
120
+ switch (nodeType) {
121
+ case 'inputNode':
122
+ compiledCode += compileInputNode(node, context);
123
+ break;
124
+ case 'decisionTableNode':
125
+ compiledCode += compileDecisionTableNode(node, context);
126
+ break;
127
+ case 'switchNode':
128
+ compiledCode += compileSwitchNode(node, context);
129
+ break;
130
+ case 'decisionNode':
131
+ compiledCode += compileDecisionNode(node, context);
132
+ break;
133
+ case 'outputNode':
134
+ compiledCode += compileOutputNode(node, context);
135
+ break;
136
+ case 'expressionNode':
137
+ compiledCode += compileExpressionNode(node, context);
138
+ break;
139
+ case 'functionNode':
140
+ compiledCode += compileFunctionNode(node, context);
141
+ break;
142
+ default:
143
+ // Unknown node type - skip
144
+ break;
145
+ }
146
+ }
147
+
148
+ return compiledCode;
149
+ }
150
+
151
+ /**
152
+ * Generate evaluation code for each node in topological order.
153
+ * Skips output nodes and switch branch targets.
154
+ */
155
+ function generateEvaluationCode(
156
+ evaluationOrder: string[],
157
+ nodeMap: Map<string, JDMNode>,
158
+ switchBranchTargets: Set<string>,
159
+ ): string {
160
+ return evaluationOrder
161
+ .map((nodeId) => {
162
+ const node = nodeMap.get(nodeId);
163
+ if (!node || node.type === 'outputNode') {
164
+ return '';
165
+ }
166
+
167
+ // Skip nodes that are switch branch targets - they'll be evaluated by the switch
168
+ if (switchBranchTargets.has(nodeId)) {
169
+ return '';
170
+ }
171
+
172
+ return generateNodeEvaluationCode(node);
173
+ })
174
+ .filter(Boolean)
175
+ .join('\n');
176
+ }
177
+
178
+ /**
179
+ * Generate evaluation code for a single node.
180
+ */
181
+ function generateNodeEvaluationCode(node: JDMNode): string {
182
+ const sanitizedId = sanitizeId(node.id);
183
+
184
+ // Check if this node has passThrough enabled (decision tables and expression nodes)
185
+ const hasPassThrough = node.content?.passThrough === true;
186
+
187
+ // Store node result in context under $nodes.<nodeName>
188
+ let code = ` ctx.set("$nodes.${node.name}", evaluateNode_${sanitizedId}(ctx));`;
189
+
190
+ // Handle outputPath - if specified, store the result at the given path
191
+ // This is used for collect-style decision tables to place array results at a nested path
192
+ const outputPath = node.content?.outputPath;
193
+ if (outputPath) {
194
+ // Check if it's a simple (non-nested) path or a nested path
195
+ if (!outputPath.includes('.')) {
196
+ // Simple path - just set directly in context
197
+ code += `
198
+ // Store node output at outputPath: ${outputPath} (simple path)
199
+ ctx.set("${outputPath}", ctx.get("$nodes.${node.name}"));`;
200
+ } else {
201
+ // Nested path - use shared helper to generate nested object structure
202
+ code += `
203
+ ${generateNestedPathAssignment(outputPath, `ctx.get("$nodes.${node.name}")`)}`;
204
+ }
205
+ }
206
+
207
+ // If passThrough is enabled, merge the node's output properties back into the context
208
+ // This allows subsequent nodes to access the computed values directly
209
+ if (hasPassThrough) {
210
+ code += `\n ${generatePassThroughMergeCode(node.name)}`;
211
+ }
212
+
213
+ return code;
214
+ }
215
+
216
+ /**
217
+ * Find output node IDs (nodes with no outgoing edges).
218
+ */
219
+ function findOutputNodeIds(jdm: JDMDecision): Set<string> {
220
+ const outputNodeIds = new Set<string>();
221
+ for (const node of jdm.nodes) {
222
+ const outgoingEdges = jdm.edges.filter((e) => e.sourceId === node.id);
223
+ if (outgoingEdges.length === 0) {
224
+ outputNodeIds.add(node.id);
225
+ }
226
+ }
227
+ return outputNodeIds;
228
+ }
229
+
230
+ /**
231
+ * Filter evaluation order to get only nodes that were actually evaluated.
232
+ */
233
+ function filterEvaluatedNodes(
234
+ evaluationOrder: string[],
235
+ nodeMap: Map<string, JDMNode>,
236
+ switchBranchTargets: Set<string>,
237
+ ): string[] {
238
+ return evaluationOrder.filter((id) => {
239
+ const node = nodeMap.get(id);
240
+ if (!node) {
241
+ return false;
242
+ }
243
+ // Exclude input and output nodes
244
+ if (node.type === 'inputNode' || node.type === 'outputNode') {
245
+ return false;
246
+ }
247
+ // Exclude switch branch targets - they're evaluated by the switch
248
+ if (switchBranchTargets.has(id)) {
249
+ return false;
250
+ }
251
+ return true;
252
+ });
253
+ }
254
+
255
+ /**
256
+ * Generate code to select and extract the final result.
257
+ */
258
+ function generateResultSelectionCode(
259
+ nodeMap: Map<string, JDMNode>,
260
+ evaluatedNodes: string[],
261
+ outputNodeIds: Set<string>,
262
+ ): string {
263
+ // Use the result-selection module to determine which node's result to use
264
+ const resultNode = selectResultNode({
265
+ nodeMap,
266
+ evaluatedNodes,
267
+ switchBranchTargets: new Set(), // Already filtered out
268
+ });
269
+
270
+ if (resultNode) {
271
+ return generateResultCode(resultNode);
272
+ }
273
+
274
+ return generateFallbackResultCode(outputNodeIds, sanitizeId);
275
+ }
276
+
277
+ /**
278
+ * Generate the complete AssemblyScript module code.
279
+ */
280
+ function generateModuleCode(
281
+ helperFunctionsCode: string,
282
+ compiledCode: string,
283
+ evaluationCode: string,
284
+ resultCode: string,
285
+ ): string {
286
+ return `
287
+ import { Value } from './values';
288
+ import { Context, ScopedContext } from './context';
289
+ import {
290
+ addValues,
291
+ subtractValues,
292
+ multiplyValues,
293
+ divideValues,
294
+ moduloValues,
295
+ powerValues,
296
+ negateValue,
297
+ valuesEqual,
298
+ compareValues,
299
+ getProperty,
300
+ getIndex,
301
+ valueIn,
302
+ createInterval,
303
+ evaluateFunction,
304
+ makeArgs1,
305
+ makeArgs2,
306
+ makeArgs3
307
+ } from './expressions';
308
+ import { SetLastError, SetLastErrorWithMessage, hasError, RuntimeErrorCode, initializeMemoryLayout, resetHeap } from './memory';
309
+ import { readValueMap, writeValue } from './arrays';
310
+
311
+ ${helperFunctionsCode}
312
+
313
+ ${compiledCode}
314
+
315
+ // Main entry point for the compiled decision
316
+ // Input: pointer to input data in WASM memory (serialized Map<string, Value>)
317
+ // Returns: pointer to output data in WASM memory (serialized Value)
318
+ export function evaluate(inputPtr: usize): usize {
319
+ // Initialize memory layout for custom heap (used for output marshaling)
320
+ // Memory regions (from 0):
321
+ // +--------------------------+
322
+ // | Static data | 0 - ~50KB (AS's __heap_base)
323
+ // +--------------------------+
324
+ // | AS runtime heap | ~50KB - ~192KB (grows upward during evaluation)
325
+ // +--------------------------+
326
+ // | Input data buffer | 192KB - 512KB (written by host, up to 320KB)
327
+ // +--------------------------+
328
+ // | Custom heap (ours) | 512KB - (used for writeValue/marshaling)
329
+ // +--------------------------+
330
+ // The custom heap starts at 512KB to avoid conflicts with AS's internal heap
331
+ // and the host-written input buffer. Host must grow memory to at least 768KB.
332
+ initializeMemoryLayout(${CUSTOM_HEAP_START_BYTES}, 0);
333
+
334
+ // Reset heap for fresh evaluation
335
+ resetHeap();
336
+
337
+ // Read input from memory
338
+ let input = readValueMap(inputPtr);
339
+
340
+ // Create context with input data
341
+ let ctx = new Context(input);
342
+
343
+ // Evaluate the decision graph in topological order
344
+ ${evaluationCode}
345
+
346
+ // Get the final result
347
+ ${resultCode}
348
+ // Write result to output memory and return pointer
349
+ return writeValue(result);
350
+ }
351
+ `;
352
+ }
@@ -0,0 +1,115 @@
1
+ import { CompilationError, ErrorCode } from './errors';
2
+ import { validateFunctionNode } from './nodes/function';
3
+
4
+ export enum NodeType {
5
+ INPUT = 'inputNode',
6
+ OUTPUT = 'outputNode',
7
+ DECISION_TABLE = 'decisionTableNode',
8
+ SWITCH = 'switchNode',
9
+ EXPRESSION = 'expressionNode',
10
+ DECISION = 'decisionNode',
11
+ FUNCTION = 'functionNode',
12
+ }
13
+
14
+ export interface JDMNode {
15
+ id: string;
16
+ type: NodeType;
17
+ name: string;
18
+ position: { x: number; y: number };
19
+ content?: any;
20
+ parsedContent?: any;
21
+ }
22
+
23
+ export interface JDMEdge {
24
+ id: string;
25
+ type: string;
26
+ sourceId: string;
27
+ targetId: string;
28
+ /** Optional source handle for nodes with multiple outputs (e.g., switch statements) */
29
+ sourceHandle?: string;
30
+ }
31
+
32
+ export interface JDMDecision {
33
+ nodes: JDMNode[];
34
+ edges: JDMEdge[];
35
+ metadata?: any;
36
+ }
37
+
38
+ /**
39
+ * Validate that a node has all required fields.
40
+ *
41
+ * All JDM nodes must have: id, name, and type.
42
+ * Validating early provides clear error messages before processing.
43
+ *
44
+ * @param node - The node to validate
45
+ * @param index - The index of the node in the nodes array (for error reporting)
46
+ * @throws CompilationError if required fields are missing
47
+ */
48
+ export function validateNodeStructure(node: any, index: number): void {
49
+ const missingFields: string[] = [];
50
+
51
+ if (typeof node.id !== 'string' || node.id.trim() === '') {
52
+ missingFields.push('id');
53
+ }
54
+
55
+ if (typeof node.name !== 'string') {
56
+ missingFields.push('name');
57
+ }
58
+
59
+ if (typeof node.type !== 'string' || node.type.trim() === '') {
60
+ missingFields.push('type');
61
+ }
62
+
63
+ if (missingFields.length > 0) {
64
+ const nodeIdentifier = node.id || node.name || `at index ${index}`;
65
+ throw new CompilationError(
66
+ `Node "${nodeIdentifier}" is missing required field(s): ${missingFields.join(', ')}`,
67
+ ErrorCode.INVALID_NODE_STRUCTURE,
68
+ { nodeId: node.id, nodeName: node.name },
69
+ );
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Parse and validate JDM JSON.
75
+ * Function nodes have complex internal structure that needs schema validation and transformation.
76
+ * Validating early provides better error messages and catches issues before expensive compilation steps.
77
+ */
78
+ export function parseJDM(jdm: string | JDMDecision | any): JDMDecision {
79
+ const parsed: JDMDecision = typeof jdm === 'string' ? JSON.parse(jdm) : jdm;
80
+
81
+ // Validate basic structure before processing
82
+ if (!parsed.nodes || !Array.isArray(parsed.nodes)) {
83
+ throw new CompilationError(
84
+ "Invalid JDM: missing or invalid 'nodes' array",
85
+ ErrorCode.INVALID_JSON,
86
+ { field: 'nodes' },
87
+ );
88
+ }
89
+
90
+ // Validate each node has required fields before any processing
91
+ parsed.nodes.forEach((node: any, index: number) => {
92
+ validateNodeStructure(node, index);
93
+ });
94
+
95
+ // Function nodes have rich content structure (parameters, return type, expressions) requiring special
96
+ // parsing. Other node types have simpler content handled during codegen.
97
+ parsed.nodes.forEach((node: any) => {
98
+ if (node.type === NodeType.FUNCTION) {
99
+ try {
100
+ node.parsedContent = validateFunctionNode(node);
101
+ } catch (error) {
102
+ if (error instanceof CompilationError) {
103
+ throw error;
104
+ }
105
+ throw new CompilationError(
106
+ `Failed to parse function node "${node.name}": ${error instanceof Error ? error.message : String(error)}`,
107
+ ErrorCode.INVALID_NODE_STRUCTURE,
108
+ { nodeId: node.id, nodeName: node.name },
109
+ );
110
+ }
111
+ }
112
+ });
113
+
114
+ return parsed;
115
+ }
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Result selection logic for JDM decisions.
3
+ *
4
+ * This module determines how to compute the final result from the evaluation order.
5
+ * It handles different scenarios:
6
+ * - Switch nodes that route to different branches
7
+ * - Decision tables with collect-style hit policies
8
+ * - PassThrough nodes that accumulate context
9
+ * - Regular nodes that return their result directly
10
+ */
11
+
12
+ import type { JDMNode } from './parser';
13
+
14
+ /**
15
+ * Check if a decision table node uses a collect-style hit policy.
16
+ * Collect-style policies return arrays and need to be wrapped in an object with the node name as key.
17
+ */
18
+ export function isCollectStyleHitPolicy(node: JDMNode): boolean {
19
+ if (node.type !== 'decisionTableNode') {
20
+ return false;
21
+ }
22
+ const hitPolicy = node.content?.hitPolicy || 'first';
23
+ return ['collect', 'ruleOrder', 'outputOrder', 'priority'].includes(hitPolicy);
24
+ }
25
+
26
+ /**
27
+ * Options for result code generation.
28
+ */
29
+ export interface ResultSelectionOptions {
30
+ /** Map of node IDs to JDMNode objects */
31
+ nodeMap: Map<string, JDMNode>;
32
+ /** Ordered list of node IDs that were actually evaluated (not skipped) */
33
+ evaluatedNodes: string[];
34
+ /** Set of node IDs that are switch branch targets (skipped in main loop) */
35
+ switchBranchTargets: Set<string>;
36
+ }
37
+
38
+ /**
39
+ * Determine which node's result should be used as the final output.
40
+ *
41
+ * Priority order:
42
+ * 1. If there's a switch node, use its result (it handles routing)
43
+ * 2. Otherwise, use the last non-input, non-output node result
44
+ * 3. Fallback to output node or null
45
+ *
46
+ * @param options - The selection options
47
+ * @returns The node to use for the final result, or null if fallback needed
48
+ */
49
+ export function selectResultNode(options: ResultSelectionOptions): JDMNode | null {
50
+ const { nodeMap, evaluatedNodes } = options;
51
+
52
+ // Check if there's a switch node that routes to different branches
53
+ // Only switch nodes truly route - decision tables in a linear flow are NOT routing nodes
54
+ const switchNodes = evaluatedNodes.filter((id) => {
55
+ const node = nodeMap.get(id);
56
+ return node && node.type === 'switchNode';
57
+ });
58
+
59
+ // When there are switch nodes, use the switch result since it handles branch evaluation
60
+ if (switchNodes.length > 0) {
61
+ // Use the last switch node's result (it handles branch routing to terminal nodes)
62
+ const lastSwitchNodeId = switchNodes[switchNodes.length - 1];
63
+ return nodeMap.get(lastSwitchNodeId) || null;
64
+ }
65
+
66
+ // Use the last evaluated node
67
+ if (evaluatedNodes.length > 0) {
68
+ const lastNodeId = evaluatedNodes[evaluatedNodes.length - 1];
69
+ return nodeMap.get(lastNodeId) || null;
70
+ }
71
+
72
+ return null;
73
+ }
74
+
75
+ /**
76
+ * Generate AssemblyScript code to extract the final result from a node.
77
+ *
78
+ * Handles:
79
+ * - Collect-style hit policies (return array directly)
80
+ * - PassThrough nodes (return accumulated context)
81
+ * - Regular nodes (return node result directly)
82
+ *
83
+ * @param node - The node to generate result code for
84
+ * @returns AssemblyScript code string
85
+ */
86
+ export function generateResultCode(node: JDMNode): string {
87
+ // COLLECT-style hit policies return arrays directly (not wrapped in an object with the
88
+ // node name as key) to match zen-engine behavior where the array IS the result
89
+ if (isCollectStyleHitPolicy(node)) {
90
+ return ` let result = ctx.get("$nodes.${node.name}");`;
91
+ }
92
+
93
+ // If the node has passThrough enabled, return the accumulated context
94
+ // This includes all values from previous nodes that were merged via passThrough
95
+ //
96
+ // Both 'no match with passThrough' and 'valid result' return Objects, so we use
97
+ // the __passthrough marker a marker to distinguish these cases while maintaining
98
+ // type safety.
99
+ const hasPassThrough = node.content?.passThrough === true;
100
+ if (hasPassThrough) {
101
+ return ` // Check node result for passThrough handling
102
+ let __nodeResult = ctx.get("$nodes.${node.name}");
103
+ let result: Value;
104
+
105
+ // Check if this is a "passthrough signal" (no match with passThrough enabled)
106
+ if (!__nodeResult.isNull() && __nodeResult.isObject()) {
107
+ let __obj = __nodeResult.asObject();
108
+ if (__obj.has("__passthrough") && __obj.get("__passthrough").asBool()) {
109
+ // Node signaled to use passthrough - return accumulated context
110
+ let __finalResult = new Map<string, Value>();
111
+ const __ctxKeys = ctx.data.keys();
112
+ for (let __i = 0; __i < __ctxKeys.length; __i++) {
113
+ const __key = __ctxKeys[__i];
114
+ if (!__key.startsWith("$") && __key !== "#" && __key !== "acc") {
115
+ __finalResult.set(__key, ctx.data.get(__key));
116
+ }
117
+ }
118
+ result = Value.Object(__finalResult);
119
+ } else {
120
+ // Valid result - build from accumulated context (passThrough merges input with output)
121
+ let __finalResult = new Map<string, Value>();
122
+ const __ctxKeys = ctx.data.keys();
123
+ for (let __i = 0; __i < __ctxKeys.length; __i++) {
124
+ const __key = __ctxKeys[__i];
125
+ if (!__key.startsWith("$") && __key !== "#" && __key !== "acc") {
126
+ __finalResult.set(__key, ctx.data.get(__key));
127
+ }
128
+ }
129
+ result = Value.Object(__finalResult);
130
+ }
131
+ } else if (__nodeResult.isNull()) {
132
+ // Node returned null (error case) - return null, don't passthrough
133
+ result = Value.Null();
134
+ } else {
135
+ // Non-object result - return as-is
136
+ result = __nodeResult;
137
+ }`;
138
+ }
139
+
140
+ return ` let result = ctx.get("$nodes.${node.name}");`;
141
+ }
142
+
143
+ /**
144
+ * Generate fallback result code when no suitable node is found.
145
+ *
146
+ * @param outputNodeIds - Set of output node IDs
147
+ * @param sanitizeId - Function to sanitize node IDs for code generation
148
+ * @returns AssemblyScript code string
149
+ */
150
+ export function generateFallbackResultCode(
151
+ outputNodeIds: Set<string>,
152
+ sanitizeId: (id: string) => string,
153
+ ): string {
154
+ if (outputNodeIds.size > 0) {
155
+ // Fallback: evaluate output node if no other nodes were evaluated
156
+ const outputNodeId = Array.from(outputNodeIds)[0];
157
+ const sanitizedOutputId = sanitizeId(outputNodeId);
158
+ return ` let result = evaluateNode_${sanitizedOutputId}(ctx);`;
159
+ }
160
+ return ' let result = Value.Null();';
161
+ }
@@ -0,0 +1,26 @@
1
+ // src/compiler/runtime/index.ts
2
+ import { readFileSync } from 'fs';
3
+ import { resolve, dirname } from 'path';
4
+ import { fileURLToPath } from 'url';
5
+
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+
8
+ // Must work in both development (src/compiler/runtime) and installed package (dist/compiler/runtime).
9
+ // Relative path from __dirname traverses up to src/runtime.
10
+ function getAssemblyRuntimePath(): string {
11
+ // From dist/compiler/runtime -> ../../runtime
12
+ return resolve(__dirname, '..', '..', 'runtime');
13
+ }
14
+
15
+ function loadRuntime(filename: string): string {
16
+ const runtimePath = getAssemblyRuntimePath();
17
+ return readFileSync(resolve(runtimePath, filename), 'utf-8');
18
+ }
19
+
20
+ export const RUNTIME_VALUES = loadRuntime('values.ts');
21
+ export const RUNTIME_CONTEXT = loadRuntime('context.ts');
22
+ export const RUNTIME_EXPRESSIONS = loadRuntime('expressions.ts');
23
+ export const RUNTIME_TABLES = loadRuntime('tables.ts');
24
+ export const RUNTIME_MEMORY = loadRuntime('memory.ts');
25
+ export const RUNTIME_STRINGS = loadRuntime('strings.ts');
26
+ export const RUNTIME_ARRAYS = loadRuntime('arrays.ts');