@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,414 @@
1
+ /**
2
+ * Caches compiled WASM modules keyed by source code + runtime + compiler options.
3
+ * WASM compilation via AssemblyScript is expensive (~250ms per decision), so caching
4
+ * identical compilations significantly improves the speed of iterative development
5
+ * and testing.
6
+ */
7
+
8
+ import { createHash } from 'crypto';
9
+ import {
10
+ existsSync,
11
+ mkdirSync,
12
+ readFileSync,
13
+ writeFileSync,
14
+ readdirSync,
15
+ statSync,
16
+ unlinkSync,
17
+ } from 'fs';
18
+ import { join, dirname } from 'path';
19
+
20
+ // Import runtime source strings to include in cache key
21
+ import {
22
+ RUNTIME_VALUES,
23
+ RUNTIME_CONTEXT,
24
+ RUNTIME_EXPRESSIONS,
25
+ RUNTIME_TABLES,
26
+ RUNTIME_MEMORY,
27
+ RUNTIME_STRINGS,
28
+ RUNTIME_ARRAYS,
29
+ } from './runtime/index';
30
+
31
+ // Package version - included in cache key to invalidate cache across compiler versions
32
+ let packageVersion: string = '';
33
+
34
+ function getPackageVersion(): string {
35
+ if (packageVersion === '') {
36
+ try {
37
+ // Try to find package.json from this file's location
38
+ const packagePath = join(dirname(__dirname), '..', 'package.json');
39
+ const pkg = JSON.parse(readFileSync(packagePath, 'utf-8'));
40
+ packageVersion = pkg.version || 'unknown';
41
+ } catch {
42
+ packageVersion = 'unknown';
43
+ }
44
+ }
45
+ return packageVersion;
46
+ }
47
+
48
+ /**
49
+ * Cache directory location
50
+ */
51
+ function getCacheDir(): string {
52
+ // Use node_modules/.cache/jdm-asm for caching
53
+ // This is a common convention and gets cleaned up with node_modules
54
+ const cacheDir = join(process.cwd(), 'node_modules', '.cache', 'jdm-asm');
55
+ return cacheDir;
56
+ }
57
+
58
+ /**
59
+ * Ensure the cache directory exists
60
+ * @throws Error if directory creation fails
61
+ */
62
+ function ensureCacheDir(): string {
63
+ const cacheDir = getCacheDir();
64
+ if (!existsSync(cacheDir)) {
65
+ try {
66
+ mkdirSync(cacheDir, { recursive: true });
67
+ } catch (error) {
68
+ const errorMsg = error instanceof Error ? error.message : String(error);
69
+ throw new Error(`Failed to create cache directory at ${cacheDir}: ${errorMsg}`);
70
+ }
71
+ }
72
+ return cacheDir;
73
+ }
74
+
75
+ /**
76
+ * Compute a stable hash for cache key.
77
+ */
78
+ export function computeCacheKey(
79
+ assemblyScriptCode: string,
80
+ options: { optimize?: boolean; debug?: boolean },
81
+ ): string {
82
+ const hash = createHash('sha256');
83
+
84
+ // Include package version
85
+ hash.update(`version:${getPackageVersion()}\n`);
86
+
87
+ // Include compiler options
88
+ hash.update(`optimize:${options.optimize ?? true}\n`);
89
+ hash.update(`debug:${options.debug ?? false}\n`);
90
+
91
+ // Include all runtime source files: runtime code changes affect WASM output, so
92
+ // must be part of cache key
93
+ hash.update('---RUNTIME_VALUES---\n');
94
+ hash.update(RUNTIME_VALUES);
95
+ hash.update('---RUNTIME_CONTEXT---\n');
96
+ hash.update(RUNTIME_CONTEXT);
97
+ hash.update('---RUNTIME_EXPRESSIONS---\n');
98
+ hash.update(RUNTIME_EXPRESSIONS);
99
+ hash.update('---RUNTIME_TABLES---\n');
100
+ hash.update(RUNTIME_TABLES);
101
+ hash.update('---RUNTIME_MEMORY---\n');
102
+ hash.update(RUNTIME_MEMORY);
103
+ hash.update('---RUNTIME_STRINGS---\n');
104
+ hash.update(RUNTIME_STRINGS);
105
+ hash.update('---RUNTIME_ARRAYS---\n');
106
+ hash.update(RUNTIME_ARRAYS);
107
+
108
+ // Include the generated AssemblyScript code
109
+ hash.update('---ASSEMBLYSCRIPT---\n');
110
+ hash.update(assemblyScriptCode);
111
+
112
+ // Return first 32 characters of hex digest (128 bits - sufficient for cache key)
113
+ return hash.digest('hex').slice(0, 32);
114
+ }
115
+
116
+ /**
117
+ * Cache entry format
118
+ */
119
+ interface CacheEntry {
120
+ version: string;
121
+ timestamp: number;
122
+ binary: string; // Base64 encoded WASM binary
123
+ wat: string;
124
+ }
125
+
126
+ /**
127
+ * Read cached WASM compilation result from disk if available
128
+ */
129
+ export function readCacheFromDisk(cacheKey: string): { binary: Uint8Array; wat: string } | null {
130
+ const cacheDir = getCacheDir();
131
+ const cachePath = join(cacheDir, `${cacheKey}.json`);
132
+
133
+ if (!existsSync(cachePath)) {
134
+ return null;
135
+ }
136
+
137
+ try {
138
+ const content = readFileSync(cachePath, 'utf-8');
139
+ const entry: CacheEntry = JSON.parse(content);
140
+
141
+ // Version changes invalidate cache to prevent incompatible compiled code from being used
142
+ // when the compiler implementation changes between releases
143
+ if (entry.version !== getPackageVersion()) {
144
+ // Version mismatch, invalidate
145
+ unlinkSync(cachePath);
146
+ return null;
147
+ }
148
+
149
+ // Decode binary from base64
150
+ const binary = new Uint8Array(Buffer.from(entry.binary, 'base64'));
151
+ return { binary, wat: entry.wat };
152
+ } catch (error) {
153
+ // Distinguish between different error types for better diagnostics
154
+ if (error && typeof error === 'object' && 'code' in error) {
155
+ const code = (error as { code: string }).code;
156
+
157
+ // ENOENT (file not found) is benign - cache miss
158
+ if (code === 'ENOENT') {
159
+ return null;
160
+ }
161
+
162
+ // EACCES/EPERM (permission denied) should warn the user
163
+ if (code === 'EACCES' || code === 'EPERM') {
164
+ const errorMsg = error instanceof Error ? error.message : String(error);
165
+ console.warn(
166
+ `[jdm-asm] Warning: Cache file exists but cannot be read due to permissions: ${cachePath}\n${errorMsg}`,
167
+ );
168
+ return null;
169
+ }
170
+ }
171
+
172
+ // Cache corruption or other errors are benign since we can regenerate the result.
173
+ // Failing fast would hurt UX when cache is just a performance optimization, not critical.
174
+ // Try to clean up corrupted cache file
175
+ try {
176
+ unlinkSync(cachePath);
177
+ } catch (cleanupError) {
178
+ // If we can't delete it, just warn (might be permission issue)
179
+ if (cleanupError && typeof cleanupError === 'object' && 'code' in cleanupError) {
180
+ const code = (cleanupError as { code: string }).code;
181
+ if (code === 'EACCES' || code === 'EPERM') {
182
+ console.warn(
183
+ `[jdm-asm] Warning: Cannot clean up corrupted cache file (permission denied): ${cachePath}`,
184
+ );
185
+ }
186
+ }
187
+ }
188
+ return null;
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Write compilation result to disk cache
194
+ * Failures are logged as warnings but do not throw since caching is optional
195
+ */
196
+ export function writeCacheToDisk(
197
+ cacheKey: string,
198
+ result: { binary: Uint8Array; wat: string },
199
+ ): void {
200
+ try {
201
+ const cacheDir = ensureCacheDir();
202
+ const cachePath = join(cacheDir, `${cacheKey}.json`);
203
+
204
+ const entry: CacheEntry = {
205
+ version: getPackageVersion(),
206
+ timestamp: Date.now(),
207
+ binary: Buffer.from(result.binary).toString('base64'),
208
+ wat: result.wat,
209
+ };
210
+
211
+ writeFileSync(cachePath, JSON.stringify(entry));
212
+ } catch (error) {
213
+ // Cache write failures should not break compilation since caching is a performance
214
+ // optimization, not a requirement. Warn the user so they know cache isn't working.
215
+ const errorMsg = error instanceof Error ? error.message : String(error);
216
+
217
+ // Provide more specific guidance for common errors
218
+ if (error && typeof error === 'object' && 'code' in error) {
219
+ const code = (error as { code: string }).code;
220
+
221
+ if (code === 'ENOSPC') {
222
+ console.warn(`[jdm-asm] Warning: Failed to write cache (disk full): ${errorMsg}`);
223
+ } else if (code === 'EACCES' || code === 'EPERM' || code === 'EROFS') {
224
+ console.warn(
225
+ `[jdm-asm] Warning: Failed to write cache (permission denied or read-only filesystem): ${errorMsg}`,
226
+ );
227
+ } else {
228
+ console.warn(`[jdm-asm] Warning: Failed to write cache: ${errorMsg}`);
229
+ }
230
+ } else {
231
+ console.warn(`[jdm-asm] Warning: Failed to write cache: ${errorMsg}`);
232
+ }
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Get the cache directory path
238
+ * Exposes where compiled WASM modules are stored on disk
239
+ */
240
+ export function getCacheDirectory(): string {
241
+ return getCacheDir();
242
+ }
243
+
244
+ /**
245
+ * Get cache health diagnostics
246
+ * Returns information about cache status, any issues, and recent operations
247
+ */
248
+ export function getCacheHealth(): {
249
+ enabled: boolean;
250
+ directory: string;
251
+ directoryExists: boolean;
252
+ accessible: boolean;
253
+ stats: {
254
+ entries: number;
255
+ totalSize: number;
256
+ oldestEntry: number | null;
257
+ newestEntry: number | null;
258
+ };
259
+ issues: string[];
260
+ } {
261
+ const enabled = isCacheEnabled();
262
+ const directory = getCacheDir();
263
+ const directoryExists = existsSync(directory);
264
+ const issues: string[] = [];
265
+
266
+ // Check if cache is disabled
267
+ if (!enabled) {
268
+ issues.push('Cache is disabled via JDM_ASM_NO_CACHE environment variable');
269
+ }
270
+
271
+ // Check if directory exists
272
+ if (enabled && !directoryExists) {
273
+ issues.push('Cache directory does not exist yet (will be created on first write)');
274
+ }
275
+
276
+ // Check if directory is accessible
277
+ let accessible = false;
278
+ if (directoryExists) {
279
+ try {
280
+ // Try to read the directory to check accessibility
281
+ readdirSync(directory);
282
+ accessible = true;
283
+ } catch (error) {
284
+ accessible = false;
285
+ issues.push(
286
+ `Cache directory exists but is not accessible: ${error instanceof Error ? error.message : String(error)}`,
287
+ );
288
+ }
289
+ }
290
+
291
+ // Get cache stats if accessible
292
+ const stats = accessible
293
+ ? getCacheStats()
294
+ : {
295
+ entries: 0,
296
+ totalSize: 0,
297
+ oldestEntry: null,
298
+ newestEntry: null,
299
+ };
300
+
301
+ return {
302
+ enabled,
303
+ directory,
304
+ directoryExists,
305
+ accessible,
306
+ stats,
307
+ issues,
308
+ };
309
+ }
310
+
311
+ /**
312
+ * Clear the entire cache
313
+ */
314
+ export function clearCache(): void {
315
+ const cacheDir = getCacheDir();
316
+ if (!existsSync(cacheDir)) {
317
+ return;
318
+ }
319
+
320
+ const files = readdirSync(cacheDir);
321
+ for (const file of files) {
322
+ if (file.endsWith('.json')) {
323
+ try {
324
+ unlinkSync(join(cacheDir, file));
325
+ } catch {}
326
+ }
327
+ }
328
+ }
329
+
330
+ /**
331
+ * Get cache statistics
332
+ */
333
+ export function getCacheStats(): {
334
+ entries: number;
335
+ totalSize: number;
336
+ oldestEntry: number | null;
337
+ newestEntry: number | null;
338
+ } {
339
+ const cacheDir = getCacheDir();
340
+ if (!existsSync(cacheDir)) {
341
+ return { entries: 0, totalSize: 0, oldestEntry: null, newestEntry: null };
342
+ }
343
+
344
+ const files = readdirSync(cacheDir).filter((f) => f.endsWith('.json'));
345
+ let totalSize = 0;
346
+ let oldestEntry: number | null = null;
347
+ let newestEntry: number | null = null;
348
+
349
+ for (const file of files) {
350
+ const stat = statSync(join(cacheDir, file));
351
+ totalSize += stat.size;
352
+
353
+ const mtime = stat.mtimeMs;
354
+ if (oldestEntry === null || mtime < oldestEntry) {
355
+ oldestEntry = mtime;
356
+ }
357
+ if (newestEntry === null || mtime > newestEntry) {
358
+ newestEntry = mtime;
359
+ }
360
+ }
361
+
362
+ return { entries: files.length, totalSize, oldestEntry, newestEntry };
363
+ }
364
+
365
+ /**
366
+ * Prune old cache entries (keep most recent N entries or entries younger than maxAge)
367
+ */
368
+ export function pruneCache(
369
+ options: {
370
+ maxEntries?: number;
371
+ maxAgeMs?: number;
372
+ } = {},
373
+ ): number {
374
+ const { maxEntries = 100, maxAgeMs = 7 * 24 * 60 * 60 * 1000 } = options; // Default: 100 entries, 7 days
375
+ const cacheDir = getCacheDir();
376
+
377
+ if (!existsSync(cacheDir)) {
378
+ return 0;
379
+ }
380
+
381
+ const files = readdirSync(cacheDir)
382
+ .filter((f) => f.endsWith('.json'))
383
+ .map((f) => {
384
+ const stat = statSync(join(cacheDir, f));
385
+ return { name: f, mtime: stat.mtimeMs };
386
+ })
387
+ .sort((a, b) => b.mtime - a.mtime); // Sort by newest first
388
+
389
+ const now = Date.now();
390
+ let removed = 0;
391
+
392
+ for (let i = 0; i < files.length; i++) {
393
+ const file = files[i];
394
+ const age = now - file.mtime;
395
+
396
+ // Remove if exceeds max entries or max age
397
+ if (i >= maxEntries || age > maxAgeMs) {
398
+ try {
399
+ unlinkSync(join(cacheDir, file.name));
400
+ removed++;
401
+ } catch {}
402
+ }
403
+ }
404
+
405
+ return removed;
406
+ }
407
+
408
+ /**
409
+ * Check if caching is enabled
410
+ * Can be disabled via JDM_ASM_NO_CACHE=1 environment variable
411
+ */
412
+ export function isCacheEnabled(): boolean {
413
+ return process.env.JDM_ASM_NO_CACHE !== '1';
414
+ }
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Code generation helpers for shared AssemblyScript code patterns.
3
+ *
4
+ * These helpers generate AssemblyScript code strings that can be used across
5
+ * different compiler modules to avoid duplication.
6
+ */
7
+
8
+ import { sanitizeId } from './utils';
9
+
10
+ /**
11
+ * Generate AssemblyScript code to assign a value to a nested path in the context.
12
+ *
13
+ * This handles dotted paths like "cart.items.total" by navigating/creating the
14
+ * necessary object hierarchy in the context. The algorithm:
15
+ * 1. Splits the path by "."
16
+ * 2. Gets or creates the root object from context
17
+ * 3. Navigates/creates intermediate objects for each part
18
+ * 4. Sets the final value at the leaf
19
+ *
20
+ * @param path - The dotted path string (e.g., "cart.items.total")
21
+ * @param valueExpr - The AssemblyScript expression for the value to assign
22
+ * @param prefix - Optional prefix for generated variable names to avoid collisions (default: "__np")
23
+ * @returns AssemblyScript code string that performs the nested assignment
24
+ */
25
+ export function generateNestedPathAssignment(
26
+ path: string,
27
+ valueExpr: string,
28
+ prefix: string = '__np',
29
+ ): string {
30
+ return `// Store value at nested path: ${path}
31
+ {
32
+ const ${prefix}_value = ${valueExpr};
33
+ const ${prefix}_parts = "${path}".split(".");
34
+ const ${prefix}_rootKey = ${prefix}_parts[0];
35
+ // Get or create the root object
36
+ let ${prefix}_rootObj: Map<string, Value>;
37
+ if (ctx.data.has(${prefix}_rootKey) && ctx.data.get(${prefix}_rootKey).isObject()) {
38
+ ${prefix}_rootObj = ctx.data.get(${prefix}_rootKey).asObject();
39
+ } else {
40
+ ${prefix}_rootObj = new Map<string, Value>();
41
+ ctx.set(${prefix}_rootKey, Value.Object(${prefix}_rootObj));
42
+ }
43
+ // Navigate/create nested objects for intermediate parts
44
+ let ${prefix}_current = ${prefix}_rootObj;
45
+ for (let ${prefix}_j = 1; ${prefix}_j < ${prefix}_parts.length - 1; ${prefix}_j++) {
46
+ const ${prefix}_part = ${prefix}_parts[${prefix}_j];
47
+ if (${prefix}_current.has(${prefix}_part) && ${prefix}_current.get(${prefix}_part).isObject()) {
48
+ ${prefix}_current = ${prefix}_current.get(${prefix}_part).asObject();
49
+ } else {
50
+ const ${prefix}_newObj = new Map<string, Value>();
51
+ ${prefix}_current.set(${prefix}_part, Value.Object(${prefix}_newObj));
52
+ ${prefix}_current = ${prefix}_newObj;
53
+ }
54
+ }
55
+ // Set the final value at the leaf of the path
56
+ ${prefix}_current.set(${prefix}_parts[${prefix}_parts.length - 1], ${prefix}_value);
57
+ }`;
58
+ }
59
+
60
+ /**
61
+ * Generate AssemblyScript code to build a final result from accumulated context.
62
+ *
63
+ * This extracts all user-facing keys from the context (excluding internal namespaces)
64
+ * and builds a Map suitable for returning as a Value.Object result.
65
+ *
66
+ * The generated code:
67
+ * 1. Creates a new Map for the result
68
+ * 2. Iterates over all keys in ctx.data
69
+ * 3. Filters out internal keys ($*, #, acc)
70
+ * 4. Copies remaining keys to the result map
71
+ *
72
+ * @param resultVarName - The name of the variable to store the result in
73
+ * @param prefix - Optional prefix for loop variables to avoid collisions (default: "__bfr")
74
+ * @returns AssemblyScript code string that builds the result map
75
+ */
76
+ export function generateBuildFinalResultCode(
77
+ resultVarName: string,
78
+ prefix: string = '__bfr',
79
+ ): string {
80
+ return `// Build final result from accumulated context
81
+ let ${resultVarName} = new Map<string, Value>();
82
+ const ${prefix}_keys = ctx.data.keys();
83
+ for (let ${prefix}_i = 0; ${prefix}_i < ${prefix}_keys.length; ${prefix}_i++) {
84
+ const ${prefix}_key = ${prefix}_keys[${prefix}_i];
85
+ // $nodes/$ are internal namespaces
86
+ // # is iteration variable,
87
+ // acc is accumulator
88
+ // None should appear in final output, only actual output field names
89
+ if (!${prefix}_key.startsWith("$") && ${prefix}_key !== "#" && ${prefix}_key !== "acc") {
90
+ ${resultVarName}.set(${prefix}_key, ctx.data.get(${prefix}_key));
91
+ }
92
+ }`;
93
+ }
94
+
95
+ /**
96
+ * Generate AssemblyScript code to evaluate a single node and handle its outputPath and passThrough settings.
97
+ *
98
+ * This is the standard node evaluation pattern used across the codebase. It:
99
+ * 1. Calls the node's evaluateNode function
100
+ * 2. Stores the result in $nodes.<nodeName>
101
+ * 3. Handles outputPath if specified (storing result at the given path)
102
+ * 4. Handles passThrough merge if the node is configured for it
103
+ *
104
+ * @param nodeId - The raw node ID
105
+ * @param nodeName - The name of the node (for context storage)
106
+ * @param node - The JDM node definition (optional, for outputPath/passThrough handling)
107
+ * @returns AssemblyScript code string that evaluates the node
108
+ */
109
+ export function generateNodeEvaluationCode(
110
+ nodeId: string,
111
+ nodeName: string,
112
+ node?: {
113
+ type?: string;
114
+ content?: { outputPath?: string; passThrough?: boolean; outputs?: Array<{ field?: string }> };
115
+ },
116
+ ): string {
117
+ const sanitizedId = sanitizeId(nodeId);
118
+ const statements: string[] = [];
119
+
120
+ // Call the node's evaluateNode function and store result
121
+ statements.push(`ctx.set("$nodes.${nodeName}", evaluateNode_${sanitizedId}(ctx));`);
122
+
123
+ if (!node) {
124
+ return statements.join('\n ');
125
+ }
126
+
127
+ const outputPath = node.content?.outputPath;
128
+ if (outputPath) {
129
+ if (!outputPath.includes('.')) {
130
+ statements.push(`ctx.set("${outputPath}", ctx.get("$nodes.${nodeName}"));`);
131
+ } else {
132
+ statements.push(generateNestedPathAssignment(outputPath, `ctx.get("$nodes.${nodeName}")`));
133
+ }
134
+ }
135
+
136
+ // Determine if we should merge node results into context
137
+ // Expression nodes compute values meant for the output, so their results should flow
138
+ // through to the final result regardless of passThrough setting. Decision tables with
139
+ // dotted output fields (e.g., "flag.turnover") similarly need merging to build nested
140
+ // output structures.
141
+ const hasOutputFields =
142
+ node.type === 'decisionTableNode' &&
143
+ node.content?.outputs?.some((o: { field?: string }) => o.field && o.field.includes('.'));
144
+ const shouldMerge =
145
+ node.type === 'expressionNode' || node.content?.passThrough === true || hasOutputFields;
146
+
147
+ if (shouldMerge) {
148
+ statements.push(generatePassThroughMergeCode(nodeName));
149
+ }
150
+
151
+ return statements.join('\n ');
152
+ }
153
+
154
+ /**
155
+ * Generate AssemblyScript code to merge passThrough node results into the context.
156
+ *
157
+ * This handles both simple keys (e.g., "status") and nested paths (e.g., "evaluation.score").
158
+ * For nested paths, it navigates/creates the necessary object hierarchy in the context.
159
+ *
160
+ * The generated code:
161
+ * 1. Gets the node result from `$nodes.<nodeName>`
162
+ * 2. Iterates over all keys in the result
163
+ * 3. For simple keys, sets them directly in the context
164
+ * 4. For nested paths, navigates/creates intermediate objects and sets the leaf value
165
+ *
166
+ * @param nodeName - The name of the node whose results should be merged
167
+ * @returns AssemblyScript code string that performs the merge
168
+ */
169
+ export function generatePassThroughMergeCode(nodeName: string): string {
170
+ // Generate the nested path assignment code for use inside the loop
171
+ // We use a special prefix "__pt" to avoid collisions with other generated code
172
+ const nestedPathCode = `const __pt_parts = __key.split(".");
173
+ const __pt_rootKey = __pt_parts[0];
174
+ let __pt_rootObj: Map<string, Value>;
175
+ if (ctx.data.has(__pt_rootKey) && ctx.data.get(__pt_rootKey).isObject()) {
176
+ __pt_rootObj = ctx.data.get(__pt_rootKey).asObject();
177
+ } else {
178
+ __pt_rootObj = new Map<string, Value>();
179
+ ctx.set(__pt_rootKey, Value.Object(__pt_rootObj));
180
+ }
181
+ let __pt_current = __pt_rootObj;
182
+ for (let __pt_j = 1; __pt_j < __pt_parts.length - 1; __pt_j++) {
183
+ const __pt_part = __pt_parts[__pt_j];
184
+ if (__pt_current.has(__pt_part) && __pt_current.get(__pt_part).isObject()) {
185
+ __pt_current = __pt_current.get(__pt_part).asObject();
186
+ } else {
187
+ const __pt_newObj = new Map<string, Value>();
188
+ __pt_current.set(__pt_part, Value.Object(__pt_newObj));
189
+ __pt_current = __pt_newObj;
190
+ }
191
+ }
192
+ __pt_current.set(__pt_parts[__pt_parts.length - 1], __value);`;
193
+
194
+ return `// Merge passThrough results for ${nodeName}
195
+ {
196
+ const __nodeResult = ctx.get("$nodes.${nodeName}");
197
+ if (__nodeResult.isObject()) {
198
+ const __resultMap = __nodeResult.asObject();
199
+ const __keys = __resultMap.keys();
200
+ for (let __i = 0; __i < __keys.length; __i++) {
201
+ const __key = __keys[__i];
202
+ const __value = __resultMap.get(__key);
203
+ if (__key.includes(".")) {
204
+ ${nestedPathCode}
205
+ } else {
206
+ ctx.set(__key, __value);
207
+ }
208
+ }
209
+ }
210
+ }`;
211
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Code Generation Module Index
3
+ *
4
+ * This module provides code generation utilities for the JDM compiler,
5
+ * organized by target language and concern:
6
+ *
7
+ * - JavaScript marshaling: Generates JS code for WASM memory serialization/deserialization
8
+ * - JavaScript validation: Generates JS code for input validation against TypeBox schemas
9
+ */
10
+
11
+ // JavaScript marshaling code generation
12
+ export { generateMarshalCode, _generateUnmarshalBody } from './js-marshal';
13
+
14
+ // JavaScript validation code generation
15
+ export { generateValidationCode } from './js-validation';