@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,236 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { parser, lexer } from '../../../src/compiler/expression-parser';
3
+ import { cstToAst } from '../../../src/compiler/cst-visitor';
4
+
5
+ describe('Expression Parser - Logical OR Operator', () => {
6
+ beforeEach(() => {
7
+ // Reset parser state before each test
8
+ parser.reset();
9
+ });
10
+
11
+ /**
12
+ * Note: both `or` keyword and `||` (double pipe) syntax are parsed.
13
+ * zen-engine evaluation only supports `or` keyword, but our compiler
14
+ * supports both forms for compatibility.
15
+ */
16
+
17
+ it('should parse "true" as just a boolean literal', () => {
18
+ const lexingResult = lexer.tokenize('true');
19
+
20
+ if (lexingResult.errors.length > 0) {
21
+ throw new Error(`Lexer error: ${lexingResult.errors.map((e: any) => e.message).join(', ')}`);
22
+ }
23
+
24
+ parser.input = lexingResult.tokens;
25
+ const cst = parser.expression();
26
+
27
+ if (parser.errors.length > 0) {
28
+ throw new Error(`Parse error: ${parser.errors.map((e: any) => e.message).join(', ')}`);
29
+ }
30
+
31
+ const ast = cstToAst(cst);
32
+ expect(ast).toEqual({
33
+ type: 'BooleanLiteral',
34
+ value: true,
35
+ });
36
+ });
37
+
38
+ it('should parse "true or true"', () => {
39
+ const lexingResult = lexer.tokenize('true or true');
40
+
41
+ if (lexingResult.errors.length > 0) {
42
+ throw new Error(`Lexer error: ${lexingResult.errors.map((e: any) => e.message).join(', ')}`);
43
+ }
44
+
45
+ parser.input = lexingResult.tokens;
46
+ const cst = parser.expression();
47
+
48
+ if (parser.errors.length > 0) {
49
+ throw new Error(`Parse error: ${parser.errors.map((e: any) => e.message).join(', ')}`);
50
+ }
51
+
52
+ const ast = cstToAst(cst);
53
+ expect(ast).toEqual({
54
+ type: 'BinaryOp',
55
+ op: 'or',
56
+ left: { type: 'BooleanLiteral', value: true },
57
+ right: { type: 'BooleanLiteral', value: true },
58
+ });
59
+ });
60
+
61
+ it('should parse "true || true"', () => {
62
+ const lexingResult = lexer.tokenize('true || true');
63
+
64
+ if (lexingResult.errors.length > 0) {
65
+ throw new Error(`Lexer error: ${lexingResult.errors.map((e: any) => e.message).join(', ')}`);
66
+ }
67
+
68
+ parser.input = lexingResult.tokens;
69
+ const cst = parser.expression();
70
+
71
+ if (parser.errors.length > 0) {
72
+ throw new Error(`Parse error: ${parser.errors.map((e: any) => e.message).join(', ')}`);
73
+ }
74
+
75
+ const ast = cstToAst(cst);
76
+ expect(ast).toEqual({
77
+ type: 'BinaryOp',
78
+ op: 'or',
79
+ left: { type: 'BooleanLiteral', value: true },
80
+ right: { type: 'BooleanLiteral', value: true },
81
+ });
82
+ });
83
+
84
+ it('should parse "x < 5 or x > 10"', () => {
85
+ const lexingResult = lexer.tokenize('x < 5 or x > 10');
86
+
87
+ if (lexingResult.errors.length > 0) {
88
+ throw new Error(`Lexer error: ${lexingResult.errors.map((e: any) => e.message).join(', ')}`);
89
+ }
90
+
91
+ parser.input = lexingResult.tokens;
92
+ const cst = parser.expression();
93
+
94
+ if (parser.errors.length > 0) {
95
+ throw new Error(`Parse error: ${parser.errors.map((e: any) => e.message).join(', ')}`);
96
+ }
97
+
98
+ const ast = cstToAst(cst);
99
+ expect(ast).toEqual({
100
+ type: 'BinaryOp',
101
+ op: 'or',
102
+ left: {
103
+ type: 'BinaryOp',
104
+ op: '<',
105
+ left: { type: 'Identifier', name: 'x' },
106
+ right: { type: 'NumberLiteral', value: 5 },
107
+ },
108
+ right: {
109
+ type: 'BinaryOp',
110
+ op: '>',
111
+ left: { type: 'Identifier', name: 'x' },
112
+ right: { type: 'NumberLiteral', value: 10 },
113
+ },
114
+ });
115
+ });
116
+
117
+ it('should parse "x < 5 || x > 10"', () => {
118
+ const lexingResult = lexer.tokenize('x < 5 || x > 10');
119
+
120
+ if (lexingResult.errors.length > 0) {
121
+ throw new Error(`Lexer error: ${lexingResult.errors.map((e: any) => e.message).join(', ')}`);
122
+ }
123
+
124
+ parser.input = lexingResult.tokens;
125
+ const cst = parser.expression();
126
+
127
+ if (parser.errors.length > 0) {
128
+ throw new Error(`Parse error: ${parser.errors.map((e: any) => e.message).join(', ')}`);
129
+ }
130
+
131
+ const ast = cstToAst(cst);
132
+ expect(ast).toEqual({
133
+ type: 'BinaryOp',
134
+ op: 'or',
135
+ left: {
136
+ type: 'BinaryOp',
137
+ op: '<',
138
+ left: { type: 'Identifier', name: 'x' },
139
+ right: { type: 'NumberLiteral', value: 5 },
140
+ },
141
+ right: {
142
+ type: 'BinaryOp',
143
+ op: '>',
144
+ left: { type: 'Identifier', name: 'x' },
145
+ right: { type: 'NumberLiteral', value: 10 },
146
+ },
147
+ });
148
+ });
149
+
150
+ it('should parse "false or false or false"', () => {
151
+ const lexingResult = lexer.tokenize('false or false or false');
152
+
153
+ if (lexingResult.errors.length > 0) {
154
+ throw new Error(`Lexer error: ${lexingResult.errors.map((e: any) => e.message).join(', ')}`);
155
+ }
156
+
157
+ parser.input = lexingResult.tokens;
158
+ const cst = parser.expression();
159
+
160
+ if (parser.errors.length > 0) {
161
+ throw new Error(`Parse error: ${parser.errors.map((e: any) => e.message).join(', ')}`);
162
+ }
163
+
164
+ const ast = cstToAst(cst);
165
+ // Multiple ORs are left-associative: (false or false) or false
166
+ expect(ast).toEqual({
167
+ type: 'BinaryOp',
168
+ op: 'or',
169
+ left: {
170
+ type: 'BinaryOp',
171
+ op: 'or',
172
+ left: { type: 'BooleanLiteral', value: false },
173
+ right: { type: 'BooleanLiteral', value: false },
174
+ },
175
+ right: { type: 'BooleanLiteral', value: false },
176
+ });
177
+ });
178
+
179
+ it('should parse "x and y or z" (OR has lower precedence than AND)', () => {
180
+ const lexingResult = lexer.tokenize('x and y or z');
181
+
182
+ if (lexingResult.errors.length > 0) {
183
+ throw new Error(`Lexer error: ${lexingResult.errors.map((e: any) => e.message).join(', ')}`);
184
+ }
185
+
186
+ parser.input = lexingResult.tokens;
187
+ const cst = parser.expression();
188
+
189
+ if (parser.errors.length > 0) {
190
+ throw new Error(`Parse error: ${parser.errors.map((e: any) => e.message).join(', ')}`);
191
+ }
192
+
193
+ const ast = cstToAst(cst);
194
+ // OR has lower precedence, so this is: (x and y) or z
195
+ expect(ast).toEqual({
196
+ type: 'BinaryOp',
197
+ op: 'or',
198
+ left: {
199
+ type: 'BinaryOp',
200
+ op: 'and',
201
+ left: { type: 'Identifier', name: 'x' },
202
+ right: { type: 'Identifier', name: 'y' },
203
+ },
204
+ right: { type: 'Identifier', name: 'z' },
205
+ });
206
+ });
207
+
208
+ it('should parse "x or y and z" (AND has higher precedence than OR)', () => {
209
+ const lexingResult = lexer.tokenize('x or y and z');
210
+
211
+ if (lexingResult.errors.length > 0) {
212
+ throw new Error(`Lexer error: ${lexingResult.errors.map((e: any) => e.message).join(', ')}`);
213
+ }
214
+
215
+ parser.input = lexingResult.tokens;
216
+ const cst = parser.expression();
217
+
218
+ if (parser.errors.length > 0) {
219
+ throw new Error(`Parse error: ${parser.errors.map((e: any) => e.message).join(', ')}`);
220
+ }
221
+
222
+ const ast = cstToAst(cst);
223
+ // AND has higher precedence, so this is: x or (y and z)
224
+ expect(ast).toEqual({
225
+ type: 'BinaryOp',
226
+ op: 'or',
227
+ left: { type: 'Identifier', name: 'x' },
228
+ right: {
229
+ type: 'BinaryOp',
230
+ op: 'and',
231
+ left: { type: 'Identifier', name: 'y' },
232
+ right: { type: 'Identifier', name: 'z' },
233
+ },
234
+ });
235
+ });
236
+ });
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Marshaling Code Generation Tests
3
+ *
4
+ * Tests for the marshaling code generation:
5
+ * - Marshal code generation
6
+ * - Unmarshal code generation
7
+ * - Validation code generation
8
+ *
9
+ * These tests verify that the code generators produce syntactically valid output.
10
+ * The actual marshaling/unmarshaling behavior is tested through integration tests.
11
+ */
12
+
13
+ import { describe, it, expect } from 'vitest';
14
+ import { Type } from '@sinclair/typebox';
15
+ import { generateMarshalCode, generateValidationCode } from '../../../../src/compiler/marshal-gen';
16
+ import { flattenSchema, computeSchemaHash } from '../../../../src/compiler/schema';
17
+
18
+ describe('Marshaling Code Generation', () => {
19
+ describe('generateMarshalCode', () => {
20
+ it('should generate marshal code that is syntactically valid', () => {
21
+ const schema = Type.Object({
22
+ age: Type.Number(),
23
+ name: Type.String(),
24
+ });
25
+
26
+ const layout = flattenSchema(schema);
27
+ const hash = computeSchemaHash(schema, schema);
28
+
29
+ const code = generateMarshalCode(layout, layout, hash);
30
+
31
+ // Verify code is generated
32
+ expect(typeof code).toBe('string');
33
+ expect(code.length).toBeGreaterThan(0);
34
+
35
+ // Verify balanced braces/parens (basic syntax check)
36
+ checkBalancedSyntax(code);
37
+ });
38
+
39
+ it('should generate code with required exports', () => {
40
+ const schema = Type.Object({
41
+ value: Type.Number(),
42
+ });
43
+
44
+ const layout = flattenSchema(schema);
45
+ const hash = computeSchemaHash(schema, schema);
46
+
47
+ const code = generateMarshalCode(layout, layout, hash);
48
+
49
+ // These exports are required for the runtime to function
50
+ expect(code).toMatch(/export function marshalInput/);
51
+ expect(code).toMatch(/export function unmarshalOutput/);
52
+ });
53
+ });
54
+
55
+ describe('generateValidationCode', () => {
56
+ it('should generate validation code that is syntactically valid', () => {
57
+ const schema = Type.Object({
58
+ age: Type.Number(),
59
+ name: Type.String(),
60
+ });
61
+
62
+ const code = generateValidationCode(schema);
63
+
64
+ expect(typeof code).toBe('string');
65
+ expect(code.length).toBeGreaterThan(0);
66
+ checkBalancedSyntax(code);
67
+ });
68
+
69
+ it('should generate code with required exports', () => {
70
+ const schema = Type.Object({ value: Type.Number() });
71
+
72
+ const code = generateValidationCode(schema);
73
+
74
+ // These exports are required for the runtime to function
75
+ expect(code).toMatch(/export function validateInput/);
76
+ expect(code).toMatch(/export class ValidationError/);
77
+ expect(code).toMatch(/export function checkInput/);
78
+ });
79
+ });
80
+ });
81
+
82
+ /**
83
+ * Helper to check if generated code has balanced braces, parens, and brackets
84
+ */
85
+ function checkBalancedSyntax(code: string): void {
86
+ const openBraces = (code.match(/{/g) || []).length;
87
+ const closeBraces = (code.match(/}/g) || []).length;
88
+ expect(openBraces).toBe(closeBraces);
89
+
90
+ const openParens = (code.match(/\(/g) || []).length;
91
+ const closeParens = (code.match(/\)/g) || []).length;
92
+ expect(openParens).toBe(closeParens);
93
+
94
+ const openBrackets = (code.match(/\[/g) || []).length;
95
+ const closeBrackets = (code.match(/\]/g) || []).length;
96
+ expect(openBrackets).toBe(closeBrackets);
97
+ }
@@ -0,0 +1,103 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { compileDecisionTableNode } from '../../../../src/compiler/nodes/decision-table';
3
+ import { NodeType, type JDMNode } from '../../../../src/compiler/parser';
4
+ import { createMockContextWithRealParser } from '../../../helpers';
5
+
6
+ /**
7
+ * Decision Table Node Compilation Tests
8
+ *
9
+ * These tests verify the compiler's validation and error handling for decision table nodes.
10
+ * The actual code generation behavior is tested through integration tests that compile
11
+ * and execute the generated code.
12
+ */
13
+ describe('Decision Table Node Compilation', () => {
14
+ describe('compileDecisionTableNode', () => {
15
+ const createMockContext = createMockContextWithRealParser;
16
+
17
+ it('should generate code for a decision table node', () => {
18
+ const node: JDMNode = {
19
+ id: 'decision-table-1',
20
+ type: NodeType.DECISION_TABLE,
21
+ name: 'Decision Table',
22
+ position: { x: 0, y: 0 },
23
+ content: {
24
+ rules: [{ input1: 'value', output1: 'result' }],
25
+ inputs: [{ id: 'input1', type: 'string', field: 'input' }],
26
+ outputs: [{ id: 'output1', type: 'string', field: 'result' }],
27
+ hitPolicy: 'first',
28
+ },
29
+ };
30
+
31
+ const context = createMockContext();
32
+ const code = compileDecisionTableNode(node, context);
33
+
34
+ expect(typeof code).toBe('string');
35
+ expect(code.length).toBeGreaterThan(0);
36
+ });
37
+
38
+ it('should generate code with different hit policies', () => {
39
+ const policies = ['first', 'collect', 'priority', 'unique'];
40
+
41
+ for (const policy of policies) {
42
+ const node: JDMNode = {
43
+ id: `dt-${policy}`,
44
+ type: NodeType.DECISION_TABLE,
45
+ name: `${policy} Hit Policy`,
46
+ position: { x: 0, y: 0 },
47
+ content: {
48
+ rules: [{ rule1: 'value', output1: 'result1' }],
49
+ inputs: [{ id: 'rule1', type: 'string', field: 'input' }],
50
+ outputs: [{ id: 'output1', type: 'string', field: 'result' }],
51
+ hitPolicy: policy,
52
+ },
53
+ };
54
+
55
+ const context = createMockContext();
56
+ const code = compileDecisionTableNode(node, context);
57
+
58
+ expect(code.length).toBeGreaterThan(0);
59
+ }
60
+ });
61
+
62
+ it('should throw error when PRIORITY is used with no outputs', () => {
63
+ const node: JDMNode = {
64
+ id: 'dt-priority-no-outputs',
65
+ type: NodeType.DECISION_TABLE,
66
+ name: 'Priority No Outputs',
67
+ position: { x: 0, y: 0 },
68
+ content: {
69
+ rules: [{ input1: 'value1' }],
70
+ inputs: [{ id: 'input1', type: 'string', field: 'input' }],
71
+ outputs: [],
72
+ hitPolicy: 'priority',
73
+ },
74
+ };
75
+
76
+ const context = createMockContext();
77
+
78
+ expect(() => compileDecisionTableNode(node, context)).toThrow(
79
+ 'PRIORITY hit policy requires at least one output field',
80
+ );
81
+ });
82
+
83
+ it('should compile successfully when RETURN_DEFAULT is used with a value', () => {
84
+ const node: JDMNode = {
85
+ id: 'dt-no-match-default-with-value',
86
+ type: NodeType.DECISION_TABLE,
87
+ name: 'No Match Default With Value',
88
+ position: { x: 0, y: 0 },
89
+ content: {
90
+ rules: [{ input1: 'value1', output1: '10' }],
91
+ inputs: [{ id: 'input1', type: 'string', field: 'input' }],
92
+ outputs: [{ id: 'output1', type: 'number', field: 'output' }],
93
+ hitPolicy: 'first',
94
+ noMatchBehavior: { type: 'returnDefault', value: 'default-value' },
95
+ },
96
+ };
97
+
98
+ const context = createMockContext();
99
+ const code = compileDecisionTableNode(node, context);
100
+ expect(code).toContain('result.set("output", Value.String("default-value"))');
101
+ });
102
+ });
103
+ });
@@ -0,0 +1,182 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { compileDecisionNode } from '../../../../src/compiler/nodes/decision';
3
+ import type { JDMNode, JDMDecision } from '../../../../src/compiler/parser';
4
+ import { createMockContext } from '../../../helpers';
5
+
6
+ /**
7
+ * Sub-Decision Node Compilation Tests
8
+ *
9
+ * These tests verify the compiler's validation and error handling for sub-decision nodes.
10
+ * The actual code generation behavior is tested through integration tests that compile
11
+ * and execute the generated code.
12
+ */
13
+ describe('Sub-Decision Node Compilation', () => {
14
+ describe('compileDecisionNode', () => {
15
+ const createSubDecision = (): JDMDecision => ({
16
+ nodes: [
17
+ {
18
+ id: 'sub-input',
19
+ type: 'inputNode' as any,
20
+ name: 'Sub Decision Input',
21
+ position: { x: 0, y: 0 },
22
+ },
23
+ {
24
+ id: 'sub-output',
25
+ type: 'outputNode' as any,
26
+ name: 'Sub Decision Output',
27
+ position: { x: 100, y: 0 },
28
+ },
29
+ ],
30
+ edges: [
31
+ {
32
+ id: 'sub-edge',
33
+ type: 'direct',
34
+ sourceId: 'sub-input',
35
+ targetId: 'sub-output',
36
+ },
37
+ ],
38
+ });
39
+
40
+ it('should generate code for a valid sub-decision node', () => {
41
+ const node: JDMNode = {
42
+ id: 'sub-decision-1',
43
+ type: 'decisionNode' as any,
44
+ name: 'Sub Decision',
45
+ position: { x: 0, y: 0 },
46
+ content: { key: '$test.json' },
47
+ };
48
+
49
+ const subDecision = createSubDecision();
50
+ const context = createMockContext();
51
+ context.loadDecision = () => subDecision;
52
+
53
+ const code = compileDecisionNode(node, context);
54
+
55
+ // Verify code is generated (non-empty string)
56
+ expect(typeof code).toBe('string');
57
+ expect(code.length).toBeGreaterThan(0);
58
+ });
59
+
60
+ it('should detect circular dependencies', () => {
61
+ const node: JDMNode = {
62
+ id: 'sub-cycle',
63
+ type: 'decisionNode' as any,
64
+ name: 'Circular Dep',
65
+ position: { x: 0, y: 0 },
66
+ content: { key: '$cycle.json' },
67
+ };
68
+
69
+ const subDecision = createSubDecision();
70
+ const context = createMockContext();
71
+ context.loadDecision = () => subDecision;
72
+
73
+ // Add node to decision path to simulate circular reference
74
+ context.decisionPath.push('sub-cycle');
75
+
76
+ expect(() => compileDecisionNode(node, context)).toThrow('Circular dependency detected');
77
+ });
78
+
79
+ it('should throw an error when node has no content.key', () => {
80
+ const node: JDMNode = {
81
+ id: 'sub-no-key',
82
+ type: 'decisionNode' as any,
83
+ name: 'No Key',
84
+ position: { x: 0, y: 0 },
85
+ // No content.key!
86
+ };
87
+
88
+ const context = createMockContext();
89
+ context.loadDecision = () => createSubDecision();
90
+
91
+ expect(() => compileDecisionNode(node, context)).toThrow('no content.key');
92
+ });
93
+
94
+ it('should throw an error when sub-decision has no input node', () => {
95
+ const node: JDMNode = {
96
+ id: 'sub-no-input',
97
+ type: 'decisionNode' as any,
98
+ name: 'No Input',
99
+ position: { x: 0, y: 0 },
100
+ content: { key: '$no-input.json' },
101
+ };
102
+
103
+ const subDecision: JDMDecision = {
104
+ nodes: [
105
+ {
106
+ id: 'sub-output',
107
+ type: 'outputNode' as any,
108
+ name: 'Output',
109
+ position: { x: 0, y: 0 },
110
+ },
111
+ ],
112
+ edges: [],
113
+ };
114
+
115
+ const context = createMockContext();
116
+ context.loadDecision = () => subDecision;
117
+
118
+ expect(() => compileDecisionNode(node, context)).toThrow('no input node');
119
+ });
120
+
121
+ it('should throw an error when sub-decision has no output nodes', () => {
122
+ const node: JDMNode = {
123
+ id: 'sub-no-output',
124
+ type: 'decisionNode' as any,
125
+ name: 'No Output',
126
+ position: { x: 0, y: 0 },
127
+ content: { key: '$no-output.json' },
128
+ };
129
+
130
+ const subDecision: JDMDecision = {
131
+ nodes: [
132
+ {
133
+ id: 'sub-input',
134
+ type: 'inputNode' as any,
135
+ name: 'Input',
136
+ position: { x: 0, y: 0 },
137
+ },
138
+ ],
139
+ edges: [],
140
+ };
141
+
142
+ const context = createMockContext();
143
+ context.loadDecision = () => subDecision;
144
+
145
+ expect(() => compileDecisionNode(node, context)).toThrow('no output nodes');
146
+ });
147
+
148
+ it('should cache compiled sub-decisions to avoid recompilation', () => {
149
+ const subDecision = createSubDecision();
150
+ const node1: JDMNode = {
151
+ id: 'node1',
152
+ type: 'decisionNode' as any,
153
+ name: 'First Reference',
154
+ position: { x: 0, y: 0 },
155
+ content: { key: '$shared.json' },
156
+ };
157
+ const node2: JDMNode = {
158
+ id: 'node2',
159
+ type: 'decisionNode' as any,
160
+ name: 'Second Reference',
161
+ position: { x: 0, y: 0 },
162
+ content: { key: '$shared.json' },
163
+ };
164
+
165
+ const context = createMockContext();
166
+ context.loadDecision = () => subDecision;
167
+
168
+ // Compile the same sub-decision twice
169
+ const code1 = compileDecisionNode(node1, context);
170
+ const code2 = compileDecisionNode(node2, context);
171
+
172
+ // First compilation should produce code
173
+ expect(code1.length).toBeGreaterThan(0);
174
+
175
+ // Both should produce valid code
176
+ expect(code2.length).toBeGreaterThan(0);
177
+
178
+ // Verify caching occurred (the cache should have an entry)
179
+ expect(context.compiledSubDecisions.size).toBe(1);
180
+ });
181
+ });
182
+ });