@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,999 @@
1
+ /**
2
+ * JavaScript Marshaling Code Generation
3
+ *
4
+ * This module generates JavaScript code for serializing JavaScript objects to
5
+ * WebAssembly memory and deserializing results back. The generated code handles:
6
+ *
7
+ * - Input marshaling: Converting JS objects to WASM memory format
8
+ * - Output unmarshaling: Converting WASM memory back to JS objects
9
+ * - Size calculation: Computing memory requirements for marshaling
10
+ * - Type-tagged value encoding: Writing values with type tags for dynamic typing
11
+ *
12
+ * The generated code operates on DataView for cross-endian compatibility and
13
+ * handles both fixed-size types (numbers, booleans) and variable-length types
14
+ * (strings, arrays, objects).
15
+ */
16
+
17
+ import type { FlattenedLayout } from '../types';
18
+
19
+ /**
20
+ * Generate JavaScript marshaling code.
21
+ *
22
+ * This function generates the JavaScript code that will serialize
23
+ * JavaScript objects to WebAssembly memory and deserialize results back.
24
+ *
25
+ * @param inputLayout - The flattened input schema layout
26
+ * @param outputLayout - The flattened output schema layout
27
+ * @param schemaHash - The schema hash for runtime validation
28
+ * @returns Generated JavaScript marshaling code as a string
29
+ */
30
+ export function generateMarshalCode(
31
+ inputLayout: FlattenedLayout,
32
+ outputLayout: FlattenedLayout,
33
+ schemaHash: bigint,
34
+ ): string {
35
+ const schemaHashHex = `0x${schemaHash.toString(16).padStart(16, '0')}`;
36
+
37
+ // Calculate fixed sizes (sum of all fixed-size fields)
38
+ const inputFixedSize = inputLayout.fields
39
+ .filter((f) => f.size !== -1)
40
+ .reduce((sum, f) => sum + f.size, 0);
41
+ const outputFixedSize = outputLayout.fields
42
+ .filter((f) => f.size !== -1)
43
+ .reduce((sum, f) => sum + f.size, 0);
44
+
45
+ return `
46
+ // Generated marshaling code for schema hash ${schemaHashHex}
47
+ // Input fixed size: ${inputFixedSize} bytes
48
+ // Output fixed size: ${outputFixedSize} bytes
49
+
50
+ // Type tags for marshaling (must match AssemblyScript runtime/Values.ts)
51
+ // All type tags are stored as 4-byte u32
52
+ const TAG_NULL = 0;
53
+ const TAG_BOOLEAN = 1;
54
+ const TAG_INT = 2;
55
+ const TAG_FLOAT = 3;
56
+ const TAG_STRING = 4;
57
+ const TAG_ARRAY = 5;
58
+ const TAG_OBJECT = 6;
59
+
60
+ // Size of type tag in bytes (must match VALUE_TYPE_SIZE in AssemblyScript)
61
+ const TAG_SIZE = 4;
62
+
63
+ const SCHEMA_HASH = ${schemaHashHex}n;
64
+ const INPUT_FIXED_SIZE = ${inputFixedSize};
65
+ const OUTPUT_FIXED_SIZE = ${outputFixedSize};
66
+
67
+ /**
68
+ * Marshal JavaScript input object to WebAssembly memory as a ValueMap.
69
+ *
70
+ * The WASM runtime expects input as a ValueMap: [length: u32][keyPtr1: u32][valuePtr1: u32]...
71
+ * where keys are raw UTF-16 strings and values are tagged Value structures.
72
+ *
73
+ * @param data - The input JavaScript object
74
+ * @param memory - WebAssembly Memory instance
75
+ * @param allocate - Function to allocate memory: (size: number) => number
76
+ * @returns Pointer to marshaled ValueMap in WASM memory
77
+ */
78
+ export function marshalInput(data, memory, allocate) {
79
+ const view = new DataView(memory.buffer);
80
+ const entries = Object.entries(data);
81
+ const length = entries.length;
82
+
83
+ // Calculate total size needed for ValueMap
84
+ // Format: [length: u32][keyPtr1: u32][valuePtr1: u32]...[key data...][value data...]
85
+ let totalSize = 4 + length * 8; // map header + key/value pointer pairs
86
+
87
+ // Calculate size for keys (raw strings) and values (tagged)
88
+ for (let i = 0; i < length; i++) {
89
+ const [key, value] = entries[i];
90
+ // Key: raw UTF-16 string [length: u32][utf16 chars...]
91
+ totalSize += 4 + key.length * 2;
92
+ // Value: tagged value
93
+ totalSize += calculateValueSize(value);
94
+ }
95
+
96
+ // Allocate memory
97
+ const ptr = allocate(totalSize);
98
+
99
+ // Write map length
100
+ view.setUint32(ptr, length, true);
101
+
102
+ // Current offset for variable data (after map structure)
103
+ let currentOffset = ptr + 4 + length * 8;
104
+
105
+ // Write each key/value pair
106
+ let ptrOffset = ptr + 4;
107
+ for (let i = 0; i < length; i++) {
108
+ const [key, value] = entries[i];
109
+
110
+ // Write key as raw string (not tagged): [length: u32][utf16 chars...]
111
+ const keyPtr = currentOffset;
112
+ view.setUint32(keyPtr, key.length, true);
113
+ for (let j = 0; j < key.length; j++) {
114
+ view.setUint16(keyPtr + 4 + j * 2, key.charCodeAt(j), true);
115
+ }
116
+ currentOffset += 4 + key.length * 2;
117
+
118
+ // Write value (tagged)
119
+ const valuePtr = currentOffset;
120
+ currentOffset += writeValue(value, view, valuePtr);
121
+
122
+ // Write pointers to map structure
123
+ view.setUint32(ptrOffset, keyPtr, true);
124
+ view.setUint32(ptrOffset + 4, valuePtr, true);
125
+ ptrOffset += 8;
126
+ }
127
+
128
+ return ptr;
129
+ }
130
+
131
+ /**
132
+ * Unmarshal WebAssembly memory to JavaScript output object.
133
+ * @param ptr - Pointer to output data in WASM memory
134
+ * @param memory - WebAssembly Memory instance
135
+ * @returns The output JavaScript object
136
+ */
137
+ export function unmarshalOutput(ptr, memory) {
138
+ const view = new DataView(memory.buffer);
139
+
140
+ // Output is written using writeValue() which writes a tagged Value
141
+ // Use readValue() to read it back generically
142
+ const output = readValue(view, ptr);
143
+
144
+ // Convert flat dotted keys to nested objects.
145
+ // Decision tables with passThrough emit flat keys like 'features.prioritySupport'
146
+ // which must be restructured into nested objects for JavaScript consumption.
147
+ // e.g., {"features.prioritySupport": true} -> {"features": {"prioritySupport": true}}
148
+ return unflattenObject(output);
149
+ }
150
+
151
+ /**
152
+ * Convert flat dotted keys to nested objects.
153
+ * Recursively processes objects and arrays.
154
+ *
155
+ * @param value - The value to unflatten
156
+ * @returns The unflattened value
157
+ */
158
+ function unflattenObject(value) {
159
+ if (value === null || value === undefined) {
160
+ return value;
161
+ }
162
+
163
+ if (Array.isArray(value)) {
164
+ return value.map(item => unflattenObject(item));
165
+ }
166
+
167
+ if (typeof value !== 'object') {
168
+ return value;
169
+ }
170
+
171
+ const result = {};
172
+
173
+ for (const [key, val] of Object.entries(value)) {
174
+ // Recursively unflatten the value first
175
+ const unflattenedVal = unflattenObject(val);
176
+
177
+ if (key.includes('.')) {
178
+ // Split the key and create nested structure
179
+ const parts = key.split('.');
180
+ let current = result;
181
+
182
+ for (let i = 0; i < parts.length - 1; i++) {
183
+ const part = parts[i];
184
+ if (!(part in current)) {
185
+ current[part] = {};
186
+ } else if (typeof current[part] !== 'object' || current[part] === null) {
187
+ // Conflicts where both 'a' and 'a.b' exist can occur from multiple decision
188
+ // table rules. Nested structure takes precedence to preserve data hierarchy.
189
+ current[part] = {};
190
+ }
191
+ current = current[part];
192
+ }
193
+
194
+ current[parts[parts.length - 1]] = unflattenedVal;
195
+ } else {
196
+ // No dot in key - check if we already have a nested object from a dotted key
197
+ if (key in result && typeof result[key] === 'object' && result[key] !== null && typeof unflattenedVal === 'object' && unflattenedVal !== null) {
198
+ // Merge the objects
199
+ Object.assign(result[key], unflattenedVal);
200
+ } else {
201
+ result[key] = unflattenedVal;
202
+ }
203
+ }
204
+ }
205
+
206
+ return result;
207
+ }
208
+
209
+ /**
210
+ * Calculate the total memory size needed for marshaling the input as a ValueMap.
211
+ *
212
+ * Format: [length: u32][keyPtr1: u32][valuePtr1: u32]...[key data...][value data...]
213
+ */
214
+ function calculateInputSize(data) {
215
+ const entries = Object.entries(data);
216
+ const length = entries.length;
217
+
218
+ // Map header + key/value pointer pairs
219
+ let size = 4 + length * 8;
220
+
221
+ // Add size for keys (raw strings) and values (tagged)
222
+ for (let i = 0; i < length; i++) {
223
+ const [key, value] = entries[i];
224
+ // Key: raw UTF-16 string [length: u32][utf16 chars...]
225
+ size += 4 + key.length * 2;
226
+ // Value: tagged value
227
+ size += calculateValueSize(value);
228
+ }
229
+
230
+ return size;
231
+ }
232
+
233
+ /**
234
+ * Write null value with type tag.
235
+ *
236
+ * Format: [tag: u32]
237
+ *
238
+ * @param view - DataView for writing
239
+ * @param offset - Offset to write at
240
+ * @returns Total bytes written (4 bytes for tag)
241
+ */
242
+ function writeNull(view, offset) {
243
+ // Write tag
244
+ view.setUint32(offset, TAG_NULL, true);
245
+ return TAG_SIZE; // tag only
246
+ }
247
+
248
+ /**
249
+ * Write boolean value with type tag.
250
+ *
251
+ * Format: [tag: u32][value: u8]
252
+ *
253
+ * @param value - The boolean value to write
254
+ * @param view - DataView for writing
255
+ * @param offset - Offset to write at
256
+ * @returns Total bytes written (5 bytes: tag + value)
257
+ */
258
+ function writeBoolean(value, view, offset) {
259
+ // Write tag
260
+ view.setUint32(offset, TAG_BOOLEAN, true);
261
+ // Write boolean value as 1 byte (0 or 1)
262
+ view.setUint8(offset + TAG_SIZE, value ? 1 : 0);
263
+ return TAG_SIZE + 1; // tag + value
264
+ }
265
+
266
+ /**
267
+ * Write float (number) value with type tag.
268
+ *
269
+ * Format: [tag: u32][value: f64]
270
+ *
271
+ * Handles all JavaScript number types including:
272
+ * - Regular numbers (0, -0, integers, floats)
273
+ * - Special values (NaN, Infinity, -Infinity)
274
+ *
275
+ * @param value - The number value to write
276
+ * @param view - DataView for writing
277
+ * @param offset - Offset to write at
278
+ * @returns Total bytes written (12 bytes: 4-byte tag + 8-byte f64)
279
+ */
280
+ function writeFloat(value, view, offset) {
281
+ // Write tag
282
+ view.setUint32(offset, TAG_FLOAT, true);
283
+ // Write number as f64 (little-endian)
284
+ view.setFloat64(offset + TAG_SIZE, value, true);
285
+ return TAG_SIZE + 8; // tag + f64
286
+ }
287
+
288
+ /**
289
+ * Read a float value from memory.
290
+ *
291
+ * Format: [tag: u32][value: f64]
292
+ *
293
+ * @param view - DataView for reading
294
+ * @param offset - Offset to read from
295
+ * @returns The decoded number value (as integer if it's a whole number)
296
+ * @throws {Error} If type tag is not TAG_FLOAT
297
+ */
298
+ function readFloat(view, offset) {
299
+ // Read and verify tag
300
+ const tag = view.getUint32(offset, true);
301
+ if (tag !== TAG_FLOAT) {
302
+ throw new Error(\`Expected float tag (\${TAG_FLOAT}), got \${tag}\`);
303
+ }
304
+ // Read number as f64 (little-endian)
305
+ const value = view.getFloat64(offset + TAG_SIZE, true);
306
+ // Return as integer if it's a whole number (for cleaner JSON output)
307
+ if (Number.isInteger(value)) {
308
+ return value;
309
+ }
310
+ return value;
311
+ }
312
+
313
+ /**
314
+ * Write a UTF-16 string to memory with type tag.
315
+ *
316
+ * Format: [tag: u32][pointer: u32] - pointer points to string data
317
+ * String data format: [length: u32][utf16 code units...]
318
+ *
319
+ * The pointer in the Value structure points immediately after the Value structure
320
+ * itself (at offset + 8), where the string data begins.
321
+ *
322
+ * Uses UTF-16 encoding to match AssemblyScript's native string format.
323
+ *
324
+ * @param str - The string to write
325
+ * @param view - DataView for writing
326
+ * @param offset - Offset to write at
327
+ * @returns Total bytes written (tag + pointer + string data)
328
+ */
329
+ function writeString(str, view, offset) {
330
+ const len = str.length;
331
+ // Write tag
332
+ view.setUint32(offset, TAG_STRING, true);
333
+ // String data starts right after the Value structure (tag + pointer = 8 bytes)
334
+ const stringDataPtr = offset + TAG_SIZE + 4;
335
+ // Write pointer to string data
336
+ view.setUint32(offset + TAG_SIZE, stringDataPtr, true);
337
+ // Write string data: [length: u32][utf16 code units...]
338
+ view.setUint32(stringDataPtr, len, true);
339
+ for (let i = 0; i < len; i++) {
340
+ view.setUint16(stringDataPtr + 4 + i * 2, str.charCodeAt(i), true);
341
+ }
342
+ // Total: tag (4) + pointer (4) + length (4) + utf16 data (len * 2)
343
+ return 8 + 4 + len * 2;
344
+ }
345
+
346
+ /**
347
+ * Read null value with type tag.
348
+ *
349
+ * Format: [tag: u32]
350
+ *
351
+ * @param view - DataView for reading
352
+ * @param offset - Offset to read from
353
+ * @returns null value
354
+ * @throws {Error} If type tag is not TAG_NULL
355
+ */
356
+ function readNull(view, offset) {
357
+ // Read and verify tag
358
+ const tag = view.getUint32(offset, true);
359
+ if (tag !== TAG_NULL) {
360
+ throw new Error(\`Expected null tag (\${TAG_NULL}), got \${tag}\`);
361
+ }
362
+ return null;
363
+ }
364
+
365
+ /**
366
+ * Read boolean value with type tag.
367
+ *
368
+ * Format: [tag: u32][value: u8]
369
+ *
370
+ * @param view - DataView for reading
371
+ * @param offset - Offset to read from
372
+ * @returns The decoded boolean value
373
+ * @throws {Error} If type tag is not TAG_BOOLEAN
374
+ */
375
+ function readBoolean(view, offset) {
376
+ // Read and verify tag
377
+ const tag = view.getUint32(offset, true);
378
+ if (tag !== TAG_BOOLEAN) {
379
+ throw new Error(\`Expected boolean tag (\${TAG_BOOLEAN}), got \${tag}\`);
380
+ }
381
+ // Read boolean value and convert to boolean
382
+ const value = view.getUint8(offset + TAG_SIZE);
383
+ return value !== 0;
384
+ }
385
+
386
+ /**
387
+ * Read an integer value from memory with type tag.
388
+ *
389
+ * Format: [tag: u32][value: i64]
390
+ *
391
+ * @param view - DataView for reading
392
+ * @param offset - Offset to read from
393
+ * @returns The decoded integer value
394
+ * @throws {Error} If type tag is not TAG_INT
395
+ */
396
+ function readInt(view, offset) {
397
+ // Read and verify tag
398
+ const tag = view.getUint32(offset, true);
399
+ if (tag !== TAG_INT) {
400
+ throw new Error(\`Expected int tag (\${TAG_INT}), got \${tag}\`);
401
+ }
402
+ // Read i64 value (little-endian)
403
+ // JavaScript DataView doesn't have getBigInt64 in older versions, so use two 32-bit reads
404
+ const low = view.getUint32(offset + TAG_SIZE, true);
405
+ const high = view.getInt32(offset + TAG_SIZE + 4, true);
406
+ // Combine to form a 64-bit signed integer
407
+ // For values that fit in Number, this works fine
408
+ const value = low + high * 0x100000000;
409
+ return value;
410
+ }
411
+
412
+ /**
413
+ * Read a UTF-16 string from memory with type tag.
414
+ *
415
+ * WASM Format: [tag: u32=4][stringPtr: u32]
416
+ * String data at stringPtr: [length: u32][utf16 chars...]
417
+ *
418
+ * FORMAT DIFFERENCE: This reads the canonical WASM representation using pointers
419
+ * and UTF-16 encoding (AssemblyScript's native string format), while writeString()
420
+ * uses an inlined UTF-8 format for simplicity. Both are valid Value representations.
421
+ *
422
+ * @param view - DataView for reading
423
+ * @param offset - Offset to read from
424
+ * @returns The decoded string
425
+ * @throws {Error} If type tag is not TAG_STRING
426
+ */
427
+ function readString(view, offset) {
428
+ // Read and verify tag
429
+ const tag = view.getUint32(offset, true);
430
+ if (tag !== TAG_STRING) {
431
+ throw new Error(\`Expected string tag (\${TAG_STRING}), got \${tag}\`);
432
+ }
433
+ // Read pointer to string data
434
+ const stringPtr = view.getUint32(offset + TAG_SIZE, true);
435
+
436
+ // Read string data from the pointer
437
+ if (stringPtr === 0) return '';
438
+
439
+ const length = view.getUint32(stringPtr, true);
440
+ if (length === 0) return '';
441
+
442
+ // Read UTF-16 code units and convert to string
443
+ let result = '';
444
+ for (let i = 0; i < length; i++) {
445
+ const codeUnit = view.getUint16(stringPtr + 4 + i * 2, true);
446
+ result += String.fromCharCode(codeUnit);
447
+ }
448
+
449
+ return result;
450
+ }
451
+
452
+ /**
453
+ * Marshal a primitive value to memory with automatic type detection.
454
+ *
455
+ * Supports null, boolean, number, and string types.
456
+ *
457
+ * @param value - The value to write (null, boolean, number, or string)
458
+ * @param view - DataView for writing
459
+ * @param offset - Offset to write at
460
+ * @returns Total bytes written
461
+ * @throws {Error} If value type is not supported
462
+ */
463
+ function writePrimitive(value, view, offset) {
464
+ if (value === null) {
465
+ return writeNull(view, offset);
466
+ } else if (typeof value === 'boolean') {
467
+ return writeBoolean(value, view, offset);
468
+ } else if (typeof value === 'number') {
469
+ return writeFloat(value, view, offset);
470
+ } else if (typeof value === 'string') {
471
+ return writeString(value, view, offset);
472
+ } else {
473
+ throw new Error('Unsupported type for marshaling: ' + typeof value);
474
+ }
475
+ }
476
+
477
+ /**
478
+ * Read a primitive value from memory with type detection.
479
+ *
480
+ * Reads the type tag and dispatches to the appropriate read function.
481
+ *
482
+ * @param view - DataView for reading
483
+ * @param offset - Offset to read from
484
+ * @returns The decoded value (null, boolean, number, or string)
485
+ * @throws {Error} If type tag is not recognized
486
+ */
487
+ function readPrimitive(view, offset) {
488
+ const tag = view.getUint32(offset, true);
489
+ switch (tag) {
490
+ case TAG_NULL:
491
+ return readNull(view, offset);
492
+ case TAG_BOOLEAN:
493
+ return readBoolean(view, offset);
494
+ case TAG_INT:
495
+ return readInt(view, offset);
496
+ case TAG_FLOAT:
497
+ return readFloat(view, offset);
498
+ case TAG_STRING:
499
+ return readString(view, offset);
500
+ default:
501
+ throw new Error('Unexpected type tag: ' + tag);
502
+ }
503
+ }
504
+
505
+ /**
506
+ * Marshal an object to memory.
507
+ * Returns the total bytes written for the object.
508
+ *
509
+ * Format: [tag: u32][propertyCount: u32][key1: tagged string][value1: tagged][key2: tagged string][value2: tagged]...
510
+ *
511
+ * Keys are written as tagged strings, followed by tagged values.
512
+ * Property order is preserved for deterministic serialization using Object.entries.
513
+ *
514
+ * @param obj - The object to marshal
515
+ * @param view - DataView for writing
516
+ * @param writeOffset - Offset to write the object at
517
+ * @returns Total bytes written
518
+ */
519
+ function writeObject(obj, view, writeOffset) {
520
+ const startOffset = writeOffset;
521
+ let offset = writeOffset;
522
+
523
+ // Write tag
524
+ view.setUint32(offset, TAG_OBJECT, true);
525
+ offset += TAG_SIZE;
526
+
527
+ // Get properties in order
528
+ const entries = Object.entries(obj);
529
+ const propCount = entries.length;
530
+
531
+ // Write property count
532
+ view.setUint32(offset, propCount, true);
533
+ offset += 4;
534
+
535
+ // Write each (key, value) pair
536
+ for (let i = 0; i < propCount; i++) {
537
+ const [key, value] = entries[i];
538
+
539
+ // Write key as tagged string (keys are tagged with TAG_STRING)
540
+ offset += writeString(key, view, offset);
541
+
542
+ // Write value (tagged)
543
+ offset += writeValue(value, view, offset);
544
+ }
545
+
546
+ return offset - startOffset;
547
+ }
548
+
549
+ /**
550
+ * Marshal a value to memory with automatic type detection.
551
+ *
552
+ * Supports null, boolean, number, string, array, and object types.
553
+ * This is the top-level value marshaling function that dispatches to
554
+ * the appropriate type-specific function.
555
+ *
556
+ * @param value - The value to write
557
+ * @param view - DataView for writing
558
+ * @param offset - Offset to write at
559
+ * @returns Total bytes written
560
+ * @throws {Error} If value type is not supported
561
+ */
562
+ function writeValue(value, view, offset) {
563
+ if (value === null || value === undefined) {
564
+ return writeNull(view, offset);
565
+ } else if (typeof value === 'boolean') {
566
+ return writeBoolean(value, view, offset);
567
+ } else if (typeof value === 'number') {
568
+ return writeFloat(value, view, offset);
569
+ } else if (typeof value === 'string') {
570
+ return writeString(value, view, offset);
571
+ } else if (Array.isArray(value)) {
572
+ return writeArray(value, view, 0, offset);
573
+ } else if (typeof value === 'object') {
574
+ return writeObject(value, view, offset);
575
+ } else {
576
+ throw new Error('Unsupported type for marshaling: ' + typeof value);
577
+ }
578
+ }
579
+
580
+ /**
581
+ * Read an object from memory.
582
+ *
583
+ * WASM Format: Value.Object has: [type: u32=6][objectPtr: u32]
584
+ * objectPtr points to Map structure: [propCount: u32][keyPtr1: u32][valuePtr1: u32][keyPtr2: u32][valuePtr2: u32]...
585
+ * Key pointers point to UTF-16 string data
586
+ * Value pointers point to heap-allocated tagged values.
587
+ *
588
+ * @param view - DataView for reading
589
+ * @param offset - Offset to the Value.Object structure (NOT objectPtr)
590
+ * @returns The unmarshaled object
591
+ */
592
+ function readObject(view, offset) {
593
+ // Two cases:
594
+ // 1. If offset has TAG_OBJECT (6), it's a Value.Object structure: [type: u32][objectPtr: u32]
595
+ // 2. Otherwise, offset might already point to the Map structure directly
596
+
597
+ const tag = view.getUint32(offset, true);
598
+ let objectPtr;
599
+
600
+ if (tag === TAG_OBJECT) {
601
+ // Case 1: Value.Object structure, read pointer to Map
602
+ objectPtr = view.getUint32(offset + 4, true);
603
+ } else {
604
+ // Case 2: offset point directly to Map structure
605
+ objectPtr = offset;
606
+ }
607
+
608
+ const result = {};
609
+ if (objectPtr !== 0) {
610
+ // Read property count from map structure
611
+ const propCount = view.getUint32(objectPtr, true);
612
+ let mapOffset = objectPtr + 4;
613
+
614
+ for (let i = 0; i < propCount; i++) {
615
+ // Read key pointer and value pointer
616
+ const keyPtr = view.getUint32(mapOffset, true);
617
+ const valuePtr = view.getUint32(mapOffset + 4, true);
618
+ mapOffset += 8;
619
+
620
+ // Read key (raw UTF-16 string data at keyPtr: [length: u32][utf16 chars...])
621
+ const keyLen = view.getUint32(keyPtr, true);
622
+ let key = '';
623
+ for (let j = 0; j < keyLen; j++) {
624
+ const codeUnit = view.getUint16(keyPtr + 4 + j * 2, true);
625
+ key += String.fromCharCode(codeUnit);
626
+ }
627
+
628
+ // Read value (tagged value at valuePtr)
629
+ const value = readValue(view, valuePtr);
630
+
631
+ result[key] = value;
632
+ }
633
+ }
634
+
635
+ return result;
636
+ }
637
+
638
+ /**
639
+ * Calculate the size in bytes of a tagged value at the given offset.
640
+ *
641
+ * @param view - DataView for reading
642
+ * @param offset - Offset to calculate size from
643
+ * @returns Total bytes the value occupies
644
+ * @throws {Error} If type tag is not recognized
645
+ */
646
+ function getValueSize(view, offset) {
647
+ const tag = view.getUint32(offset, true);
648
+
649
+ switch (tag) {
650
+ case TAG_NULL:
651
+ return TAG_SIZE;
652
+ case TAG_BOOLEAN:
653
+ return TAG_SIZE + 1;
654
+ case TAG_INT:
655
+ return TAG_SIZE + 8;
656
+ case TAG_FLOAT:
657
+ return TAG_SIZE + 8;
658
+ case TAG_STRING: {
659
+ const strLen = view.getUint32(offset + TAG_SIZE, true);
660
+ return TAG_SIZE + 4 + strLen;
661
+ }
662
+ case TAG_ARRAY: {
663
+ const arrLen = view.getUint32(offset + TAG_SIZE, true);
664
+ let size = TAG_SIZE + 4; // tag + length
665
+ let elemOffset = offset + TAG_SIZE + 4;
666
+ for (let i = 0; i < arrLen; i++) {
667
+ const elemSize = getValueSize(view, elemOffset);
668
+ size += elemSize;
669
+ elemOffset += elemSize;
670
+ }
671
+ return size;
672
+ }
673
+ case TAG_OBJECT: {
674
+ const propCount = view.getUint32(offset + TAG_SIZE, true);
675
+ let size = TAG_SIZE + 4; // tag + property count
676
+ let propOffset = offset + TAG_SIZE + 4;
677
+ for (let i = 0; i < propCount; i++) {
678
+ // Skip key (tagged string)
679
+ const keySize = getValueSize(view, propOffset);
680
+ size += keySize;
681
+ propOffset += keySize;
682
+
683
+ // Skip value (tagged value)
684
+ const valSize = getValueSize(view, propOffset);
685
+ size += valSize;
686
+ propOffset += valSize;
687
+ }
688
+ return size;
689
+ }
690
+ default:
691
+ throw new Error('Unexpected type tag: ' + tag);
692
+ }
693
+ }
694
+
695
+ /**
696
+ * Read a value from memory with type detection.
697
+ *
698
+ * Reads the type tag and dispatches to the appropriate read function.
699
+ *
700
+ * @param view - DataView for reading
701
+ * @param offset - Offset to read from
702
+ * @returns The decoded value
703
+ * @throws {Error} If type tag is not recognized
704
+ */
705
+ function readValue(view, offset) {
706
+ const tag = view.getUint32(offset, true);
707
+ switch (tag) {
708
+ case TAG_NULL:
709
+ return readNull(view, offset);
710
+ case TAG_BOOLEAN:
711
+ return readBoolean(view, offset);
712
+ case TAG_INT:
713
+ return readInt(view, offset);
714
+ case TAG_FLOAT:
715
+ return readFloat(view, offset);
716
+ case TAG_STRING:
717
+ return readString(view, offset);
718
+ case TAG_ARRAY:
719
+ return readArray(view, offset);
720
+ case TAG_OBJECT:
721
+ return readObject(view, offset);
722
+ default:
723
+ throw new Error('Unexpected type tag: ' + tag);
724
+ }
725
+ }
726
+
727
+ /**
728
+ * Marshal an array to memory.
729
+ * Returns the total bytes written for the array.
730
+ *
731
+ * Format: [tag: u32][length: u32][tagged elements...]
732
+ *
733
+ * @param arr - The array to marshal
734
+ * @param view - DataView for writing
735
+ * @param ptr - Base pointer (unused, kept for API compatibility)
736
+ * @param writeOffset - Offset to write the array at
737
+ * @returns Total bytes written
738
+ */
739
+ function writeArray(arr, view, ptr, writeOffset) {
740
+ const startOffset = writeOffset;
741
+ let offset = writeOffset;
742
+
743
+ // Write tag
744
+ view.setUint32(offset, TAG_ARRAY, true);
745
+ offset += TAG_SIZE;
746
+
747
+ // Write length
748
+ view.setUint32(offset, arr.length, true);
749
+ offset += 4;
750
+
751
+ // Write elements recursively
752
+ for (let i = 0; i < arr.length; i++) {
753
+ const value = arr[i];
754
+ offset += writeValue(value, view, offset);
755
+ }
756
+
757
+ return offset - startOffset;
758
+ }
759
+
760
+ /**
761
+ * Calculate the size needed to marshal an object.
762
+ *
763
+ * Format: [tag: byte][propertyCount: u32][key1: tagged string][value1: tagged][key2: tagged string][value2: tagged]...
764
+ *
765
+ * @param obj - The object to calculate size for
766
+ * @returns Total bytes needed for the object
767
+ */
768
+ function calculateObjectSize(obj) {
769
+ let size = 5; // tag (1 byte) + property count (4 bytes)
770
+
771
+ const entries = Object.entries(obj);
772
+ for (let i = 0; i < entries.length; i++) {
773
+ const [key, value] = entries[i];
774
+ // Key: tagged string (tag: 4 + pointer: 4 + length: 4 + UTF-16 data: 2 bytes per code unit)
775
+ size += 8 + 4 + key.length * 2;
776
+ // Value: calculate size of tagged value
777
+ size += calculateValueSize(value);
778
+ }
779
+
780
+ return size;
781
+ }
782
+
783
+ /**
784
+ * Calculate the size needed to marshal a value.
785
+ *
786
+ * @param value - The value to calculate size for
787
+ * @returns Total bytes needed for the value
788
+ */
789
+ function calculateValueSize(value) {
790
+ if (value === null || value === undefined) {
791
+ return 1;
792
+ } else if (typeof value === 'boolean') {
793
+ return 2;
794
+ } else if (typeof value === 'number') {
795
+ return 9;
796
+ } else if (typeof value === 'string') {
797
+ // tag (4) + pointer (4) + length (4) + UTF-16 data (2 bytes per code unit)
798
+ return 8 + 4 + value.length * 2;
799
+ } else if (Array.isArray(value)) {
800
+ let size = 5;
801
+ for (let i = 0; i < value.length; i++) {
802
+ size += calculateValueSize(value[i]);
803
+ }
804
+ return size;
805
+ } else if (typeof value === 'object') {
806
+ return calculateObjectSize(value);
807
+ } else {
808
+ throw new Error('Unsupported type for marshaling: ' + typeof value);
809
+ }
810
+ }
811
+
812
+ /**
813
+ * Read an array from memory.
814
+ *
815
+ * WASM Format: Value.Array has: [type: u32=5][arrayPtr: u32]
816
+ * arrayPtr points to array structure: [length: u32][elementPtr1: u32][elementPtr2: u32]...
817
+ * Each elementPtr points to a tagged Value structure
818
+ *
819
+ * @param view - DataView for reading
820
+ * @param offset - Offset to the Value.Array structure (NOT arrayPtr)
821
+ * @returns The unmarshaled array
822
+ */
823
+ function readArray(view, offset) {
824
+ // Two cases:
825
+ // 1. If offset has TAG_ARRAY (5), it's a Value.Array structure: [type: u32][arrayPtr: u32]
826
+ // 2. Otherwise, offset might already point to the array structure directly
827
+
828
+ const tag = view.getUint32(offset, true);
829
+ let arrayPtr;
830
+
831
+ if (tag === TAG_ARRAY) {
832
+ // Case 1: Value.Array structure, read pointer to array data
833
+ arrayPtr = view.getUint32(offset + 4, true);
834
+ } else {
835
+ // Case 2: offset points directly to array structure
836
+ arrayPtr = offset;
837
+ }
838
+
839
+ // Validate arrayPtr is within bounds
840
+ if (arrayPtr === 0 || arrayPtr >= view.byteLength) {
841
+ return [];
842
+ }
843
+
844
+ // Read length field (may have high bit set for flat format)
845
+ const lengthField = view.getUint32(arrayPtr, true);
846
+ const FLAT_ARRAY_MARKER = 0x80000000;
847
+
848
+ // Check if this is a flat numeric array (high bit set)
849
+ if ((lengthField & FLAT_ARRAY_MARKER) !== 0) {
850
+ // Flat numeric format: [length | marker: u32][f64 elements...]
851
+ const length = lengthField & ~FLAT_ARRAY_MARKER;
852
+ const result = [];
853
+ for (let i = 0; i < length; i++) {
854
+ const value = view.getFloat64(arrayPtr + 4 + i * 8, true);
855
+ result.push(value);
856
+ }
857
+ return result;
858
+ }
859
+
860
+ // Generic format: [length: u32][Value pointers...]
861
+ const length = lengthField;
862
+
863
+ // Read element pointers and dereference them
864
+ const result = [];
865
+ for (let i = 0; i < length; i++) {
866
+ const elemPtr = view.getUint32(arrayPtr + 4 + i * 4, true);
867
+ // Skip invalid pointers
868
+ if (elemPtr === 0 || elemPtr >= view.byteLength) {
869
+ result.push(null);
870
+ continue;
871
+ }
872
+ const value = readValue(view, elemPtr);
873
+ result.push(value);
874
+ }
875
+
876
+ return result;
877
+ }
878
+ `;
879
+ }
880
+
881
+ /**
882
+ * Generate the unmarshal function body.
883
+ *
884
+ * This function is currently unused but kept for potential future use with alternative
885
+ * marshaling strategies. It generates code to read fixed-layout structs directly,
886
+ * which could be more efficient than the current generic Value-based approach.
887
+ *
888
+ * @param layout - The flattened schema layout
889
+ * @param _prefix - Unused parameter (reserved for potential future use with prefixed field names)
890
+ * @returns Generated JavaScript code for unmarshaling
891
+ */
892
+ export function _generateUnmarshalBody(layout: FlattenedLayout, _prefix: string): string {
893
+ const lines: string[] = [];
894
+
895
+ lines.push(' const output = {};');
896
+ lines.push('');
897
+
898
+ // Build nested object structure
899
+ const paths = buildNestedPaths(layout.fields);
900
+ lines.push(...paths);
901
+
902
+ lines.push('');
903
+
904
+ // Read fixed fields
905
+ for (const field of layout.fields) {
906
+ if (field.type === 'string' || field.type === 'array') {
907
+ // Skip - handled in variable section
908
+ continue;
909
+ } else if (field.type === 'bool') {
910
+ lines.push(' // ' + field.path);
911
+ lines.push(
912
+ ` output${field.path
913
+ .split('.')
914
+ .map((p) => `['${p}']`)
915
+ .join('')} = view.getUint32(readOffset + ${field.offset}, true) !== 0;`,
916
+ );
917
+ } else if (field.type === 'i64') {
918
+ lines.push(' // ' + field.path);
919
+ lines.push(
920
+ ` output${field.path
921
+ .split('.')
922
+ .map((p) => `['${p}']`)
923
+ .join('')} = Number(view.getBigInt64(readOffset + ${field.offset}, true));`,
924
+ );
925
+ } else {
926
+ lines.push(' // ' + field.path);
927
+ const valueGetter = field.type === 'f64' ? 'getFloat64' : 'getInt32';
928
+ lines.push(
929
+ ` output${field.path
930
+ .split('.')
931
+ .map((p) => `['${p}']`)
932
+ .join('')} = view.${valueGetter}(readOffset + ${field.offset}, true);`,
933
+ );
934
+ }
935
+ }
936
+
937
+ // Read variable-length data
938
+ for (const field of layout.fields) {
939
+ if (field.type === 'string') {
940
+ lines.push('');
941
+ lines.push(' // ' + field.path);
942
+ lines.push(
943
+ ` const ${field.flatName}_ptr = view.getUint32(readOffset + ${field.offset}, true);`,
944
+ );
945
+ lines.push(
946
+ ` const ${field.flatName}_len = view.getUint32(readOffset + ${field.offset} + 4, true);`,
947
+ );
948
+ lines.push(
949
+ ` output${field.path
950
+ .split('.')
951
+ .map((p) => `['${p}']`)
952
+ .join('')} = ${field.flatName}_len > 0 ? readString(view, ${field.flatName}_ptr) : '';`,
953
+ );
954
+ } else if (field.type === 'array') {
955
+ lines.push('');
956
+ lines.push(' // ' + field.path);
957
+ lines.push(
958
+ ` const ${field.flatName}_ptr = view.getUint32(readOffset + ${field.offset}, true);`,
959
+ );
960
+ lines.push(
961
+ ` const ${field.flatName}_len = view.getUint32(readOffset + ${field.offset} + 4, true);`,
962
+ );
963
+ lines.push(
964
+ ` output${field.path
965
+ .split('.')
966
+ .map((p) => `['${p}']`)
967
+ .join('')} = readArray(view, ${field.flatName}_ptr);`,
968
+ );
969
+ }
970
+ }
971
+
972
+ return lines.join('\n');
973
+ }
974
+
975
+ /**
976
+ * Build nested object initialization code
977
+ */
978
+ function buildNestedPaths(fields: Array<{ path: string }>): string[] {
979
+ const paths: string[] = [];
980
+ const nestedObjects = new Set<string>();
981
+
982
+ for (const field of fields) {
983
+ const parts = field.path.split('.');
984
+ for (let i = 0; i < parts.length - 1; i++) {
985
+ const prefix = parts.slice(0, i + 1).join('.');
986
+ if (!nestedObjects.has(prefix)) {
987
+ nestedObjects.add(prefix);
988
+ const code = ` output${prefix
989
+ .split('.')
990
+ .map((p) => `['${p}']`)
991
+ .join('')} = {};`;
992
+ paths.push(code);
993
+ }
994
+ }
995
+ }
996
+
997
+ // Deduplicate and sort
998
+ return Array.from(new Set(paths));
999
+ }