@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,836 @@
1
+ /**
2
+ * Coverage Gap Analysis
3
+ *
4
+ * Analyze zen-engine test coverage and identify gaps
5
+ */
6
+
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+
10
+ export interface FeatureCoverage {
11
+ tested: boolean;
12
+ testCount: number;
13
+ testFiles: string[];
14
+ }
15
+
16
+ export interface BuiltInFunctionCoverage {
17
+ sum: FeatureCoverage;
18
+ min: FeatureCoverage;
19
+ max: FeatureCoverage;
20
+ avg: FeatureCoverage;
21
+ count: FeatureCoverage;
22
+ filter: FeatureCoverage;
23
+ map: FeatureCoverage;
24
+ contains: FeatureCoverage;
25
+ any: FeatureCoverage;
26
+ all: FeatureCoverage;
27
+ not: FeatureCoverage;
28
+ date: FeatureCoverage;
29
+ string: FeatureCoverage;
30
+ number: FeatureCoverage;
31
+ abs: FeatureCoverage;
32
+ ceil: FeatureCoverage;
33
+ floor: FeatureCoverage;
34
+ round: FeatureCoverage;
35
+ }
36
+
37
+ export interface DecisionTableCoverage {
38
+ unary: FeatureCoverage;
39
+ expression: FeatureCoverage;
40
+ hitPolicyFirst: FeatureCoverage;
41
+ hitPolicyCollect: FeatureCoverage;
42
+ hitPolicyUnique: FeatureCoverage;
43
+ hitPolicyPriority: FeatureCoverage;
44
+ hitPolicyAny: FeatureCoverage;
45
+ hitPolicyRuleOrder: FeatureCoverage;
46
+ hitPolicyOutputOrder: FeatureCoverage;
47
+ emptyCells: FeatureCoverage;
48
+ loop: FeatureCoverage;
49
+ passThrough: FeatureCoverage;
50
+ }
51
+
52
+ export interface SwitchNodeCoverage {
53
+ basic: FeatureCoverage;
54
+ collect: FeatureCoverage;
55
+ multipleCases: FeatureCoverage;
56
+ defaultCase: FeatureCoverage;
57
+ }
58
+
59
+ export interface SubDecisionsCoverage {
60
+ nesting: FeatureCoverage;
61
+ recursion: FeatureCoverage;
62
+ crossReferences: FeatureCoverage;
63
+ }
64
+
65
+ export interface CoverageReport {
66
+ arithmetic: FeatureCoverage;
67
+ comparisons: FeatureCoverage;
68
+ logicalOps: FeatureCoverage;
69
+ stringOps: FeatureCoverage;
70
+ arrayAccess: FeatureCoverage;
71
+ objectAccess: FeatureCoverage;
72
+ builtInFuncs: BuiltInFunctionCoverage;
73
+ decisionTable: DecisionTableCoverage;
74
+ switchNode: SwitchNodeCoverage;
75
+ subDecisions: SubDecisionsCoverage;
76
+ existingTests: number;
77
+ gaps: string[];
78
+ coverage: number;
79
+ testFiles: string[];
80
+ }
81
+
82
+ /**
83
+ * Initialize empty feature coverage
84
+ */
85
+ function initFeatureCoverage(): FeatureCoverage {
86
+ return {
87
+ tested: false,
88
+ testCount: 0,
89
+ testFiles: [],
90
+ };
91
+ }
92
+
93
+ /**
94
+ * Initialize built-in function coverage
95
+ */
96
+ function initBuiltInFunctionCoverage(): BuiltInFunctionCoverage {
97
+ const functions = [
98
+ 'sum',
99
+ 'min',
100
+ 'max',
101
+ 'avg',
102
+ 'count',
103
+ 'filter',
104
+ 'map',
105
+ 'contains',
106
+ 'any',
107
+ 'all',
108
+ 'not',
109
+ 'date',
110
+ 'string',
111
+ 'number',
112
+ 'abs',
113
+ 'ceil',
114
+ 'floor',
115
+ 'round',
116
+ ];
117
+ const result: any = {};
118
+ for (const fn of functions) {
119
+ result[fn] = initFeatureCoverage();
120
+ }
121
+ return result as BuiltInFunctionCoverage;
122
+ }
123
+
124
+ /**
125
+ * Initialize decision table coverage
126
+ */
127
+ function initDecisionTableCoverage(): DecisionTableCoverage {
128
+ return {
129
+ unary: initFeatureCoverage(),
130
+ expression: initFeatureCoverage(),
131
+ hitPolicyFirst: initFeatureCoverage(),
132
+ hitPolicyCollect: initFeatureCoverage(),
133
+ hitPolicyUnique: initFeatureCoverage(),
134
+ hitPolicyPriority: initFeatureCoverage(),
135
+ hitPolicyAny: initFeatureCoverage(),
136
+ hitPolicyRuleOrder: initFeatureCoverage(),
137
+ hitPolicyOutputOrder: initFeatureCoverage(),
138
+ emptyCells: initFeatureCoverage(),
139
+ loop: initFeatureCoverage(),
140
+ passThrough: initFeatureCoverage(),
141
+ };
142
+ }
143
+
144
+ /**
145
+ * Initialize switch node coverage
146
+ */
147
+ function initSwitchNodeCoverage(): SwitchNodeCoverage {
148
+ return {
149
+ basic: initFeatureCoverage(),
150
+ collect: initFeatureCoverage(),
151
+ multipleCases: initFeatureCoverage(),
152
+ defaultCase: initFeatureCoverage(),
153
+ };
154
+ }
155
+
156
+ /**
157
+ * Initialize sub-decision coverage
158
+ */
159
+ function initSubDecisionsCoverage(): SubDecisionsCoverage {
160
+ return {
161
+ nesting: initFeatureCoverage(),
162
+ recursion: initFeatureCoverage(),
163
+ crossReferences: initFeatureCoverage(),
164
+ };
165
+ }
166
+
167
+ /**
168
+ * Check if content contains arithmetic operations
169
+ */
170
+ function hasArithmetic(content: string): boolean {
171
+ return /[+\-*/%]/.test(content) && !/\/\/|\/\*/.test(content);
172
+ }
173
+
174
+ /**
175
+ * Check if content contains comparison operations
176
+ */
177
+ function hasComparisons(content: string): boolean {
178
+ return (
179
+ /[=!<>]=?|!=|<>/.test(content) && !/(\/\/|\/\*)|[^=!==<>/]=(!==|<=|>=|=|<|>)/.test(content)
180
+ );
181
+ }
182
+
183
+ /**
184
+ * Check if content contains logical operations
185
+ */
186
+ function hasLogicalOps(content: string): boolean {
187
+ return /\b(and|or|not|xor)\b/i.test(content);
188
+ }
189
+
190
+ /**
191
+ * Check if content contains string operations
192
+ */
193
+ function hasStringOps(content: string): boolean {
194
+ return /["']|string\s*\(|substring\s*\(|concat\s*\(|upper\s*\(|lower\s*\(|trim\s*\(/i.test(
195
+ content,
196
+ );
197
+ }
198
+
199
+ /**
200
+ * Check if content contains array access
201
+ */
202
+ function hasArrayAccess(content: string): boolean {
203
+ return /\w+\[[0-9]+\]|\[[^\]]+\]\.\w+/.test(content);
204
+ }
205
+
206
+ /**
207
+ * Check if content contains object access
208
+ */
209
+ function hasObjectAccess(content: string): boolean {
210
+ return /\.\w+/.test(content) && !/[()[]\]]/.test(content);
211
+ }
212
+
213
+ /**
214
+ * Extract built-in function usage
215
+ */
216
+ function extractBuiltInFunctions(content: string): string[] {
217
+ const functionPattern =
218
+ /\b(sum|min|max|avg|count|filter|map|contains|any|all|not|date|string|number|abs|ceil|floor|round)\s*\(/gi;
219
+ const matches = content.match(functionPattern);
220
+ if (!matches) {
221
+ return [];
222
+ }
223
+
224
+ const functions = matches.map((m) => m.toLowerCase().replace(/\s*\($/, ''));
225
+ return [...new Set(functions)];
226
+ }
227
+
228
+ /**
229
+ * Extract decision table features
230
+ */
231
+ function extractDecisionTableFeatures(node: any): string[] {
232
+ const features: string[] = [];
233
+ const content = node.content;
234
+
235
+ if (!content) {
236
+ return features;
237
+ }
238
+
239
+ // Check hit policy
240
+ if (content.hitPolicy) {
241
+ features.push(
242
+ `hitPolicy${content.hitPolicy.charAt(0).toUpperCase() + content.hitPolicy.slice(1).toLowerCase()}`,
243
+ );
244
+ }
245
+
246
+ // Check input types (unary vs expression)
247
+ if (content.inputs) {
248
+ const expressionInputs = content.inputs.filter((i: any) => i.type === 'expression');
249
+ if (expressionInputs.length > 0 && expressionInputs.length === content.inputs.length) {
250
+ features.push('expression');
251
+ } else if (expressionInputs.length === 0) {
252
+ features.push('unary');
253
+ }
254
+ }
255
+
256
+ // Check for empty cells
257
+ if (content.rules) {
258
+ for (const rule of content.rules) {
259
+ for (const [key, value] of Object.entries(rule)) {
260
+ if (key !== '_id' && (value === '' || value === null || value === undefined)) {
261
+ features.push('emptyCells');
262
+ break;
263
+ }
264
+ }
265
+ }
266
+ }
267
+
268
+ // Check for execution mode
269
+ if (content.executionMode === 'loop') {
270
+ features.push('loop');
271
+ }
272
+
273
+ // Check for pass through
274
+ if (content.passThrough) {
275
+ features.push('passThrough');
276
+ }
277
+
278
+ return features;
279
+ }
280
+
281
+ /**
282
+ * Extract switch node features
283
+ */
284
+ function extractSwitchFeatures(node: any): string[] {
285
+ const features: string[] = [];
286
+ const content = node.content;
287
+
288
+ if (!content) {
289
+ return features;
290
+ }
291
+
292
+ // Check for collect property
293
+ if (content.collect) {
294
+ features.push('collect');
295
+ } else {
296
+ features.push('basic');
297
+ }
298
+
299
+ // Check for multiple cases
300
+ if (content.statements && content.statements.length > 2) {
301
+ features.push('multipleCases');
302
+ }
303
+
304
+ // Check for default case (empty condition)
305
+ if (content.statements) {
306
+ const hasDefault = content.statements.some((s: any) => !s.condition || s.condition === '');
307
+ if (hasDefault) {
308
+ features.push('defaultCase');
309
+ }
310
+ }
311
+
312
+ return features;
313
+ }
314
+
315
+ /**
316
+ * Extract sub-decision features
317
+ */
318
+ function extractSubDecisionFeatures(nodes: any[], edges: any[]): string[] {
319
+ const features: string[] = [];
320
+
321
+ const decisionCount = nodes.filter(
322
+ (n: any) => n.type === 'decisionNode' || n.type === 'expressionNode',
323
+ ).length;
324
+
325
+ if (decisionCount > 1) {
326
+ features.push('nesting');
327
+ }
328
+
329
+ // Check for cyclic references (recursion)
330
+ for (const edge of edges) {
331
+ // If there's a back edge from later to earlier in flow, it might be recursion
332
+ const sourceIndex = nodes.findIndex((n: any) => n.id === edge.sourceId);
333
+ const targetIndex = nodes.findIndex((n: any) => n.id === edge.targetId);
334
+ if (sourceIndex > targetIndex && sourceIndex - targetIndex === 1) {
335
+ features.push('recursion');
336
+ }
337
+ }
338
+
339
+ // Check for cross-references
340
+ for (const edge of edges) {
341
+ const source = nodes.find((n: any) => n.id === edge.sourceId);
342
+ const target = nodes.find((n: any) => n.id === edge.targetId);
343
+ if (source && target && source.type === 'decisionNode' && target.type === 'decisionNode') {
344
+ features.push('crossReferences');
345
+ }
346
+ }
347
+
348
+ return features;
349
+ }
350
+
351
+ /**
352
+ * Analyze a single test file
353
+ */
354
+ function analyzeTestFile(filePath: string, coverage: CoverageReport): void {
355
+ try {
356
+ const content = fs.readFileSync(filePath, 'utf-8');
357
+ const jdm = JSON.parse(content);
358
+
359
+ // Track test file
360
+ coverage.testFiles.push(filePath);
361
+
362
+ // Analyze nodes
363
+ for (const node of jdm.nodes || []) {
364
+ const nodeContent = JSON.stringify(node.content || node);
365
+
366
+ // Expression language features
367
+ if (node.type === 'expressionNode' || node.type === 'decisionTableNode') {
368
+ if (hasArithmetic(nodeContent)) {
369
+ coverage.arithmetic.tested = true;
370
+ coverage.arithmetic.testCount++;
371
+ if (!coverage.arithmetic.testFiles.includes(filePath)) {
372
+ coverage.arithmetic.testFiles.push(filePath);
373
+ }
374
+ }
375
+
376
+ if (hasComparisons(nodeContent)) {
377
+ coverage.comparisons.tested = true;
378
+ coverage.comparisons.testCount++;
379
+ if (!coverage.comparisons.testFiles.includes(filePath)) {
380
+ coverage.comparisons.testFiles.push(filePath);
381
+ }
382
+ }
383
+
384
+ if (hasLogicalOps(nodeContent)) {
385
+ coverage.logicalOps.tested = true;
386
+ coverage.logicalOps.testCount++;
387
+ if (!coverage.logicalOps.testFiles.includes(filePath)) {
388
+ coverage.logicalOps.testFiles.push(filePath);
389
+ }
390
+ }
391
+
392
+ if (hasStringOps(nodeContent)) {
393
+ coverage.stringOps.tested = true;
394
+ coverage.stringOps.testCount++;
395
+ if (!coverage.stringOps.testFiles.includes(filePath)) {
396
+ coverage.stringOps.testFiles.push(filePath);
397
+ }
398
+ }
399
+
400
+ if (hasArrayAccess(nodeContent)) {
401
+ coverage.arrayAccess.tested = true;
402
+ coverage.arrayAccess.testCount++;
403
+ if (!coverage.arrayAccess.testFiles.includes(filePath)) {
404
+ coverage.arrayAccess.testFiles.push(filePath);
405
+ }
406
+ }
407
+
408
+ if (hasObjectAccess(nodeContent)) {
409
+ coverage.objectAccess.tested = true;
410
+ coverage.objectAccess.testCount++;
411
+ if (!coverage.objectAccess.testFiles.includes(filePath)) {
412
+ coverage.objectAccess.testFiles.push(filePath);
413
+ }
414
+ }
415
+
416
+ // Built-in functions
417
+ const functions = extractBuiltInFunctions(nodeContent);
418
+ for (const fn of functions) {
419
+ if (coverage.builtInFuncs[fn as keyof BuiltInFunctionCoverage]) {
420
+ const cov = coverage.builtInFuncs[fn as keyof BuiltInFunctionCoverage];
421
+ cov.tested = true;
422
+ cov.testCount++;
423
+ if (!cov.testFiles.includes(filePath)) {
424
+ cov.testFiles.push(filePath);
425
+ }
426
+ }
427
+ }
428
+ }
429
+
430
+ // Decision table features
431
+ if (node.type === 'decisionTableNode') {
432
+ const dtFeatures = extractDecisionTableFeatures(node);
433
+ for (const feature of dtFeatures) {
434
+ if (coverage.decisionTable[feature as keyof DecisionTableCoverage]) {
435
+ const cov = coverage.decisionTable[feature as keyof DecisionTableCoverage];
436
+ cov.tested = true;
437
+ cov.testCount++;
438
+ if (!cov.testFiles.includes(filePath)) {
439
+ cov.testFiles.push(filePath);
440
+ }
441
+ }
442
+ }
443
+ }
444
+
445
+ // Switch node features
446
+ if (node.type === 'switchNode') {
447
+ const swFeatures = extractSwitchFeatures(node);
448
+ for (const feature of swFeatures) {
449
+ if (coverage.switchNode[feature as keyof SwitchNodeCoverage]) {
450
+ const cov = coverage.switchNode[feature as keyof SwitchNodeCoverage];
451
+ cov.tested = true;
452
+ cov.testCount++;
453
+ if (!cov.testFiles.includes(filePath)) {
454
+ cov.testFiles.push(filePath);
455
+ }
456
+ }
457
+ }
458
+ }
459
+ }
460
+
461
+ // Sub-decision features
462
+ const subDecisionFeatures = extractSubDecisionFeatures(jdm.nodes || [], jdm.edges || []);
463
+ for (const feature of subDecisionFeatures) {
464
+ if (coverage.subDecisions[feature as keyof SubDecisionsCoverage]) {
465
+ const cov = coverage.subDecisions[feature as keyof SubDecisionsCoverage];
466
+ cov.tested = true;
467
+ cov.testCount++;
468
+ if (!cov.testFiles.includes(filePath)) {
469
+ cov.testFiles.push(filePath);
470
+ }
471
+ }
472
+ }
473
+ } catch {
474
+ // Silently skip invalid files
475
+ }
476
+ }
477
+
478
+ /**
479
+ * Identify coverage gaps
480
+ */
481
+ function identifyGaps(coverage: CoverageReport): void {
482
+ const gaps: string[] = [];
483
+
484
+ // Expression language features
485
+ if (!coverage.arithmetic.tested) {
486
+ gaps.push('Arithmetic operations (+, -, *, /)');
487
+ }
488
+ if (!coverage.comparisons.tested) {
489
+ gaps.push('Comparison operators (==, !=, <, >, <=, >=)');
490
+ }
491
+ if (!coverage.logicalOps.tested) {
492
+ gaps.push('Logical operations (and, or, not)');
493
+ }
494
+ if (!coverage.stringOps.tested) {
495
+ gaps.push('String operations');
496
+ }
497
+ if (!coverage.arrayAccess.tested) {
498
+ gaps.push('Array access (e.g., items[0])');
499
+ }
500
+ if (!coverage.objectAccess.tested) {
501
+ gaps.push('Object access (e.g., customer.name)');
502
+ }
503
+
504
+ // Built-in functions
505
+ for (const [func, cov] of Object.entries(coverage.builtInFuncs)) {
506
+ if (!cov.tested) {
507
+ gaps.push(`${func}() function`);
508
+ }
509
+ }
510
+
511
+ // Decision table features
512
+ if (!coverage.decisionTable.unary.tested) {
513
+ gaps.push('Decision table unary mode');
514
+ }
515
+ if (!coverage.decisionTable.expression.tested) {
516
+ gaps.push('Decision table expression mode');
517
+ }
518
+ if (!coverage.decisionTable.hitPolicyFirst.tested) {
519
+ gaps.push('Decision table hit policy: FIRST');
520
+ }
521
+ if (!coverage.decisionTable.hitPolicyCollect.tested) {
522
+ gaps.push('Decision table hit policy: COLLECT');
523
+ }
524
+ if (!coverage.decisionTable.hitPolicyUnique.tested) {
525
+ gaps.push('Decision table hit policy: UNIQUE');
526
+ }
527
+ if (!coverage.decisionTable.hitPolicyPriority.tested) {
528
+ gaps.push('Decision table hit policy: PRIORITY');
529
+ }
530
+ if (!coverage.decisionTable.hitPolicyAny.tested) {
531
+ gaps.push('Decision table hit policy: ANY');
532
+ }
533
+ if (!coverage.decisionTable.hitPolicyRuleOrder.tested) {
534
+ gaps.push('Decision table hit policy: RULE ORDER');
535
+ }
536
+ if (!coverage.decisionTable.hitPolicyOutputOrder.tested) {
537
+ gaps.push('Decision table hit policy: OUTPUT ORDER');
538
+ }
539
+ if (!coverage.decisionTable.emptyCells.tested) {
540
+ gaps.push('Decision table empty cells');
541
+ }
542
+ if (!coverage.decisionTable.loop.tested) {
543
+ gaps.push('Decision table loop execution mode');
544
+ }
545
+ if (!coverage.decisionTable.passThrough.tested) {
546
+ gaps.push('Decision table pass through');
547
+ }
548
+
549
+ // Switch node features
550
+ if (!coverage.switchNode.basic.tested) {
551
+ gaps.push('Switch node basic mode');
552
+ }
553
+ if (!coverage.switchNode.collect.tested) {
554
+ gaps.push('Switch node collect mode');
555
+ }
556
+ if (!coverage.switchNode.multipleCases.tested) {
557
+ gaps.push('Switch node multiple cases');
558
+ }
559
+ if (!coverage.switchNode.defaultCase.tested) {
560
+ gaps.push('Switch node default case');
561
+ }
562
+
563
+ // Sub-decision features
564
+ if (!coverage.subDecisions.nesting.tested) {
565
+ gaps.push('Sub-decision nesting');
566
+ }
567
+ if (!coverage.subDecisions.recursion.tested) {
568
+ gaps.push('Sub-decision recursion');
569
+ }
570
+ if (!coverage.subDecisions.crossReferences.tested) {
571
+ gaps.push('Sub-decision cross-references');
572
+ }
573
+
574
+ coverage.gaps = gaps;
575
+ }
576
+
577
+ /**
578
+ * Calculate overall coverage percentage
579
+ */
580
+ function calculateCoverage(coverage: CoverageReport): void {
581
+ let totalFeatures = 0;
582
+ let testedFeatures = 0;
583
+
584
+ // Expression language features
585
+ const expressionFeatures = [
586
+ coverage.arithmetic,
587
+ coverage.comparisons,
588
+ coverage.logicalOps,
589
+ coverage.stringOps,
590
+ coverage.arrayAccess,
591
+ coverage.objectAccess,
592
+ ];
593
+ for (const f of expressionFeatures) {
594
+ totalFeatures++;
595
+ if (f.tested) {
596
+ testedFeatures++;
597
+ }
598
+ }
599
+
600
+ // Built-in functions
601
+ for (const cov of Object.values(coverage.builtInFuncs)) {
602
+ totalFeatures++;
603
+ if (cov.tested) {
604
+ testedFeatures++;
605
+ }
606
+ }
607
+
608
+ // Decision table features
609
+ for (const cov of Object.values(coverage.decisionTable)) {
610
+ totalFeatures++;
611
+ if (cov.tested) {
612
+ testedFeatures++;
613
+ }
614
+ }
615
+
616
+ // Switch node features
617
+ for (const cov of Object.values(coverage.switchNode)) {
618
+ totalFeatures++;
619
+ if (cov.tested) {
620
+ testedFeatures++;
621
+ }
622
+ }
623
+
624
+ // Sub-decision features
625
+ for (const cov of Object.values(coverage.subDecisions)) {
626
+ totalFeatures++;
627
+ if (cov.tested) {
628
+ testedFeatures++;
629
+ }
630
+ }
631
+
632
+ coverage.coverage = totalFeatures > 0 ? testedFeatures / totalFeatures : 0;
633
+ }
634
+
635
+ /**
636
+ * Find all test JSON files recursively
637
+ */
638
+ function findTestFiles(dir: string): string[] {
639
+ const files: string[] = [];
640
+
641
+ function traverse(currentDir: string) {
642
+ const entries = fs.readdirSync(currentDir, { withFileTypes: true });
643
+ for (const entry of entries) {
644
+ if (
645
+ entry.isDirectory() &&
646
+ !entry.name.startsWith('node_modules') &&
647
+ !entry.name.startsWith('.')
648
+ ) {
649
+ traverse(path.join(currentDir, entry.name));
650
+ } else if (entry.isFile() && entry.name.endsWith('.json')) {
651
+ files.push(path.join(currentDir, entry.name));
652
+ }
653
+ }
654
+ }
655
+
656
+ traverse(dir);
657
+ return files;
658
+ }
659
+
660
+ /**
661
+ * Analyze zen-engine test coverage and identify gaps
662
+ */
663
+ export function analyzeCoverage(
664
+ testDataDir: string = path.join(process.cwd(), 'test-data'),
665
+ ): CoverageReport {
666
+ const coverage: CoverageReport = {
667
+ arithmetic: initFeatureCoverage(),
668
+ comparisons: initFeatureCoverage(),
669
+ logicalOps: initFeatureCoverage(),
670
+ stringOps: initFeatureCoverage(),
671
+ arrayAccess: initFeatureCoverage(),
672
+ objectAccess: initFeatureCoverage(),
673
+ builtInFuncs: initBuiltInFunctionCoverage(),
674
+ decisionTable: initDecisionTableCoverage(),
675
+ switchNode: initSwitchNodeCoverage(),
676
+ subDecisions: initSubDecisionsCoverage(),
677
+ existingTests: 0,
678
+ gaps: [],
679
+ coverage: 0,
680
+ testFiles: [],
681
+ };
682
+
683
+ // Find all test JSON files
684
+ const testFiles = findTestFiles(testDataDir);
685
+ coverage.existingTests = testFiles.length;
686
+
687
+ // Analyze each test file
688
+ for (const testFile of testFiles) {
689
+ // Skip node_modules and hidden directories
690
+ if (testFile.includes('node_modules') || testFile.includes('/.')) {
691
+ continue;
692
+ }
693
+ analyzeTestFile(testFile, coverage);
694
+ }
695
+
696
+ // Identify gaps
697
+ identifyGaps(coverage);
698
+
699
+ // Calculate coverage
700
+ calculateCoverage(coverage);
701
+
702
+ return coverage;
703
+ }
704
+
705
+ /**
706
+ * Pretty print coverage report
707
+ */
708
+ export function printCoverageReport(coverage: CoverageReport): void {
709
+ console.log('\n' + '='.repeat(70));
710
+ console.log('COVERAGE GAP ANALYSIS REPORT');
711
+ console.log('='.repeat(70));
712
+ console.log(`\n## Summary`);
713
+ console.log(`- Total test files: ${coverage.existingTests}`);
714
+ console.log(`- Coverage: ${(coverage.coverage * 100).toFixed(1)}%`);
715
+ console.log(`- Gaps found: ${coverage.gaps.length}`);
716
+
717
+ console.log(`\n## Expression Language Features`);
718
+ console.log(
719
+ `- Arithmetic: ${coverage.arithmetic.tested ? '✅' : '❌'} (${coverage.arithmetic.testCount} tests)`,
720
+ );
721
+ console.log(
722
+ `- Comparisons: ${coverage.comparisons.tested ? '✅' : '❌'} (${coverage.comparisons.testCount} tests)`,
723
+ );
724
+ console.log(
725
+ `- Logical ops: ${coverage.logicalOps.tested ? '✅' : '❌'} (${coverage.logicalOps.testCount} tests)`,
726
+ );
727
+ console.log(
728
+ `- String ops: ${coverage.stringOps.tested ? '✅' : '❌'} (${coverage.stringOps.testCount} tests)`,
729
+ );
730
+ console.log(
731
+ `- Array access: ${coverage.arrayAccess.tested ? '✅' : '❌'} (${coverage.arrayAccess.testCount} tests)`,
732
+ );
733
+ console.log(
734
+ `- Object access: ${coverage.objectAccess.tested ? '✅' : '❌'} (${coverage.objectAccess.testCount} tests)`,
735
+ );
736
+
737
+ console.log(`\n## Built-in Functions`);
738
+ for (const [func, cov] of Object.entries(coverage.builtInFuncs)) {
739
+ console.log(`- ${func}(): ${cov.tested ? '✅' : '❌'} (${cov.testCount} tests)`);
740
+ }
741
+
742
+ console.log(`\n## Decision Table Features`);
743
+ console.log(
744
+ `- Unary mode: ${coverage.decisionTable.unary.tested ? '✅' : '❌'} (${coverage.decisionTable.unary.testCount} tests)`,
745
+ );
746
+ console.log(
747
+ `- Expression mode: ${coverage.decisionTable.expression.tested ? '✅' : '❌'} (${coverage.decisionTable.expression.testCount} tests)`,
748
+ );
749
+ console.log(
750
+ `- Hit policy FIRST: ${coverage.decisionTable.hitPolicyFirst.tested ? '✅' : '❌'} (${coverage.decisionTable.hitPolicyFirst.testCount} tests)`,
751
+ );
752
+ console.log(
753
+ `- Hit policy COLLECT: ${coverage.decisionTable.hitPolicyCollect.tested ? '✅' : '❌'} (${coverage.decisionTable.hitPolicyCollect.testCount} tests)`,
754
+ );
755
+ console.log(
756
+ `- Hit policy UNIQUE: ${coverage.decisionTable.hitPolicyUnique.tested ? '✅' : '❌'} (${coverage.decisionTable.hitPolicyUnique.testCount} tests)`,
757
+ );
758
+ console.log(
759
+ `- Hit policy PRIORITY: ${coverage.decisionTable.hitPolicyPriority.tested ? '✅' : '❌'} (${coverage.decisionTable.hitPolicyPriority.testCount} tests)`,
760
+ );
761
+ console.log(
762
+ `- Hit policy ANY: ${coverage.decisionTable.hitPolicyAny.tested ? '✅' : '❌'} (${coverage.decisionTable.hitPolicyAny.testCount} tests)`,
763
+ );
764
+ console.log(
765
+ `- Hit policy RULE ORDER: ${coverage.decisionTable.hitPolicyRuleOrder.tested ? '✅' : '❌'} (${coverage.decisionTable.hitPolicyRuleOrder.testCount} tests)`,
766
+ );
767
+ console.log(
768
+ `- Hit policy OUTPUT ORDER: ${coverage.decisionTable.hitPolicyOutputOrder.tested ? '✅' : '❌'} (${coverage.decisionTable.hitPolicyOutputOrder.testCount} tests)`,
769
+ );
770
+ console.log(
771
+ `- Empty cells: ${coverage.decisionTable.emptyCells.tested ? '✅' : '❌'} (${coverage.decisionTable.emptyCells.testCount} tests)`,
772
+ );
773
+ console.log(
774
+ `- Loop execution: ${coverage.decisionTable.loop.tested ? '✅' : '❌'} (${coverage.decisionTable.loop.testCount} tests)`,
775
+ );
776
+ console.log(
777
+ `- Pass through: ${coverage.decisionTable.passThrough.tested ? '✅' : '❌'} (${coverage.decisionTable.passThrough.testCount} tests)`,
778
+ );
779
+
780
+ console.log(`\n## Switch Node Features`);
781
+ console.log(
782
+ `- Basic mode: ${coverage.switchNode.basic.tested ? '✅' : '❌'} (${coverage.switchNode.basic.testCount} tests)`,
783
+ );
784
+ console.log(
785
+ `- Collect mode: ${coverage.switchNode.collect.tested ? '✅' : '❌'} (${coverage.switchNode.collect.testCount} tests)`,
786
+ );
787
+ console.log(
788
+ `- Multiple cases: ${coverage.switchNode.multipleCases.tested ? '✅' : '❌'} (${coverage.switchNode.multipleCases.testCount} tests)`,
789
+ );
790
+ console.log(
791
+ `- Default case: ${coverage.switchNode.defaultCase.tested ? '✅' : '❌'} (${coverage.switchNode.defaultCase.testCount} tests)`,
792
+ );
793
+
794
+ console.log(`\n## Sub-Decision Features`);
795
+ console.log(
796
+ `- Nesting: ${coverage.subDecisions.nesting.tested ? '✅' : '❌'} (${coverage.subDecisions.nesting.testCount} tests)`,
797
+ );
798
+ console.log(
799
+ `- Recursion: ${coverage.subDecisions.recursion.tested ? '✅' : '❌'} (${coverage.subDecisions.recursion.testCount} tests)`,
800
+ );
801
+ console.log(
802
+ `- Cross references: ${coverage.subDecisions.crossReferences.tested ? '✅' : '❌'} (${coverage.subDecisions.crossReferences.testCount} tests)`,
803
+ );
804
+
805
+ if (coverage.gaps.length > 0) {
806
+ console.log(`\n## Coverage Gaps (${coverage.gaps.length})`);
807
+ for (const gap of coverage.gaps) {
808
+ console.log(`- ${gap}`);
809
+ }
810
+ } else {
811
+ console.log(`\n## Coverage Gaps`);
812
+ console.log('✅ All features covered!');
813
+ }
814
+
815
+ console.log('='.repeat(70));
816
+ }
817
+
818
+ /**
819
+ * CLI entry point - run as: node -e "import('./dist/tests/coverage-analysis.js')
820
+ * .then(async (m) => { const report = m.analyzeCoverage(); m.printCoverageReport(report); })"
821
+ */
822
+ export async function runCLI(testDataPath?: string): Promise<void> {
823
+ const testDataDir = testDataPath || path.join(process.cwd(), 'test-data');
824
+ const report = analyzeCoverage(testDataDir);
825
+ printCoverageReport(report);
826
+ }
827
+
828
+ // For direct execution via Node.js
829
+ if (
830
+ globalThis.__filename?.endsWith('coverage-analysis.ts') &&
831
+ process.argv[1]?.endsWith('coverage-analysis.ts')
832
+ ) {
833
+ const testDataPath = process.argv[2] || path.join(process.cwd(), 'test-data');
834
+ const report = analyzeCoverage(testDataPath);
835
+ printCoverageReport(report);
836
+ }