@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,238 @@
1
+ /**
2
+ * WASM Compilation Cache Tests
3
+ */
4
+
5
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
6
+ import {
7
+ computeCacheKey,
8
+ readCacheFromDisk,
9
+ writeCacheToDisk,
10
+ clearCache,
11
+ getCacheStats,
12
+ isCacheEnabled,
13
+ getCacheDirectory,
14
+ getCacheHealth,
15
+ } from '../../../src/compiler/cache';
16
+ import { join } from 'path';
17
+
18
+ describe('WASM Compilation Cache', () => {
19
+ const testCacheDir = join(process.cwd(), 'node_modules', '.cache', 'jdm-asm');
20
+
21
+ beforeEach(() => {
22
+ // Clear cache before each test
23
+ clearCache();
24
+ });
25
+
26
+ describe('computeCacheKey', () => {
27
+ it('should produce consistent hash for same inputs', () => {
28
+ const code = 'export function evaluate(): i32 { return 42; }';
29
+ const options = { optimize: true, debug: false };
30
+
31
+ const key1 = computeCacheKey(code, options);
32
+ const key2 = computeCacheKey(code, options);
33
+
34
+ expect(key1).toBe(key2);
35
+ expect(key1.length).toBe(32); // 128-bit hex
36
+ });
37
+
38
+ it('should produce different hash for different code', () => {
39
+ const options = { optimize: true, debug: false };
40
+
41
+ const key1 = computeCacheKey('export function a(): i32 { return 1; }', options);
42
+ const key2 = computeCacheKey('export function b(): i32 { return 2; }', options);
43
+
44
+ expect(key1).not.toBe(key2);
45
+ });
46
+
47
+ it('should produce different hash for different options', () => {
48
+ const code = 'export function evaluate(): i32 { return 42; }';
49
+
50
+ const key1 = computeCacheKey(code, { optimize: true, debug: false });
51
+ const key2 = computeCacheKey(code, { optimize: false, debug: false });
52
+ const key3 = computeCacheKey(code, { optimize: true, debug: true });
53
+
54
+ expect(key1).not.toBe(key2);
55
+ expect(key1).not.toBe(key3);
56
+ expect(key2).not.toBe(key3);
57
+ });
58
+ });
59
+
60
+ describe('readCacheFromDisk / writeCacheToDisk', () => {
61
+ it('should store and retrieve cache entry', () => {
62
+ const cacheKey = 'test_key_' + Date.now().toString(16);
63
+ const testBinary = new Uint8Array([0x00, 0x61, 0x73, 0x6d]); // WASM magic
64
+ const testWat = '(module)';
65
+
66
+ writeCacheToDisk(cacheKey, { binary: testBinary, wat: testWat });
67
+
68
+ const result = readCacheFromDisk(cacheKey);
69
+ expect(result).not.toBeNull();
70
+ expect(result!.binary).toEqual(testBinary);
71
+ expect(result!.wat).toBe(testWat);
72
+ });
73
+ });
74
+
75
+ describe('getCacheStats', () => {
76
+ it('should count cache entries', () => {
77
+ const binary = new Uint8Array([0x00, 0x61, 0x73, 0x6d]);
78
+
79
+ writeCacheToDisk('test_key_1', { binary, wat: '(module)' });
80
+ writeCacheToDisk('test_key_2', { binary, wat: '(module)' });
81
+
82
+ const stats = getCacheStats();
83
+ expect(stats.entries).toBe(2);
84
+ expect(stats.totalSize).toBeGreaterThan(0);
85
+ });
86
+ });
87
+
88
+ describe('clearCache', () => {
89
+ it('should remove all cache entries', () => {
90
+ const binary = new Uint8Array([0x00, 0x61, 0x73, 0x6d]);
91
+
92
+ writeCacheToDisk('test_key_1', { binary, wat: '(module)' });
93
+ writeCacheToDisk('test_key_2', { binary, wat: '(module)' });
94
+
95
+ let stats = getCacheStats();
96
+ expect(stats.entries).toBe(2);
97
+
98
+ clearCache();
99
+
100
+ stats = getCacheStats();
101
+ expect(stats.entries).toBe(0);
102
+ });
103
+ });
104
+
105
+ describe('isCacheEnabled', () => {
106
+ it('should be enabled by default', () => {
107
+ const originalEnv = process.env.JDM_ASM_NO_CACHE;
108
+ delete process.env.JDM_ASM_NO_CACHE;
109
+
110
+ expect(isCacheEnabled()).toBe(true);
111
+
112
+ // Restore
113
+ if (originalEnv !== undefined) {
114
+ process.env.JDM_ASM_NO_CACHE = originalEnv;
115
+ }
116
+ });
117
+
118
+ it('should be disabled with JDM_ASM_NO_CACHE=1', () => {
119
+ const originalEnv = process.env.JDM_ASM_NO_CACHE;
120
+ process.env.JDM_ASM_NO_CACHE = '1';
121
+
122
+ expect(isCacheEnabled()).toBe(false);
123
+
124
+ // Restore
125
+ if (originalEnv !== undefined) {
126
+ process.env.JDM_ASM_NO_CACHE = originalEnv;
127
+ } else {
128
+ delete process.env.JDM_ASM_NO_CACHE;
129
+ }
130
+ });
131
+ });
132
+
133
+ describe('getCacheDirectory', () => {
134
+ it('should return cache directory path', () => {
135
+ const dir = getCacheDirectory();
136
+ expect(dir).toBe(testCacheDir);
137
+ expect(dir).toContain('node_modules/.cache/jdm-asm');
138
+ });
139
+ });
140
+
141
+ describe('getCacheHealth', () => {
142
+ it('should report health when cache is enabled and empty', () => {
143
+ const originalEnv = process.env.JDM_ASM_NO_CACHE;
144
+ delete process.env.JDM_ASM_NO_CACHE;
145
+
146
+ const health = getCacheHealth();
147
+
148
+ expect(health.enabled).toBe(true);
149
+ expect(health.directory).toBe(testCacheDir);
150
+ expect(health.stats.entries).toBe(0);
151
+
152
+ // Restore
153
+ if (originalEnv !== undefined) {
154
+ process.env.JDM_ASM_NO_CACHE = originalEnv;
155
+ }
156
+ });
157
+
158
+ it('should report health when cache is disabled', () => {
159
+ const originalEnv = process.env.JDM_ASM_NO_CACHE;
160
+ process.env.JDM_ASM_NO_CACHE = '1';
161
+
162
+ const health = getCacheHealth();
163
+
164
+ expect(health.enabled).toBe(false);
165
+ expect(health.issues).toContain(
166
+ 'Cache is disabled via JDM_ASM_NO_CACHE environment variable',
167
+ );
168
+
169
+ // Restore
170
+ if (originalEnv !== undefined) {
171
+ process.env.JDM_ASM_NO_CACHE = originalEnv;
172
+ } else {
173
+ delete process.env.JDM_ASM_NO_CACHE;
174
+ }
175
+ });
176
+
177
+ it('should report stats when cache has entries', () => {
178
+ const originalEnv = process.env.JDM_ASM_NO_CACHE;
179
+ delete process.env.JDM_ASM_NO_CACHE;
180
+
181
+ const binary = new Uint8Array([0x00, 0x61, 0x73, 0x6d]);
182
+ writeCacheToDisk('test_key_1', { binary, wat: '(module)' });
183
+ writeCacheToDisk('test_key_2', { binary, wat: '(module)' });
184
+
185
+ const health = getCacheHealth();
186
+
187
+ expect(health.enabled).toBe(true);
188
+ expect(health.accessible).toBe(true);
189
+ expect(health.stats.entries).toBe(2);
190
+ expect(health.stats.totalSize).toBeGreaterThan(0);
191
+
192
+ // Restore
193
+ if (originalEnv !== undefined) {
194
+ process.env.JDM_ASM_NO_CACHE = originalEnv;
195
+ }
196
+ });
197
+ });
198
+
199
+ describe('Error Handling', () => {
200
+ it('should handle cache write failures gracefully', () => {
201
+ // Create console.warn spy to verify warning is logged
202
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
203
+
204
+ const binary = new Uint8Array([0x00, 0x61, 0x73, 0x6d]);
205
+
206
+ // Try to write to an invalid path by using a cache key with invalid characters
207
+ // This should not throw but should log a warning
208
+ writeCacheToDisk('/invalid:key*with?bad<chars>', { binary, wat: '(module)' });
209
+
210
+ // Note: On some systems this might actually succeed, so we don't assert on the warning
211
+ // The important part is that it doesn't throw
212
+
213
+ warnSpy.mockRestore();
214
+ });
215
+
216
+ it('should return null when reading non-existent cache file', () => {
217
+ const result = readCacheFromDisk('nonexistent_key_12345');
218
+ expect(result).toBeNull();
219
+ });
220
+
221
+ it('should handle corrupted cache files gracefully', () => {
222
+ const cacheKey = 'test_corrupted_' + Date.now().toString(16);
223
+
224
+ // Write a valid cache entry first
225
+ const binary = new Uint8Array([0x00, 0x61, 0x73, 0x6d]);
226
+ writeCacheToDisk(cacheKey, { binary, wat: '(module)' });
227
+
228
+ // Corrupt the cache file by writing invalid JSON
229
+ const fs = require('fs');
230
+ const cachePath = join(testCacheDir, `${cacheKey}.json`);
231
+ fs.writeFileSync(cachePath, '{ invalid json }', 'utf-8');
232
+
233
+ // Should return null and not throw
234
+ const result = readCacheFromDisk(cacheKey);
235
+ expect(result).toBeNull();
236
+ });
237
+ });
238
+ });
@@ -0,0 +1,316 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ CompilationError,
4
+ ErrorCode,
5
+ type SourceLocation,
6
+ ErrorCollector,
7
+ isCompilationError,
8
+ isStructuralError,
9
+ isFeatureError,
10
+ isExpressionError,
11
+ } from '../../../src/compiler/errors';
12
+
13
+ describe('Error Handling Infrastructure', () => {
14
+ describe('SourceLocation', () => {
15
+ it('should accept minimal location information', () => {
16
+ const location: SourceLocation = { nodeId: 'node-1' };
17
+ expect(location.nodeId).toBe('node-1');
18
+ expect(location.nodeName).toBeUndefined();
19
+ expect(location.line).toBeUndefined();
20
+ });
21
+
22
+ it('should accept complete location information', () => {
23
+ const location: SourceLocation = {
24
+ nodeId: 'node-1',
25
+ nodeName: 'AgeCheck',
26
+ field: 'expression',
27
+ line: 10,
28
+ column: 15,
29
+ };
30
+ expect(location.nodeId).toBe('node-1');
31
+ expect(location.nodeName).toBe('AgeCheck');
32
+ expect(location.field).toBe('expression');
33
+ expect(location.line).toBe(10);
34
+ expect(location.column).toBe(15);
35
+ });
36
+ });
37
+
38
+ describe('ErrorCode', () => {
39
+ it('should have all structural error codes', () => {
40
+ expect(ErrorCode.INVALID_JSON).toBe('INVALID_JSON');
41
+ expect(ErrorCode.MISSING_INPUT_NODE).toBe('MISSING_INPUT_NODE');
42
+ expect(ErrorCode.MISSING_OUTPUT_NODE).toBe('MISSING_OUTPUT_NODE');
43
+ expect(ErrorCode.MULTIPLE_INPUT_NODES).toBe('MULTIPLE_INPUT_NODES');
44
+ expect(ErrorCode.CYCLE_DETECTED).toBe('CYCLE_DETECTED');
45
+ expect(ErrorCode.INVALID_EDGE).toBe('INVALID_EDGE');
46
+ });
47
+
48
+ it('should have all feature error codes', () => {
49
+ expect(ErrorCode.UNSUPPORTED_FUNCTION_NODE).toBe('UNSUPPORTED_FUNCTION_NODE');
50
+ expect(ErrorCode.UNSUPPORTED_EXPRESSION).toBe('UNSUPPORTED_EXPRESSION');
51
+ });
52
+
53
+ it('should have all expression error codes', () => {
54
+ expect(ErrorCode.PARSE_ERROR).toBe('PARSE_ERROR');
55
+ expect(ErrorCode.UNKNOWN_FUNCTION).toBe('UNKNOWN_FUNCTION');
56
+ expect(ErrorCode.TYPE_MISMATCH).toBe('TYPE_MISMATCH');
57
+ expect(ErrorCode.UNKNOWN_FIELD).toBe('UNKNOWN_FIELD');
58
+ });
59
+
60
+ it('should have all schema error codes', () => {
61
+ expect(ErrorCode.SCHEMA_MISMATCH).toBe('SCHEMA_MISMATCH');
62
+ expect(ErrorCode.INVALID_SCHEMA).toBe('INVALID_SCHEMA');
63
+ });
64
+ });
65
+
66
+ describe('CompilationError', () => {
67
+ it('should create error with mandatory fields', () => {
68
+ const error = new CompilationError('Test error', ErrorCode.PARSE_ERROR);
69
+ expect(error.message).toBe('Test error');
70
+ expect(error.code).toBe(ErrorCode.PARSE_ERROR);
71
+ expect(error.name).toBe('CompilationError');
72
+ expect(error.location).toBeUndefined();
73
+ expect(error.context).toBeUndefined();
74
+ });
75
+
76
+ it('should create error with location', () => {
77
+ const location: SourceLocation = { nodeName: 'MyNode', line: 10, column: 5 };
78
+ const error = new CompilationError('Test error', ErrorCode.UNKNOWN_FIELD, location);
79
+ expect(error.message).toBe('Test error');
80
+ expect(error.code).toBe(ErrorCode.UNKNOWN_FIELD);
81
+ expect(error.location).toEqual(location);
82
+ });
83
+
84
+ it('should create error with context', () => {
85
+ const context = { variable: 'age', expectedType: 'number', actualType: 'string' };
86
+ const error = new CompilationError(
87
+ 'Type mismatch',
88
+ ErrorCode.TYPE_MISMATCH,
89
+ undefined,
90
+ context,
91
+ );
92
+ expect(error.context).toEqual(context);
93
+ });
94
+
95
+ it('should create error with both location and context', () => {
96
+ const location: SourceLocation = { nodeName: 'MyNode', field: 'expression' };
97
+ const context = { expression: 'age + "hello"' };
98
+ const error = new CompilationError('Type error', ErrorCode.TYPE_MISMATCH, location, context);
99
+ expect(error.location).toEqual(location);
100
+ expect(error.context).toEqual(context);
101
+ });
102
+
103
+ it('should format message without location', () => {
104
+ const error = new CompilationError('Test error', ErrorCode.PARSE_ERROR);
105
+ expect(error.getFormattedMessage()).toBe('[PARSE_ERROR] Test error');
106
+ });
107
+
108
+ it('should format message with nodeName', () => {
109
+ const location: SourceLocation = { nodeName: 'AgeCheck' };
110
+ const error = new CompilationError('Test error', ErrorCode.PARSE_ERROR, location);
111
+ expect(error.getFormattedMessage()).toBe('[AgeCheck] [PARSE_ERROR] Test error');
112
+ });
113
+
114
+ it('should format message with nodeId', () => {
115
+ const location: SourceLocation = { nodeId: 'node-123' };
116
+ const error = new CompilationError('Test error', ErrorCode.PARSE_ERROR, location);
117
+ expect(error.getFormattedMessage()).toBe('[(id: node-123)] [PARSE_ERROR] Test error');
118
+ });
119
+
120
+ it('should format message with field', () => {
121
+ const location: SourceLocation = { nodeName: 'MyNode', field: 'condition' };
122
+ const error = new CompilationError('Test error', ErrorCode.PARSE_ERROR, location);
123
+ expect(error.getFormattedMessage()).toBe('[MyNode .condition] [PARSE_ERROR] Test error');
124
+ });
125
+
126
+ it('should format message with line and column', () => {
127
+ const location: SourceLocation = { line: 10, column: 5 };
128
+ const error = new CompilationError('Test error', ErrorCode.PARSE_ERROR, location);
129
+ expect(error.getFormattedMessage()).toBe('[@10:5] [PARSE_ERROR] Test error');
130
+ });
131
+
132
+ it('should format message with all location fields', () => {
133
+ const location: SourceLocation = {
134
+ nodeId: 'node-1',
135
+ nodeName: 'MyNode',
136
+ field: 'expression',
137
+ line: 10,
138
+ column: 5,
139
+ };
140
+ const error = new CompilationError('Test error', ErrorCode.PARSE_ERROR, location);
141
+ expect(error.getFormattedMessage()).toBe(
142
+ '[MyNode (id: node-1) .expression @10:5] [PARSE_ERROR] Test error',
143
+ );
144
+ });
145
+ });
146
+
147
+ describe('ErrorCollector', () => {
148
+ it('should start with no errors', () => {
149
+ const collector = new ErrorCollector();
150
+ expect(collector.hasErrors()).toBe(false);
151
+ });
152
+
153
+ it('should add single error', () => {
154
+ const collector = new ErrorCollector();
155
+ const error = new CompilationError('Test error', ErrorCode.PARSE_ERROR);
156
+ collector.add(error);
157
+
158
+ expect(collector.hasErrors()).toBe(true);
159
+ });
160
+
161
+ it('should add multiple errors', () => {
162
+ const collector = new ErrorCollector();
163
+ const error1 = new CompilationError('Error 1', ErrorCode.UNKNOWN_FIELD);
164
+ const error2 = new CompilationError('Error 2', ErrorCode.TYPE_MISMATCH);
165
+ const error3 = new CompilationError('Error 3', ErrorCode.UNKNOWN_FUNCTION);
166
+
167
+ collector.add(error1);
168
+ collector.add(error2);
169
+ collector.add(error3);
170
+
171
+ expect(collector.hasErrors()).toBe(true);
172
+ });
173
+
174
+ it('should not throw when throwIfErrors called with no errors', () => {
175
+ const collector = new ErrorCollector();
176
+ expect(() => collector.throwIfErrors()).not.toThrow();
177
+ });
178
+
179
+ it('should throw single error directly', () => {
180
+ const collector = new ErrorCollector();
181
+ const error = new CompilationError('Single error', ErrorCode.PARSE_ERROR);
182
+ collector.add(error);
183
+
184
+ expect(() => collector.throwIfErrors()).toThrow('Single error');
185
+ });
186
+
187
+ it('should throw aggregated error for multiple errors', () => {
188
+ const collector = new ErrorCollector();
189
+ collector.add(new CompilationError('Error 1', ErrorCode.UNKNOWN_FIELD));
190
+ collector.add(new CompilationError('Error 2', ErrorCode.TYPE_MISMATCH));
191
+
192
+ expect(() => collector.throwIfErrors()).toThrow('2 compilation errors');
193
+ });
194
+
195
+ it('should include all errors in aggregated message', () => {
196
+ const collector = new ErrorCollector();
197
+ collector.add(new CompilationError('First error', ErrorCode.UNKNOWN_FIELD));
198
+ collector.add(new CompilationError('Second error', ErrorCode.TYPE_MISMATCH));
199
+ collector.add(new CompilationError('Third error', ErrorCode.UNKNOWN_FUNCTION));
200
+
201
+ expect(() => collector.throwIfErrors()).toThrow();
202
+ try {
203
+ collector.throwIfErrors();
204
+ } catch (e) {
205
+ if (e instanceof CompilationError) {
206
+ expect(e.message).toContain('3 compilation errors');
207
+ expect(e.message).toContain('1. UNKNOWN_FIELD: First error');
208
+ expect(e.message).toContain('2. TYPE_MISMATCH: Second error');
209
+ expect(e.message).toContain('3. UNKNOWN_FUNCTION: Third error');
210
+ }
211
+ }
212
+ });
213
+ });
214
+
215
+ describe('isCompilationError', () => {
216
+ it('should return true for CompilationError instance', () => {
217
+ const error = new CompilationError('Test', ErrorCode.PARSE_ERROR);
218
+ expect(isCompilationError(error)).toBe(true);
219
+ });
220
+
221
+ it('should return false for regular Error', () => {
222
+ const error = new Error('Test');
223
+ expect(isCompilationError(error)).toBe(false);
224
+ });
225
+ });
226
+
227
+ describe('isStructuralError', () => {
228
+ it('should return true for structural error codes', () => {
229
+ expect(isStructuralError(ErrorCode.INVALID_JSON)).toBe(true);
230
+ expect(isStructuralError(ErrorCode.MISSING_INPUT_NODE)).toBe(true);
231
+ expect(isStructuralError(ErrorCode.MISSING_OUTPUT_NODE)).toBe(true);
232
+ expect(isStructuralError(ErrorCode.MULTIPLE_INPUT_NODES)).toBe(true);
233
+ expect(isStructuralError(ErrorCode.CYCLE_DETECTED)).toBe(true);
234
+ expect(isStructuralError(ErrorCode.INVALID_EDGE)).toBe(true);
235
+ });
236
+
237
+ it('should return false for non-structural error codes', () => {
238
+ expect(isStructuralError(ErrorCode.PARSE_ERROR)).toBe(false);
239
+ expect(isStructuralError(ErrorCode.UNKNOWN_FUNCTION)).toBe(false);
240
+ expect(isStructuralError(ErrorCode.TYPE_MISMATCH)).toBe(false);
241
+ expect(isStructuralError(ErrorCode.UNKNOWN_FIELD)).toBe(false);
242
+ expect(isStructuralError(ErrorCode.UNSUPPORTED_FUNCTION_NODE)).toBe(false);
243
+ expect(isStructuralError(ErrorCode.SCHEMA_MISMATCH)).toBe(false);
244
+ });
245
+ });
246
+
247
+ describe('isFeatureError', () => {
248
+ it('should return true for feature error codes', () => {
249
+ expect(isFeatureError(ErrorCode.UNSUPPORTED_FUNCTION_NODE)).toBe(true);
250
+ expect(isFeatureError(ErrorCode.UNSUPPORTED_EXPRESSION)).toBe(true);
251
+ });
252
+
253
+ it('should return false for non-feature error codes', () => {
254
+ expect(isFeatureError(ErrorCode.PARSE_ERROR)).toBe(false);
255
+ expect(isFeatureError(ErrorCode.INVALID_JSON)).toBe(false);
256
+ expect(isFeatureError(ErrorCode.SCHEMA_MISMATCH)).toBe(false);
257
+ });
258
+ });
259
+
260
+ describe('isExpressionError', () => {
261
+ it('should return true for expression error codes', () => {
262
+ expect(isExpressionError(ErrorCode.PARSE_ERROR)).toBe(true);
263
+ expect(isExpressionError(ErrorCode.UNKNOWN_FUNCTION)).toBe(true);
264
+ expect(isExpressionError(ErrorCode.TYPE_MISMATCH)).toBe(true);
265
+ expect(isExpressionError(ErrorCode.UNKNOWN_FIELD)).toBe(true);
266
+ });
267
+
268
+ it('should return false for non-expression error codes', () => {
269
+ expect(isExpressionError(ErrorCode.INVALID_JSON)).toBe(false);
270
+ expect(isExpressionError(ErrorCode.CYCLE_DETECTED)).toBe(false);
271
+ expect(isExpressionError(ErrorCode.UNSUPPORTED_FUNCTION_NODE)).toBe(false);
272
+ expect(isExpressionError(ErrorCode.SCHEMA_MISMATCH)).toBe(false);
273
+ });
274
+ });
275
+
276
+ describe('Integration: ErrorCollector workflow', () => {
277
+ it('should support typical expression parsing workflow', () => {
278
+ const collector = new ErrorCollector();
279
+
280
+ // Simulate collecting errors during parsing
281
+ collector.add(new CompilationError('Unknown variable', ErrorCode.UNKNOWN_FIELD));
282
+ collector.add(new CompilationError('Type mismatch', ErrorCode.TYPE_MISMATCH));
283
+
284
+ // Check if any errors were collected
285
+ expect(collector.hasErrors()).toBe(true);
286
+
287
+ // Throw all errors at once
288
+ expect(() => collector.throwIfErrors()).toThrow();
289
+ try {
290
+ collector.throwIfErrors();
291
+ } catch (e) {
292
+ expect(isCompilationError(e)).toBe(true);
293
+ if (e instanceof CompilationError) {
294
+ expect(e.message).toContain('2 compilation errors');
295
+ }
296
+ }
297
+ });
298
+
299
+ it('should support batched validation then clean throw', () => {
300
+ const collector = new ErrorCollector();
301
+
302
+ const location1: SourceLocation = { nodeName: 'Node1', field: 'expression' };
303
+ const location2: SourceLocation = { nodeName: 'Node2', field: 'expression' };
304
+
305
+ collector.add(new CompilationError('Invalid syntax', ErrorCode.PARSE_ERROR, location1));
306
+ collector.add(
307
+ new CompilationError('Unknown function', ErrorCode.UNKNOWN_FUNCTION, location2),
308
+ );
309
+
310
+ expect(collector.hasErrors()).toBe(true);
311
+
312
+ // Should throw with aggregated message
313
+ expect(() => collector.throwIfErrors()).toThrow('2 compilation errors');
314
+ });
315
+ });
316
+ });