@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
package/README.md ADDED
@@ -0,0 +1,769 @@
1
+ # jdm-asm
2
+
3
+ A high-performance JDM (JSON Decision Model) compiler that transforms decision models into WebAssembly modules using AssemblyScript. Compatible with [GoRules zen-engine](https://github.com/gorules/zen) JDM format with **sub-10 microsecond** decision latency and **5-9x faster** execution than zen-engine.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Overview](#overview)
8
+ - [Installation](#installation)
9
+ - [Quick Start](#quick-start)
10
+ - [Usage Guide](#usage-guide)
11
+ - [Defining Schemas](#defining-schemas)
12
+ - [Creating JDM Files](#creating-jdm-files)
13
+ - [Compiling Decisions](#compiling-decisions)
14
+ - [Executing Decisions](#executing-decisions)
15
+ - [Configuration Options](#configuration-options)
16
+ - [JDM Format Reference](#jdm-format-reference)
17
+ - [Node Types](#node-types)
18
+ - [Expression Language](#expression-language)
19
+ - [Built-in Functions](#built-in-functions)
20
+ - [Decision Table Hit Policies](#decision-table-hit-policies)
21
+ - [Architecture](#architecture)
22
+ - [Compile Phase vs Execution Phase](#compile-phase-vs-execution-phase)
23
+ - [Component Overview](#component-overview)
24
+ - [Data Marshaling](#data-marshaling)
25
+ - [Performance](#performance)
26
+ - [Benchmark Results](#benchmark-results)
27
+ - [When to Use jdm-asm](#when-to-use-jdm-asm)
28
+ - [Compatibility with zen-engine](#compatibility-with-zen-engine)
29
+ - [Development](#development)
30
+ - [License](#license)
31
+
32
+ ## Overview
33
+
34
+ jdm-asm compiles JSON Decision Models (JDM) into optimized WebAssembly modules. This approach moves expensive parsing and interpretation to compile-time, resulting in significantly faster runtime execution compared to traditional JavaScript rule engines.
35
+
36
+ **Key Features:**
37
+
38
+ - **Ultra-Low Latency**: 3.5-7 microsecond execution for typical decisions in single-threaded mode
39
+ - **High Performance**: 5-9x faster than zen-engine across all scenarios
40
+ - **Type Safety**: TypeBox schemas for input/output validation
41
+ - **zen-engine Compatible**: Drop-in replacement for most JDM files
42
+ - **Extended Hit Policies**: Supports DMN-standard policies (unique, ruleOrder, outputOrder, priority)
43
+ - **Multi-threaded**: Worker pool support for high-throughput batch processing
44
+
45
+ ## Installation
46
+
47
+ ```bash
48
+ npm install jdm-asm
49
+ ```
50
+
51
+ **Requirements:**
52
+ - Node.js 18+
53
+ - TypeScript 5.0+ (for TypeBox schemas)
54
+
55
+ ## Quick Start
56
+
57
+ ```typescript
58
+ import { Type } from '@sinclair/typebox';
59
+ import { compile, createCompiledDecision } from 'jdm-asm';
60
+
61
+ // 1. Define input/output schemas
62
+ const InputSchema = Type.Object({
63
+ customerType: Type.String(),
64
+ orderAmount: Type.Number(),
65
+ });
66
+
67
+ const OutputSchema = Type.Object({
68
+ discount: Type.Number(),
69
+ });
70
+
71
+ // 2. Define your decision model (or load from file)
72
+ const jdm = {
73
+ nodes: [
74
+ { id: 'input', type: 'inputNode', name: 'Request', position: { x: 0, y: 0 } },
75
+ {
76
+ id: 'table',
77
+ type: 'decisionTableNode',
78
+ name: 'Discount Rules',
79
+ position: { x: 200, y: 0 },
80
+ content: {
81
+ hitPolicy: 'first',
82
+ inputs: [
83
+ { id: 'in1', name: 'Customer', field: 'customerType' },
84
+ { id: 'in2', name: 'Amount', field: 'orderAmount' },
85
+ ],
86
+ outputs: [{ id: 'out1', name: 'Discount', field: 'discount' }],
87
+ rules: [
88
+ { _id: 'r1', in1: '"premium"', in2: '> 100', out1: '0.15' },
89
+ { _id: 'r2', in1: '"standard"', in2: '> 100', out1: '0.10' },
90
+ { _id: 'r3', in1: '', in2: '', out1: '0' },
91
+ ],
92
+ },
93
+ },
94
+ { id: 'output', type: 'outputNode', name: 'Response', position: { x: 400, y: 0 } },
95
+ ],
96
+ edges: [
97
+ { id: 'e1', sourceId: 'input', targetId: 'table', type: 'edge' },
98
+ { id: 'e2', sourceId: 'table', targetId: 'output', type: 'edge' },
99
+ ],
100
+ };
101
+
102
+ // 3. Compile to WebAssembly
103
+ const compiled = await compile({
104
+ jdm,
105
+ inputSchema: InputSchema,
106
+ outputSchema: OutputSchema,
107
+ });
108
+
109
+ // 4. Create decision instance
110
+ const decision = await createCompiledDecision(compiled);
111
+
112
+ // 5. Evaluate
113
+ const result = await decision.evaluate({
114
+ customerType: 'premium',
115
+ orderAmount: 150,
116
+ });
117
+
118
+ console.log(result); // { discount: 0.15 }
119
+
120
+ // 6. Clean up when done
121
+ decision.dispose();
122
+ ```
123
+
124
+ ## Usage Guide
125
+
126
+ ### Defining Schemas
127
+
128
+ jdm-asm uses [TypeBox](https://github.com/sinclairzx81/typebox) schemas to define the structure of input and output data. Schemas enable:
129
+
130
+ - Compile-time type checking
131
+ - Runtime input validation
132
+ - Optimized memory layout for WASM
133
+
134
+ ```typescript
135
+ import { Type } from '@sinclair/typebox';
136
+
137
+ // Simple flat schema
138
+ const InputSchema = Type.Object({
139
+ age: Type.Number(),
140
+ name: Type.String(),
141
+ active: Type.Boolean(),
142
+ });
143
+
144
+ // Nested schema
145
+ const InputSchema = Type.Object({
146
+ customer: Type.Object({
147
+ id: Type.String(),
148
+ tier: Type.String(),
149
+ loyaltyYears: Type.Number(),
150
+ }),
151
+ order: Type.Object({
152
+ total: Type.Number(),
153
+ items: Type.Array(Type.Object({
154
+ sku: Type.String(),
155
+ price: Type.Number(),
156
+ quantity: Type.Number(),
157
+ })),
158
+ }),
159
+ });
160
+
161
+ // Output schema
162
+ const OutputSchema = Type.Object({
163
+ eligible: Type.Boolean(),
164
+ discount: Type.Number(),
165
+ message: Type.String(),
166
+ });
167
+ ```
168
+
169
+ ### Creating JDM Files
170
+
171
+ JDM files are JSON documents containing nodes and edges that form a decision graph:
172
+
173
+ ```json
174
+ {
175
+ "nodes": [
176
+ {
177
+ "id": "unique-node-id",
178
+ "type": "inputNode|outputNode|expressionNode|decisionTableNode|switchNode|decisionNode",
179
+ "name": "Human-readable name",
180
+ "position": { "x": 0, "y": 0 },
181
+ "content": { }
182
+ }
183
+ ],
184
+ "edges": [
185
+ {
186
+ "id": "unique-edge-id",
187
+ "type": "edge",
188
+ "sourceId": "source-node-id",
189
+ "targetId": "target-node-id"
190
+ }
191
+ ]
192
+ }
193
+ ```
194
+
195
+ Every JDM must have:
196
+ - Exactly one `inputNode` (entry point)
197
+ - At least one `outputNode` (exit point)
198
+ - A connected path from input to output
199
+
200
+ ### Compiling Decisions
201
+
202
+ The `compile()` function transforms JDM into WebAssembly:
203
+
204
+ ```typescript
205
+ import { compile } from 'jdm-asm';
206
+
207
+ const result = await compile({
208
+ // Required
209
+ jdm: jdmObject, // JDM as object or JSON string
210
+ inputSchema: InputSchema, // TypeBox schema
211
+ outputSchema: OutputSchema,
212
+
213
+ // Optional
214
+ optimize: true, // Enable WASM optimizations (default: true)
215
+ debug: false, // Include AS source and WAT in output
216
+ noMatchBehavior: { // When no rules match:
217
+ type: 'returnNull' // 'returnNull' | 'throwError' | 'returnDefault'
218
+ },
219
+ loadDecision: (key) => {}, // Custom loader for sub-decisions
220
+ });
221
+ ```
222
+
223
+ **Compilation Result:**
224
+
225
+ ```typescript
226
+ interface CompilationResult {
227
+ wasm: Uint8Array; // Compiled WASM binary
228
+ schemaHash: bigint; // Hash for runtime validation
229
+ marshalCode: string; // JS code for data marshaling
230
+ validationCode: string; // JS code for input validation
231
+ wat?: string; // WAT text format (debug mode)
232
+ assemblyScript?: string; // Generated AS source (debug mode)
233
+ }
234
+ ```
235
+
236
+ ### Executing Decisions
237
+
238
+ Use `createCompiledDecision()` to instantiate and execute compiled decisions:
239
+
240
+ ```typescript
241
+ import { createCompiledDecision } from 'jdm-asm';
242
+
243
+ // Create instance (instantiates WASM module)
244
+ const decision = await createCompiledDecision(compiledResult);
245
+
246
+ // Evaluate with input data
247
+ const output = await decision.evaluate({
248
+ customerType: 'premium',
249
+ orderAmount: 150,
250
+ });
251
+
252
+ // Reuse for multiple evaluations (recommended for performance)
253
+ for (const input of inputs) {
254
+ const result = await decision.evaluate(input);
255
+ processResult(result);
256
+ }
257
+
258
+ // Release resources when done
259
+ decision.dispose();
260
+ ```
261
+
262
+ **CompiledDecision API:**
263
+
264
+ ```typescript
265
+ class CompiledDecision {
266
+ // Evaluate with input
267
+ evaluate<I, O>(input: I): Promise<O>;
268
+
269
+ // Get WASM memory (debugging)
270
+ getMemory(): WebAssembly.Memory | null;
271
+
272
+ // Memory statistics
273
+ getMemoryStats(): { current: number; maximum: number; used: number };
274
+
275
+ // Release resources
276
+ dispose(): void;
277
+ }
278
+ ```
279
+
280
+ ### Configuration Options
281
+
282
+ #### No-Match Behavior
283
+
284
+ Configure what happens when no rules match:
285
+
286
+ ```typescript
287
+ // Return null (default)
288
+ { type: 'returnNull' }
289
+
290
+ // Set error code and return null
291
+ { type: 'throwError' }
292
+
293
+ // Return a specific default value
294
+ { type: 'returnDefault', value: { discount: 0, message: 'No match' } }
295
+ ```
296
+
297
+ Can be set globally via compile options or per-node in the JDM content.
298
+
299
+ #### Compilation Cache
300
+
301
+ jdm-asm caches WASM compilations to disk for faster subsequent builds:
302
+
303
+ ```typescript
304
+ import {
305
+ clearCache,
306
+ getCacheStats,
307
+ pruneCache,
308
+ getCacheDirectory,
309
+ } from 'jdm-asm';
310
+
311
+ // Clear all cached compilations
312
+ clearCache();
313
+
314
+ // Get cache statistics
315
+ const stats = getCacheStats();
316
+
317
+ // Remove old entries
318
+ pruneCache();
319
+ ```
320
+
321
+ ## JDM Format Reference
322
+
323
+ ### Node Types
324
+
325
+ #### Input Node
326
+
327
+ Entry point for the decision graph.
328
+
329
+ ```json
330
+ {
331
+ "id": "input-1",
332
+ "type": "inputNode",
333
+ "name": "Request"
334
+ }
335
+ ```
336
+
337
+ #### Output Node
338
+
339
+ Exit point that returns accumulated context data.
340
+
341
+ ```json
342
+ {
343
+ "id": "output-1",
344
+ "type": "outputNode",
345
+ "name": "Response"
346
+ }
347
+ ```
348
+
349
+ #### Expression Node
350
+
351
+ Evaluates expressions and sets output fields.
352
+
353
+ ```json
354
+ {
355
+ "id": "expr-1",
356
+ "type": "expressionNode",
357
+ "name": "Calculate",
358
+ "content": {
359
+ "expressions": [
360
+ { "id": "e1", "key": "total", "value": "price * quantity" },
361
+ { "id": "e2", "key": "tax", "value": "total * 0.08" },
362
+ { "id": "e3", "key": "grandTotal", "value": "$.total + $.tax" }
363
+ ],
364
+ "passThrough": true, // Include input fields in output
365
+ "inputField": "order", // Scope to nested field
366
+ "outputPath": "result" // Store results under this key
367
+ }
368
+ }
369
+ ```
370
+
371
+ **Self-Referential Expressions:** Use `$` to reference earlier computed values within the same expression node (e.g., `$.total` refers to the `total` computed above).
372
+
373
+ #### Decision Table Node
374
+
375
+ Rule-based decision table with conditions and outputs.
376
+
377
+ ```json
378
+ {
379
+ "id": "table-1",
380
+ "type": "decisionTableNode",
381
+ "name": "Discount Rules",
382
+ "content": {
383
+ "hitPolicy": "first",
384
+ "inputs": [
385
+ { "id": "in1", "name": "Customer Type", "field": "customerType" },
386
+ { "id": "in2", "name": "Order Amount", "field": "orderAmount" }
387
+ ],
388
+ "outputs": [
389
+ { "id": "out1", "name": "Discount", "field": "discount" }
390
+ ],
391
+ "rules": [
392
+ { "_id": "r1", "in1": "\"premium\"", "in2": "> 100", "out1": "0.15" },
393
+ { "_id": "r2", "in1": "\"standard\"", "in2": "> 100", "out1": "0.10" },
394
+ { "_id": "r3", "in1": "", "in2": "", "out1": "0" }
395
+ ],
396
+ "passThrough": false
397
+ }
398
+ }
399
+ ```
400
+
401
+ **Unary Mode:** In decision table cells, expressions are implicitly compared against the column's input value (`$`):
402
+
403
+ | Cell Value | Interpreted As |
404
+ |------------|----------------|
405
+ | `"admin"` | `$ == "admin"` |
406
+ | `> 100` | `$ > 100` |
407
+ | `>= 18, < 65` | `$ >= 18 and $ < 65` |
408
+ | `[1..10]` | `$ >= 1 and $ <= 10` |
409
+ | `"a", "b", "c"` | `$ == "a" or $ == "b" or $ == "c"` |
410
+ | `["gold", "platinum"]` | `$ in ["gold", "platinum"]` |
411
+ | `` (empty) or `-` | `true` (always matches) |
412
+
413
+ #### Switch Node
414
+
415
+ Conditional branching based on expressions.
416
+
417
+ ```json
418
+ {
419
+ "id": "switch-1",
420
+ "type": "switchNode",
421
+ "name": "Route",
422
+ "content": {
423
+ "statements": [
424
+ { "id": "s1", "condition": "status == 'active'" },
425
+ { "id": "s2", "condition": "status == 'pending'" },
426
+ { "id": "s3", "condition": "" }
427
+ ],
428
+ "hitPolicy": "first"
429
+ }
430
+ }
431
+ ```
432
+
433
+ Edges from switch nodes use `sourceHandle` to specify which branch they belong to (matching the statement `id`).
434
+
435
+ #### Decision Node
436
+
437
+ References external sub-decisions for modular composition.
438
+
439
+ ```json
440
+ {
441
+ "id": "sub-1",
442
+ "type": "decisionNode",
443
+ "name": "Calculate Shipping",
444
+ "content": {
445
+ "key": "shipping-rules.json"
446
+ }
447
+ }
448
+ ```
449
+
450
+ The `loadDecision` option in compile controls how sub-decisions are loaded.
451
+
452
+ ### Expression Language
453
+
454
+ jdm-asm supports the ZEN expression language:
455
+
456
+ #### Literals
457
+
458
+ ```
459
+ 42, 3.14, -5 // Numbers
460
+ "hello", 'world' // Strings
461
+ true, false // Booleans
462
+ null // Null
463
+ [1, 2, 3] // Arrays
464
+ {key: value} // Objects
465
+ ```
466
+
467
+ #### Operators
468
+
469
+ | Category | Operators |
470
+ |----------|-----------|
471
+ | Arithmetic | `+`, `-`, `*`, `/`, `%`, `^` (power) |
472
+ | Comparison | `==`, `!=`, `<`, `>`, `<=`, `>=` |
473
+ | Logical | `and`, `or`, `not` |
474
+ | Null coalescing | `??` |
475
+ | Membership | `in`, `not in` |
476
+ | Ternary | `condition ? then : else` |
477
+
478
+ #### Access Patterns
479
+
480
+ ```
481
+ object.property // Member access
482
+ object["key"] // Bracket access
483
+ array[0] // Index access
484
+ nested.deeply.nested.value // Chained access
485
+ ```
486
+
487
+ #### Template Literals
488
+
489
+ ```
490
+ `Hello, ${name}!`
491
+ `Order ${id}: ${items.length} items totaling ${total}`
492
+ ```
493
+
494
+ #### Interval Notation (DMN-style)
495
+
496
+ ```
497
+ [1..10] // 1 <= x <= 10 (inclusive)
498
+ (1..10) // 1 < x < 10 (exclusive)
499
+ [1..10) // 1 <= x < 10
500
+ (1..10] // 1 < x <= 10
501
+ ```
502
+
503
+ ### Built-in Functions
504
+
505
+ #### Array Functions
506
+
507
+ | Function | Description | Example |
508
+ |----------|-------------|---------|
509
+ | `sum(array)` | Sum numeric values | `sum([1, 2, 3])` → `6` |
510
+ | `avg(array)` | Average of values | `avg([1, 2, 3])` → `2` |
511
+ | `min(array)` | Minimum value | `min([3, 1, 2])` → `1` |
512
+ | `max(array)` | Maximum value | `max([3, 1, 2])` → `3` |
513
+ | `count(array)` | Array length | `count([1, 2, 3])` → `3` |
514
+ | `sort(array)` | Sort ascending | `sort([3, 1, 2])` → `[1, 2, 3]` |
515
+ | `flat(array, depth?)` | Flatten nested arrays | `flat([[1], [2, 3]])` → `[1, 2, 3]` |
516
+ | `contains(array, val)` | Check membership | `contains([1, 2], 2)` → `true` |
517
+
518
+ #### Higher-Order Functions
519
+
520
+ | Function | Description | Example |
521
+ |----------|-------------|---------|
522
+ | `filter(array, predicate)` | Filter elements | `filter(items, # > 5)` |
523
+ | `map(array, transform)` | Transform elements | `map(items, # * 2)` |
524
+ | `reduce(array, expr, init)` | Reduce to value | `reduce(nums, acc + #, 0)` |
525
+ | `all(array, predicate)` | All match | `all(scores, # >= 60)` |
526
+ | `some(array, predicate)` | Any match | `some(items, # == "gold")` |
527
+
528
+ **Note:** Use `#` to reference the current array element in predicates.
529
+
530
+ #### String Functions
531
+
532
+ | Function | Description | Example |
533
+ |----------|-------------|---------|
534
+ | `upper(str)` | Uppercase | `upper("hello")` → `"HELLO"` |
535
+ | `lower(str)` | Lowercase | `lower("HELLO")` → `"hello"` |
536
+ | `trim(str)` | Remove whitespace | `trim(" hi ")` → `"hi"` |
537
+ | `substring(str, start, end?)` | Extract substring | `substring("hello", 0, 2)` → `"he"` |
538
+ | `indexOf(str, search)` | Find index | `indexOf("hello", "l")` → `2` |
539
+ | `startsWith(str, prefix)` | Check prefix | `startsWith("hello", "he")` → `true` |
540
+ | `endsWith(str, suffix)` | Check suffix | `endsWith("hello", "lo")` → `true` |
541
+ | `split(str, delim)` | Split to array | `split("a,b,c", ",")` → `["a", "b", "c"]` |
542
+ | `join(array, delim)` | Join to string | `join(["a", "b"], "-")` → `"a-b"` |
543
+ | `replace(str, find, repl)` | Replace first | `replace("hello", "l", "L")` → `"heLlo"` |
544
+ | `replaceAll(str, find, repl)` | Replace all | `replaceAll("hello", "l", "L")` → `"heLLo"` |
545
+ | `contains(str, substr)` | Check substring | `contains("hello", "ell")` → `true` |
546
+
547
+ #### Math Functions
548
+
549
+ | Function | Description | Example |
550
+ |----------|-------------|---------|
551
+ | `abs(num)` | Absolute value | `abs(-5)` → `5` |
552
+ | `floor(num)` | Round down | `floor(3.7)` → `3` |
553
+ | `ceil(num)` | Round up | `ceil(3.2)` → `4` |
554
+ | `round(num)` | Round nearest | `round(3.5)` → `4` |
555
+
556
+ #### Date/Time Functions
557
+
558
+ | Function | Description | Example |
559
+ |----------|-------------|---------|
560
+ | `date(str)` | Parse ISO date to timestamp (seconds) | `date("2025-03-20T10:30:00Z")` |
561
+ | `date("now")` | Current timestamp | `date("now")` |
562
+ | `time(str)` | Parse time to seconds since midnight | `time("10:30:00")` → `37800` |
563
+ | `duration(str)` | Parse duration string | `duration("24h")` → `86400` |
564
+
565
+ #### Type Functions
566
+
567
+ | Function | Description | Example |
568
+ |----------|-------------|---------|
569
+ | `number(str)` | Parse to number | `number("42")` → `42` |
570
+ | `string(val)` | Convert to string | `string(42)` → `"42"` |
571
+ | `keys(obj)` | Get object keys | `keys({a: 1})` → `["a"]` |
572
+ | `values(obj)` | Get object values | `values({a: 1})` → `[1]` |
573
+
574
+ ### Decision Table Hit Policies
575
+
576
+ | Policy | Behavior | zen-engine |
577
+ |--------|----------|------------|
578
+ | `first` | Return first matching rule | Yes |
579
+ | `collect` | Return all matches as array | Yes |
580
+ | `unique` | Return single match (error if multiple) | **No** |
581
+ | `ruleOrder` | Return all matches in rule definition order | **No** |
582
+ | `outputOrder` | Return all matches sorted by output value | **No** |
583
+ | `priority` | Return highest priority match | **No** |
584
+
585
+ ## Architecture
586
+
587
+ ### Compile Phase vs Execution Phase
588
+
589
+ jdm-asm operates in two distinct phases:
590
+
591
+ **Compile Phase (~250ms-10s depending on complexity/hardware):**
592
+ 1. Parse JDM JSON and validate structure
593
+ 2. Build dependency graph from nodes/edges
594
+ 3. Topologically sort for evaluation order
595
+ 4. Generate AssemblyScript code for each node
596
+ 5. Compile AssemblyScript to WebAssembly
597
+ 6. Generate JavaScript marshaling code
598
+
599
+ **Execution Phase (~3-1000 microseconds):**
600
+ 1. Validate input against schema
601
+ 2. Marshal JavaScript object to WASM linear memory
602
+ 3. Call WASM `evaluate()` function
603
+ 4. Unmarshal result from WASM memory to JavaScript
604
+
605
+ This separation enables high performance: expensive compilation happens once, while fast execution occurs many times.
606
+
607
+ ### Data Marshaling
608
+
609
+ Data flows between JavaScript and WASM via typed memory:
610
+
611
+ ```
612
+ JavaScript WASM Linear Memory
613
+ ────────── ──────────────────
614
+ { name: "John", ──► [ValueMap]
615
+ age: 30, ├─ length: 2
616
+ tags: ["a","b"] } ├─ key0 → "name" (UTF-16)
617
+ ├─ val0 → [STRING, ptr → "John"]
618
+ ├─ key1 → "age"
619
+ ├─ val1 → [FLOAT, 30.0]
620
+ ├─ key2 → "tags"
621
+ └─ val2 → [ARRAY, ptr → [...]]
622
+ ```
623
+
624
+ **Value Types (tagged union):**
625
+
626
+ | Tag | Type | Storage |
627
+ |-----|------|---------|
628
+ | 0 | Null | Tag only |
629
+ | 1 | Boolean | Tag + u8 |
630
+ | 2 | Integer | Tag + i64 |
631
+ | 3 | Float | Tag + f64 |
632
+ | 4 | String | Tag + pointer to UTF-16 data |
633
+ | 5 | Array | Tag + pointer to element array |
634
+ | 6 | Object | Tag + pointer to ValueMap |
635
+
636
+ ## Performance
637
+
638
+ ### Benchmark Results
639
+
640
+ Benchmarks run on Apple M3 Max, Node.js 24.7, comparing jdm-asm to @gorules/zen-engine:
641
+
642
+ #### Single-Threaded Latency (Best-Case)
643
+
644
+ In single-threaded mode, jdm-asm achieves **microsecond-level** latency:
645
+
646
+ | Scenario | jdm-asm | zen-engine | Speedup |
647
+ |----------|---------|------------|---------|
648
+ | Simple (5 rules) | **3.5 µs** | 32.4 µs | **9.2x faster** |
649
+ | Moderate (12 rules) | **7.2 µs** | 36.2 µs | **5.0x faster** |
650
+ | Complex (~8000 rules) | **492 µs** | 1.47 ms | **3x faster** |
651
+
652
+ For typical decision tables (5-50 rules), expect **sub-10 microsecond** execution times.
653
+
654
+ #### Single-Threaded Latency Percentiles
655
+
656
+ | Scenario | p50 | p95 | p99 |
657
+ |----------|-----|-----|-----|
658
+ | Simple | 3.5 µs | 4.2 µs | 4.7 µs |
659
+ | Moderate | 7.2 µs | 8.0 µs | 9.7 µs |
660
+ | Complex | 492 µs | 1.1 ms | 1.6 ms |
661
+
662
+ #### Throughput (decisions/second)
663
+
664
+ | Mode | Scenario | zen-engine | jdm-asm |
665
+ |------|----------|------------|---------|
666
+ | Single-threaded | Simple | 34.6K | **277.6K** |
667
+ | Single-threaded | Moderate | 27.6K | **139.1K** |
668
+ | Single-threaded | Complex | 682 | **892** |
669
+ | Multi-thread (16) | Simple | 119K | **180K** |
670
+ | Multi-thread (16) | Moderate | 98K | **178K** |
671
+ | Multi-thread (16) | Complex | 5.6K | **20.6K** |
672
+
673
+ #### Multi-Threaded Batch Latency
674
+
675
+ When using worker threads (includes IPC overhead):
676
+
677
+ | Scenario | jdm-asm (16 threads) | zen-engine |
678
+ |----------|----------------------|------------|
679
+ | Simple | 2.7ms / 4.9ms / 6.7ms | 4.4ms / 6.3ms / 7.5ms |
680
+ | Moderate | 2.7ms / 5.0ms / 5.9ms | 5.3ms / 8.2ms / 8.9ms |
681
+ | Complex | 20.9ms / 38.1ms / 43.9ms | 121.9ms / 159.9ms / 173.8ms |
682
+
683
+ #### Compilation Time
684
+
685
+ | Scenario | WASM Size | Compile Time |
686
+ |----------|-----------|--------------|
687
+ | Simple | 34 KB | 1.4s |
688
+ | Moderate | 55 KB | 0.8s |
689
+ | Complex | 6.1 MB | 9.5s |
690
+
691
+ ### When to Use jdm-asm
692
+
693
+ **Best for:**
694
+ - Ultra-low latency requirements (sub-10 µs for typical decisions)
695
+ - High-throughput APIs evaluating hundreds of thousands of decisions per second
696
+ - Latency-sensitive applications where p99 matters
697
+ - Simple to moderate complexity rules (5-50 rules)
698
+ - Cases where rules change infrequently (amortize compilation cost)
699
+
700
+ **Consider zen-engine when:**
701
+ - Rules change frequently (compilation cost is high)
702
+ - Using function nodes with complex JavaScript logic
703
+ - Quick prototyping without schema definitions
704
+
705
+ ## Compatibility with zen-engine
706
+
707
+ jdm-asm is designed as a drop-in replacement for zen-engine with some differences:
708
+
709
+ **Fully Supported:**
710
+ - All node types (input, output, expression, decision table, switch, decision)
711
+ - Expression language (operators, functions, access patterns)
712
+ - Decision table hit policies: `first`, `collect`
713
+ - Sub-decision composition
714
+
715
+ **Extended Features (not in zen-engine):**
716
+ - DMN-standard hit policies: `unique`, `ruleOrder`, `outputOrder`, `priority`
717
+ - Compile-time optimization
718
+ - Multi-threaded execution
719
+
720
+ **Limitations:**
721
+ - Function nodes: Parsed but not executed (returns placeholder)
722
+ - Division by zero: Returns `null` instead of `Infinity`
723
+ - Full ISO 8601 durations: Simple formats (`24h`, `30d`) work; complex format (`P1Y2M3D`) not supported
724
+
725
+ ## Development
726
+
727
+ ```bash
728
+ # Install dependencies
729
+ npm install
730
+
731
+ # Build TypeScript
732
+ npm run build
733
+
734
+ # Build AssemblyScript runtime
735
+ npm run asbuild
736
+
737
+ # Run tests
738
+ npm run test
739
+
740
+ # Run benchmarks
741
+ npm run bench
742
+
743
+ # Lint code
744
+ npm run lint
745
+
746
+ # Type check
747
+ npx tsc --noEmit
748
+ ```
749
+
750
+ ### Project Structure
751
+
752
+ ```
753
+ jdm-asm/
754
+ ├── src/
755
+ │ ├── compiler/ # TypeScript compiler code
756
+ │ └── runtime/ # AssemblyScript runtime
757
+ ├── tests/
758
+ │ ├── unit/ # Unit tests
759
+ │ ├── integration/ # Integration tests
760
+ │ └── helpers/ # Test utilities
761
+ ├── test-data/ # Ported zen-engine test fixtures
762
+ ├── benchmarks/ # Performance benchmarks
763
+ ├── build/ # Compiled WASM output
764
+ └── dist/ # Built npm package
765
+ ```
766
+
767
+ ## License
768
+
769
+ MIT License - see [LICENSE](LICENSE) for details.