@divmain/jdm-asm 0.2.1 → 0.2.3
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.
- package/dist/index.js +2227 -29
- package/dist/index.js.map +1 -1
- package/package.json +8 -2
- package/.github/workflows/ci.yml +0 -53
- package/.oxfmtrc.json +0 -16
- package/.oxlintrc.json +0 -183
- package/AGENTS.md +0 -81
- package/asconfig.json +0 -23
- package/benchmarks/fixtures.ts +0 -111
- package/benchmarks/input-fixtures.ts +0 -80
- package/benchmarks/run.ts +0 -913
- package/benchmarks/worker-pool.ts +0 -223
- package/benchmarks/worker.ts +0 -374
- package/scripts/run-all-tests.ts +0 -220
- package/src/compiler/EXPRESSION_SUBSETS.md +0 -228
- package/src/compiler/asc-compiler.ts +0 -315
- package/src/compiler/ast-types.ts +0 -215
- package/src/compiler/build.ts +0 -56
- package/src/compiler/cache.ts +0 -414
- package/src/compiler/code-generators.ts +0 -211
- package/src/compiler/codegen/index.ts +0 -15
- package/src/compiler/codegen/js-marshal.ts +0 -999
- package/src/compiler/codegen/js-validation.ts +0 -243
- package/src/compiler/codegen.ts +0 -19
- package/src/compiler/compile-time-validation.ts +0 -507
- package/src/compiler/cst-visitor.ts +0 -434
- package/src/compiler/errors.ts +0 -227
- package/src/compiler/expression-parser.ts +0 -536
- package/src/compiler/graph.ts +0 -197
- package/src/compiler/index.ts +0 -199
- package/src/compiler/input-validation.ts +0 -33
- package/src/compiler/marshal-gen.ts +0 -21
- package/src/compiler/nodes/context-resolvers.ts +0 -197
- package/src/compiler/nodes/decision-table.ts +0 -507
- package/src/compiler/nodes/decision.ts +0 -292
- package/src/compiler/nodes/expression-compiler.ts +0 -526
- package/src/compiler/nodes/expression.ts +0 -425
- package/src/compiler/nodes/function.ts +0 -316
- package/src/compiler/nodes/input.ts +0 -60
- package/src/compiler/nodes/switch.ts +0 -547
- package/src/compiler/optimizer.ts +0 -948
- package/src/compiler/orchestrator.ts +0 -352
- package/src/compiler/parser.ts +0 -115
- package/src/compiler/result-selection.ts +0 -161
- package/src/compiler/runtime/index.ts +0 -26
- package/src/compiler/runtime-codegen.ts +0 -211
- package/src/compiler/runtime-validation-codegen.ts +0 -294
- package/src/compiler/runtime.ts +0 -452
- package/src/compiler/schema.ts +0 -245
- package/src/compiler/switch-branch-detection.ts +0 -92
- package/src/compiler/types.ts +0 -136
- package/src/compiler/unary-ast-transforms.ts +0 -148
- package/src/compiler/unary-parser.ts +0 -301
- package/src/compiler/unary-transform.ts +0 -161
- package/src/compiler/utils.ts +0 -27
- package/src/compiler/virtual-fs.ts +0 -90
- package/src/compiler/wasm-instantiate.ts +0 -127
- package/src/index.ts +0 -1
- package/src/runtime/arrays.ts +0 -579
- package/src/runtime/context.ts +0 -189
- package/src/runtime/expressions.ts +0 -1811
- package/src/runtime/index.ts +0 -8
- package/src/runtime/memory.ts +0 -607
- package/src/runtime/strings.ts +0 -260
- package/src/runtime/tables.ts +0 -96
- package/src/runtime/tsconfig.json +0 -4
- package/src/runtime/values.ts +0 -209
- package/test-data/README.md +0 -83
- package/test-data/decision-tables/basic/8k.json +0 -87992
- package/test-data/decision-tables/basic/affiliate-commission-calculator.json +0 -228
- package/test-data/decision-tables/basic/airline-loyalty-points-calculations.json +0 -285
- package/test-data/decision-tables/basic/airline-upgrade-eligibility.json +0 -466
- package/test-data/decision-tables/basic/auto-insurance-premium-calculator.json +0 -412
- package/test-data/decision-tables/basic/booking-personalization-system.json +0 -553
- package/test-data/decision-tables/basic/care-team-assignment-system.json +0 -585
- package/test-data/decision-tables/basic/claim-validation-system.json +0 -307
- package/test-data/decision-tables/basic/clinical-lab-result-interpreter.json +0 -433
- package/test-data/decision-tables/basic/clinical-treatment-protocol.json +0 -474
- package/test-data/decision-tables/basic/credit-limit-adjustment.json +0 -479
- package/test-data/decision-tables/basic/customer-eligibility-engine.json +0 -551
- package/test-data/decision-tables/basic/customer-lifetime-value.json +0 -200
- package/test-data/decision-tables/basic/customer-onboarding-kyc-verification.json +0 -611
- package/test-data/decision-tables/basic/customer-service-escalation.json +0 -191
- package/test-data/decision-tables/basic/decision-table-discounts.json +0 -168
- package/test-data/decision-tables/basic/decision-table-shipping.json +0 -398
- package/test-data/decision-tables/basic/delivery-route-optimizer.json +0 -271
- package/test-data/decision-tables/basic/device-compatibility-checker.json +0 -303
- package/test-data/decision-tables/basic/disaster-relief-fund-allocation.json +0 -296
- package/test-data/decision-tables/basic/dynamic-fx-rate-pricing-system.json +0 -237
- package/test-data/decision-tables/basic/dynamic-marketplace-comission-calculator.json +0 -242
- package/test-data/decision-tables/basic/dynamic-shipping-cost-calculator.json +0 -378
- package/test-data/decision-tables/basic/dynamic-tarrif-engine.json +0 -289
- package/test-data/decision-tables/basic/dynamic-ticket-pricing.json +0 -325
- package/test-data/decision-tables/basic/empty-column-with-space.json +0 -100
- package/test-data/decision-tables/basic/empty-column-without-space.json +0 -100
- package/test-data/decision-tables/basic/environment-compliance-assessment.json +0 -386
- package/test-data/decision-tables/basic/expression-table-map.json +0 -313
- package/test-data/decision-tables/basic/flash-sale-eligibility.json +0 -366
- package/test-data/decision-tables/basic/flight-dispatch-decision-system.json +0 -455
- package/test-data/decision-tables/basic/flight-rebooking-fee-calculator.json +0 -406
- package/test-data/decision-tables/basic/government-assistance.json +0 -299
- package/test-data/decision-tables/basic/grant-funding-distribution.json +0 -307
- package/test-data/decision-tables/basic/hazardous-materials-management-system.json +0 -414
- package/test-data/decision-tables/basic/immigration-eligibility-evaluator.json +0 -765
- package/test-data/decision-tables/basic/import-duties-calculator.json +0 -318
- package/test-data/decision-tables/basic/insurance-agent-commission.json +0 -228
- package/test-data/decision-tables/basic/insurance-coverage-calculator.json +0 -362
- package/test-data/decision-tables/basic/insurance-underwriting-risk.json +0 -321
- package/test-data/decision-tables/basic/international-roaming-policy-manager.json +0 -199
- package/test-data/decision-tables/basic/legacy-plan-management.json +0 -434
- package/test-data/decision-tables/basic/marketplace-listing-verification-system.json +0 -334
- package/test-data/decision-tables/basic/medication-dosage-calculator.json +0 -318
- package/test-data/decision-tables/basic/merch-bags.json +0 -171
- package/test-data/decision-tables/basic/municipal-permit-evaluation-system.json +0 -364
- package/test-data/decision-tables/basic/mvno-partner-enablement.json +0 -313
- package/test-data/decision-tables/basic/partner-revenue-sharing.json +0 -244
- package/test-data/decision-tables/basic/payment-routing-and-fee-calculator.json +0 -475
- package/test-data/decision-tables/basic/policy-discount-calculator.json +0 -307
- package/test-data/decision-tables/basic/policy-eligibility-analyzer.json +0 -299
- package/test-data/decision-tables/basic/product-listing-scoring.json +0 -358
- package/test-data/decision-tables/basic/realtime-fraud-detection.json +0 -235
- package/test-data/decision-tables/basic/regional-compliance-manager.json +0 -278
- package/test-data/decision-tables/basic/returns-and-refund-policy.json +0 -366
- package/test-data/decision-tables/basic/returns-processing-system.json +0 -448
- package/test-data/decision-tables/basic/school-district-resource-allocation.json +0 -282
- package/test-data/decision-tables/basic/seat-map-optimization.json +0 -325
- package/test-data/decision-tables/basic/seller-fee-calculator.json +0 -307
- package/test-data/decision-tables/basic/service-level-agreement-enforcement.json +0 -575
- package/test-data/decision-tables/basic/smart-financial-product-matcher.json +0 -249
- package/test-data/decision-tables/basic/supply-chain-risk.json +0 -316
- package/test-data/decision-tables/basic/table-loop.json +0 -93
- package/test-data/decision-tables/basic/table.json +0 -76
- package/test-data/decision-tables/basic/traffic-violation-penalty-calculator.json +0 -436
- package/test-data/decision-tables/basic/transaction-compliance-classifier.json +0 -525
- package/test-data/decision-tables/basic/vehicle-claims-resolution.json +0 -310
- package/test-data/decision-tables/basic/warehouse-storage-location.json +0 -345
- package/test-data/decision-tables/hit-policy-collect/collect-multiple-matches.json +0 -127
- package/test-data/decision-tables/hit-policy-collect/collect-no-match.json +0 -95
- package/test-data/decision-tables/hit-policy-first/first-match.json +0 -103
- package/test-data/decision-tables/hit-policy-first/no-match.json +0 -95
- package/test-data/decision-tables/hit-policy-output-order/output-order-respected.json +0 -94
- package/test-data/decision-tables/hit-policy-output-order/string-output-order.json +0 -94
- package/test-data/decision-tables/hit-policy-priority/priority-respected.json +0 -86
- package/test-data/decision-tables/hit-policy-rule-order/rule-order-respected.json +0 -94
- package/test-data/decision-tables/hit-policy-unique/all-match-error.json +0 -89
- package/test-data/decision-tables/hit-policy-unique/multiple-match-error.json +0 -89
- package/test-data/decision-tables/hit-policy-unique/no-match.json +0 -88
- package/test-data/decision-tables/hit-policy-unique/unique-match.json +0 -99
- package/test-data/expressions/arithmetic/error-cyclic.json +0 -114
- package/test-data/expressions/arithmetic/error-missing-input.json +0 -54
- package/test-data/expressions/arithmetic/error-missing-output.json +0 -54
- package/test-data/expressions/arithmetic/expression-default.json +0 -93
- package/test-data/expressions/arithmetic/expression-fields.json +0 -94
- package/test-data/expressions/arithmetic/expression-loop.json +0 -94
- package/test-data/expressions/arithmetic/expression-passthrough.json +0 -108
- package/test-data/expressions/arithmetic/expression.json +0 -69
- package/test-data/expressions/arithmetic/nested-request.json +0 -125
- package/test-data/expressions/arithmetic/number-function.json +0 -58
- package/test-data/expressions/arithmetic/test-number-functions.json +0 -68
- package/test-data/expressions/functions/all.json +0 -149
- package/test-data/expressions/functions/avg.json +0 -89
- package/test-data/expressions/functions/filter.json +0 -109
- package/test-data/expressions/functions/flat.json +0 -167
- package/test-data/expressions/functions/map-strings.json +0 -65
- package/test-data/expressions/functions/map.json +0 -73
- package/test-data/expressions/functions/reduce.json +0 -49
- package/test-data/expressions/functions/some.json +0 -175
- package/test-data/expressions/functions/sort-strings.json +0 -97
- package/test-data/expressions/functions/sort.json +0 -97
- package/test-data/expressions/logical/logical-and.json +0 -116
- package/test-data/expressions/logical/logical-complex.json +0 -260
- package/test-data/expressions/logical/logical-not.json +0 -111
- package/test-data/expressions/logical/logical-or.json +0 -123
- package/test-data/expressions/string/string-comparison.json +0 -128
- package/test-data/expressions/string/string-concat.json +0 -106
- package/test-data/expressions/string/string-contains.json +0 -125
- package/test-data/expressions/string/string-endsWith.json +0 -113
- package/test-data/expressions/string/string-indexOf.json +0 -131
- package/test-data/expressions/string/string-join.json +0 -92
- package/test-data/expressions/string/string-lower.json +0 -94
- package/test-data/expressions/string/string-replace.json +0 -130
- package/test-data/expressions/string/string-split.json +0 -101
- package/test-data/expressions/string/string-startsWith.json +0 -113
- package/test-data/expressions/string/string-substring.json +0 -138
- package/test-data/expressions/string/string-trim.json +0 -100
- package/test-data/expressions/string/string-upper.json +0 -94
- package/test-data/other/custom.json +0 -51
- package/test-data/other/customer-input-schema.json +0 -34
- package/test-data/other/customer-output-schema.json +0 -34
- package/test-data/other/passthrough.json +0 -31
- package/test-data/sub-decisions/basic/$nodes-child.json +0 -31
- package/test-data/sub-decisions/basic/$nodes-parent.json +0 -49
- package/test-data/sub-decisions/basic/recursive-table1.json +0 -49
- package/test-data/sub-decisions/basic/recursive-table2.json +0 -49
- package/test-data/sub-decisions/complex-multi/approval-decision.json +0 -31
- package/test-data/sub-decisions/complex-multi/complex-dag.json +0 -175
- package/test-data/sub-decisions/complex-multi/credit-check.json +0 -31
- package/test-data/sub-decisions/complex-multi/customer-segmentation.json +0 -31
- package/test-data/sub-decisions/complex-multi/discount-eligibility.json +0 -31
- package/test-data/sub-decisions/complex-multi/eligibility-check.json +0 -31
- package/test-data/sub-decisions/complex-multi/final-offer.json +0 -31
- package/test-data/sub-decisions/complex-multi/income-verification.json +0 -31
- package/test-data/sub-decisions/complex-multi/linear-chain.json +0 -121
- package/test-data/sub-decisions/complex-multi/pricing-calculation.json +0 -31
- package/test-data/sub-decisions/complex-multi/product-eligibility.json +0 -31
- package/test-data/sub-decisions/complex-multi/risk-assessment.json +0 -31
- package/test-data/sub-decisions/complex-multi/shared-validation.json +0 -31
- package/test-data/sub-decisions/complex-multi/validation.json +0 -31
- package/test-data/sub-decisions/diamond/decision-a.json +0 -31
- package/test-data/sub-decisions/diamond/decision-b.json +0 -31
- package/test-data/sub-decisions/diamond/decision-c.json +0 -31
- package/test-data/sub-decisions/diamond/decision-shared.json +0 -31
- package/test-data/sub-decisions/diamond/diamond-pattern.json +0 -109
- package/test-data/sub-decisions/error-propagation/parent-calls-error.json +0 -44
- package/test-data/sub-decisions/error-propagation/sub-decision-with-error.json +0 -60
- package/test-data/switch-nodes/basic/account-dormancy-management.json +0 -245
- package/test-data/switch-nodes/basic/application-risk-assessment.json +0 -474
- package/test-data/switch-nodes/basic/cellular-data-rollover-system.json +0 -281
- package/test-data/switch-nodes/basic/clinical-pathway-selection.json +0 -454
- package/test-data/switch-nodes/basic/insurance-prior-authorization.json +0 -467
- package/test-data/switch-nodes/basic/last-mile-delivery-assignment.json +0 -373
- package/test-data/switch-nodes/basic/loan-approval.json +0 -469
- package/test-data/switch-nodes/basic/multi-switch.json +0 -498
- package/test-data/switch-nodes/basic/online-checkin-eligibility.json +0 -285
- package/test-data/switch-nodes/basic/order-consolidation-system.json +0 -493
- package/test-data/switch-nodes/basic/seller-approval-workflow.json +0 -383
- package/test-data/switch-nodes/basic/set-fee.json +0 -243
- package/test-data/switch-nodes/basic/shipping-carrier-selector.json +0 -379
- package/test-data/switch-nodes/basic/switch-node.json +0 -167
- package/test-data/switch-nodes/basic/switch-performance-2.json +0 -1307
- package/test-data/switch-nodes/basic/switch-performance.json +0 -691
- package/test-data/switch-nodes/basic/tax-exemption.json +0 -295
- package/test-data/switch-nodes/basic/warehouse-cross-docking.json +0 -313
- package/test-data/switch-nodes/default-cases/switch-with-default.json +0 -134
- package/test-data/zen-reference/$nodes-child.json +0 -69
- package/test-data/zen-reference/$nodes-parent.json +0 -34
- package/test-data/zen-reference/8k.json +0 -87992
- package/test-data/zen-reference/credit-analysis.json +0 -324
- package/test-data/zen-reference/custom.json +0 -51
- package/test-data/zen-reference/customer-input-schema.json +0 -34
- package/test-data/zen-reference/customer-output-schema.json +0 -34
- package/test-data/zen-reference/error-cyclic.json +0 -114
- package/test-data/zen-reference/error-missing-input.json +0 -54
- package/test-data/zen-reference/error-missing-output.json +0 -54
- package/test-data/zen-reference/expression.json +0 -69
- package/test-data/zen-reference/function-v2.json +0 -48
- package/test-data/zen-reference/function.json +0 -46
- package/test-data/zen-reference/graphs/account-dormancy-management.json +0 -245
- package/test-data/zen-reference/graphs/affiliate-commission-calculator.json +0 -228
- package/test-data/zen-reference/graphs/airline-loyalty-points-calculations.json +0 -285
- package/test-data/zen-reference/graphs/airline-upgrade-eligibility.json +0 -466
- package/test-data/zen-reference/graphs/aml.json +0 -537
- package/test-data/zen-reference/graphs/application-risk-assessment.json +0 -474
- package/test-data/zen-reference/graphs/auto-insurance-premium-calculator.json +0 -412
- package/test-data/zen-reference/graphs/booking-personalization-system.json +0 -553
- package/test-data/zen-reference/graphs/care-team-assignment-system.json +0 -585
- package/test-data/zen-reference/graphs/cellular-data-rollover-system.json +0 -281
- package/test-data/zen-reference/graphs/claim-validation-system.json +0 -307
- package/test-data/zen-reference/graphs/clinical-lab-result-interpreter.json +0 -433
- package/test-data/zen-reference/graphs/clinical-pathway-selection.json +0 -454
- package/test-data/zen-reference/graphs/clinical-treatment-protocol.json +0 -474
- package/test-data/zen-reference/graphs/company-analysis.json +0 -390
- package/test-data/zen-reference/graphs/credit-limit-adjustment.json +0 -479
- package/test-data/zen-reference/graphs/customer-eligibility-engine.json +0 -551
- package/test-data/zen-reference/graphs/customer-lifetime-value.json +0 -200
- package/test-data/zen-reference/graphs/customer-onboarding-kyc-verification.json +0 -611
- package/test-data/zen-reference/graphs/customer-service-escalation.json +0 -191
- package/test-data/zen-reference/graphs/decision-table-discounts.json +0 -168
- package/test-data/zen-reference/graphs/decision-table-shipping.json +0 -398
- package/test-data/zen-reference/graphs/delivery-route-optimizer.json +0 -271
- package/test-data/zen-reference/graphs/device-compatibility-checker.json +0 -303
- package/test-data/zen-reference/graphs/disaster-relief-fund-allocation.json +0 -296
- package/test-data/zen-reference/graphs/dynamic-fx-rate-pricing-system.json +0 -237
- package/test-data/zen-reference/graphs/dynamic-marketplace-comission-calculator.json +0 -242
- package/test-data/zen-reference/graphs/dynamic-shipping-cost-calculator.json +0 -378
- package/test-data/zen-reference/graphs/dynamic-tarrif-engine.json +0 -289
- package/test-data/zen-reference/graphs/dynamic-ticket-pricing.json +0 -325
- package/test-data/zen-reference/graphs/empty-column-with-space.json +0 -100
- package/test-data/zen-reference/graphs/empty-column-without-space.json +0 -100
- package/test-data/zen-reference/graphs/environment-compliance-assessment.json +0 -386
- package/test-data/zen-reference/graphs/expression-default.json +0 -93
- package/test-data/zen-reference/graphs/expression-fields.json +0 -94
- package/test-data/zen-reference/graphs/expression-loop.json +0 -94
- package/test-data/zen-reference/graphs/expression-passthrough.json +0 -108
- package/test-data/zen-reference/graphs/expression-table-map.json +0 -313
- package/test-data/zen-reference/graphs/flash-sale-eligibility.json +0 -366
- package/test-data/zen-reference/graphs/flight-dispatch-decision-system.json +0 -455
- package/test-data/zen-reference/graphs/flight-rebooking-fee-calculator.json +0 -406
- package/test-data/zen-reference/graphs/government-assistance.json +0 -299
- package/test-data/zen-reference/graphs/grant-funding-distribution.json +0 -307
- package/test-data/zen-reference/graphs/hazardous-materials-management-system.json +0 -414
- package/test-data/zen-reference/graphs/immigration-eligibility-evaluator.json +0 -765
- package/test-data/zen-reference/graphs/import-duties-calculator.json +0 -318
- package/test-data/zen-reference/graphs/insurance-agent-commission.json +0 -228
- package/test-data/zen-reference/graphs/insurance-breakdown.json +0 -421
- package/test-data/zen-reference/graphs/insurance-coverage-calculator.json +0 -362
- package/test-data/zen-reference/graphs/insurance-prior-authorization.json +0 -467
- package/test-data/zen-reference/graphs/insurance-underwriting-risk.json +0 -321
- package/test-data/zen-reference/graphs/international-roaming-policy-manager.json +0 -199
- package/test-data/zen-reference/graphs/last-mile-delivery-assignment.json +0 -373
- package/test-data/zen-reference/graphs/legacy-plan-management.json +0 -434
- package/test-data/zen-reference/graphs/loan-approval.json +0 -469
- package/test-data/zen-reference/graphs/marketplace-listing-verification-system.json +0 -334
- package/test-data/zen-reference/graphs/medication-dosage-calculator.json +0 -318
- package/test-data/zen-reference/graphs/merch-bags.json +0 -171
- package/test-data/zen-reference/graphs/multi-switch.json +0 -498
- package/test-data/zen-reference/graphs/municipal-permit-evaluation-system.json +0 -364
- package/test-data/zen-reference/graphs/mvno-partner-enablement.json +0 -313
- package/test-data/zen-reference/graphs/nested-request.json +0 -125
- package/test-data/zen-reference/graphs/online-checkin-eligibility.json +0 -285
- package/test-data/zen-reference/graphs/order-consolidation-system.json +0 -493
- package/test-data/zen-reference/graphs/partner-revenue-sharing.json +0 -244
- package/test-data/zen-reference/graphs/payment-routing-and-fee-calculator.json +0 -475
- package/test-data/zen-reference/graphs/policy-discount-calculator.json +0 -307
- package/test-data/zen-reference/graphs/policy-eligibility-analyzer.json +0 -299
- package/test-data/zen-reference/graphs/product-listing-scoring.json +0 -358
- package/test-data/zen-reference/graphs/realtime-fraud-detection.json +0 -235
- package/test-data/zen-reference/graphs/regional-compliance-manager.json +0 -278
- package/test-data/zen-reference/graphs/returns-and-refund-policy.json +0 -366
- package/test-data/zen-reference/graphs/returns-processing-system.json +0 -448
- package/test-data/zen-reference/graphs/school-district-resource-allocation.json +0 -282
- package/test-data/zen-reference/graphs/seat-map-optimization.json +0 -325
- package/test-data/zen-reference/graphs/seller-approval-workflow.json +0 -383
- package/test-data/zen-reference/graphs/seller-fee-calculator.json +0 -307
- package/test-data/zen-reference/graphs/service-level-agreement-enforcement.json +0 -575
- package/test-data/zen-reference/graphs/set-fee.json +0 -243
- package/test-data/zen-reference/graphs/shipping-carrier-selector.json +0 -379
- package/test-data/zen-reference/graphs/smart-financial-product-matcher.json +0 -249
- package/test-data/zen-reference/graphs/supply-chain-risk.json +0 -316
- package/test-data/zen-reference/graphs/table-loop.json +0 -93
- package/test-data/zen-reference/graphs/tax-exemption.json +0 -295
- package/test-data/zen-reference/graphs/traffic-violation-penalty-calculator.json +0 -436
- package/test-data/zen-reference/graphs/transaction-compliance-classifier.json +0 -525
- package/test-data/zen-reference/graphs/vehicle-claims-resolution.json +0 -310
- package/test-data/zen-reference/graphs/warehouse-cross-docking.json +0 -313
- package/test-data/zen-reference/graphs/warehouse-storage-location.json +0 -345
- package/test-data/zen-reference/http-function.json +0 -34
- package/test-data/zen-reference/infinite-function.json +0 -46
- package/test-data/zen-reference/js/imports.js +0 -25
- package/test-data/zen-reference/passthrough.json +0 -31
- package/test-data/zen-reference/recursive-table1.json +0 -49
- package/test-data/zen-reference/recursive-table2.json +0 -49
- package/test-data/zen-reference/sleep-function.json +0 -34
- package/test-data/zen-reference/switch-node.json +0 -167
- package/test-data/zen-reference/switch-performance-2.json +0 -1307
- package/test-data/zen-reference/switch-performance.json +0 -691
- package/test-data/zen-reference/table.json +0 -76
- package/tests/helpers/index.ts +0 -73
- package/tests/helpers/mock-context.ts +0 -231
- package/tests/helpers/round-trip.ts +0 -398
- package/tests/helpers/test-harness-comparison.ts +0 -325
- package/tests/helpers/test-harness-wasm.ts +0 -710
- package/tests/helpers/test-harness.ts +0 -28
- package/tests/helpers/wasm-test.ts +0 -659
- package/tests/integration/compilation-errors.test.ts +0 -864
- package/tests/integration/decision-tables.test.ts +0 -531
- package/tests/integration/edge-cases.test.ts +0 -787
- package/tests/integration/expressions.test.ts +0 -513
- package/tests/integration/function-node-integration.test.ts +0 -182
- package/tests/integration/sub-decisions.test.ts +0 -108
- package/tests/integration/switch-nodes.test.ts +0 -399
- package/tests/integration/unary-or-matching.test.ts +0 -53
- package/tests/integration/wasm-data-types.test.ts +0 -398
- package/tests/integration/wasm-errors.test.ts +0 -199
- package/tests/integration/wasm-execution.test.ts +0 -348
- package/tests/integration/wasm-memory.test.ts +0 -228
- package/tests/scripts/analyze-coverage.ts +0 -166
- package/tests/scripts/categorize-tests.ts +0 -396
- package/tests/scripts/coverage-analysis.ts +0 -836
- package/tests/unit/compiler/cache.test.ts +0 -238
- package/tests/unit/compiler/errors.test.ts +0 -316
- package/tests/unit/compiler/graph-scalability.test.ts +0 -510
- package/tests/unit/compiler/graph.test.ts +0 -878
- package/tests/unit/compiler/input-validation.test.ts +0 -447
- package/tests/unit/compiler/logical-and-parser.test.ts +0 -143
- package/tests/unit/compiler/logical-not-parser.test.ts +0 -107
- package/tests/unit/compiler/logical-or-parser.test.ts +0 -236
- package/tests/unit/compiler/marshal-gen/marshal-gen.test.ts +0 -97
- package/tests/unit/compiler/nodes/decision-table.test.ts +0 -103
- package/tests/unit/compiler/nodes/decision.test.ts +0 -182
- package/tests/unit/compiler/nodes/function-compile.test.ts +0 -204
- package/tests/unit/compiler/nodes/function.test.ts +0 -176
- package/tests/unit/compiler/nodes/input.test.ts +0 -30
- package/tests/unit/compiler/nodes/switch.test.ts +0 -127
- package/tests/unit/compiler/optimizer-cache.test.ts +0 -327
- package/tests/unit/compiler/optimizer-implementation.test.ts +0 -625
- package/tests/unit/compiler/parser.test.ts +0 -508
- package/tests/unit/compiler/runtime-error-cleanup.test.ts +0 -426
- package/tests/unit/compiler/runtime-validation.test.ts +0 -303
- package/tests/unit/compiler/runtime.test.ts +0 -221
- package/tests/unit/compiler/schema/schema.test.ts +0 -248
- package/tests/unit/compiler/unary-ast-transforms.test.ts +0 -245
- package/tsconfig.json +0 -27
- package/tsup.config.ts +0 -11
- package/vitest.config.ts +0 -12
|
@@ -1,710 +0,0 @@
|
|
|
1
|
-
import type { TSchema } from '@sinclair/typebox';
|
|
2
|
-
import { compile as compileWasm, type CompilationResult } from '../../src/compiler';
|
|
3
|
-
import { ensureMemory } from '../../src/compiler/runtime';
|
|
4
|
-
|
|
5
|
-
export { compileWasm as compile };
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Compare actual result against expected, but only check keys present in expected.
|
|
9
|
-
* This allows actual to have extra fields (e.g., passthrough fields).
|
|
10
|
-
*/
|
|
11
|
-
function expectPartialMatch(actual: unknown, expected: unknown, message: string): void {
|
|
12
|
-
if (expected === actual) {
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (typeof expected !== typeof actual) {
|
|
17
|
-
throw new Error(
|
|
18
|
-
`${message}: type mismatch (expected ${typeof expected}, got ${typeof actual})`,
|
|
19
|
-
);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (expected === null || actual === null) {
|
|
23
|
-
if (expected !== actual) {
|
|
24
|
-
throw new Error(`${message}: null mismatch`);
|
|
25
|
-
}
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (Array.isArray(expected)) {
|
|
30
|
-
if (!Array.isArray(actual)) {
|
|
31
|
-
throw new Error(`${message}: expected array, got ${typeof actual}`);
|
|
32
|
-
}
|
|
33
|
-
if (expected.length !== actual.length) {
|
|
34
|
-
throw new Error(`${message}: array length mismatch (${expected.length} vs ${actual.length})`);
|
|
35
|
-
}
|
|
36
|
-
for (let i = 0; i < expected.length; i++) {
|
|
37
|
-
expectPartialMatch(actual[i], expected[i], `${message}[${i}]`);
|
|
38
|
-
}
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (typeof expected === 'object') {
|
|
43
|
-
if (typeof actual !== 'object') {
|
|
44
|
-
throw new Error(`${message}: expected object, got ${typeof actual}`);
|
|
45
|
-
}
|
|
46
|
-
const expectedKeys = Object.keys(expected);
|
|
47
|
-
|
|
48
|
-
for (const key of expectedKeys) {
|
|
49
|
-
const expectedValue = (expected as Record<string, unknown>)[key];
|
|
50
|
-
if (!(key in (actual as object))) {
|
|
51
|
-
throw new Error(`${message}: missing key "${key}"`);
|
|
52
|
-
}
|
|
53
|
-
expectPartialMatch(
|
|
54
|
-
(actual as Record<string, unknown>)[key],
|
|
55
|
-
expectedValue,
|
|
56
|
-
`${message}.${key}`,
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Primitive comparison
|
|
63
|
-
if (expected !== actual) {
|
|
64
|
-
// Check if this looks like a timestamp comparison (Unix timestamps are large numbers)
|
|
65
|
-
const expectedNum = typeof expected === 'number';
|
|
66
|
-
const actualNum = typeof actual === 'number';
|
|
67
|
-
const isTimestamp =
|
|
68
|
-
expectedNum && actualNum && expected > 1_000_000_000 && actual > 1_000_000_000;
|
|
69
|
-
|
|
70
|
-
if (isTimestamp) {
|
|
71
|
-
// Skip exact timestamp comparison - just verify both are timestamps
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// For floating point numbers, allow small precision differences
|
|
76
|
-
if (expectedNum && actualNum) {
|
|
77
|
-
const relativeError =
|
|
78
|
-
Math.abs((expected as number) - (actual as number)) /
|
|
79
|
-
Math.max(Math.abs(expected as number), Math.abs(actual as number), 1e-15);
|
|
80
|
-
if (relativeError < 1e-14) {
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
throw new Error(`${message}: value mismatch (expected ${expected}, got ${actual})`);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* WASM-only test configuration (no zen-engine comparison)
|
|
91
|
-
*/
|
|
92
|
-
export interface WasmTestConfig {
|
|
93
|
-
name: string;
|
|
94
|
-
jdm: string | object;
|
|
95
|
-
inputSchema: TSchema;
|
|
96
|
-
outputSchema: TSchema;
|
|
97
|
-
input?: Record<string, unknown>;
|
|
98
|
-
expected?: Record<string, unknown> | unknown[];
|
|
99
|
-
unsupported?: string[];
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Simplified WASM test config without explicit schemas.
|
|
104
|
-
* Schemas are inferred from input/expected shapes.
|
|
105
|
-
*/
|
|
106
|
-
export interface SimpleWasmTestConfig {
|
|
107
|
-
name: string;
|
|
108
|
-
jdm: string | object;
|
|
109
|
-
input?: Record<string, unknown>;
|
|
110
|
-
expected?: Record<string, unknown> | unknown[];
|
|
111
|
-
unsupported?: string[];
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Evaluate a compiled WASM module with the given input.
|
|
116
|
-
*/
|
|
117
|
-
export async function evaluateCompiled(
|
|
118
|
-
compiled: CompilationResult,
|
|
119
|
-
input: Record<string, unknown>,
|
|
120
|
-
): Promise<Record<string, unknown>> {
|
|
121
|
-
// Simple helper to marshal input as a Map (for marshaling when schema has no fixed fields)
|
|
122
|
-
function marshalMapInput(
|
|
123
|
-
data: Record<string, unknown>,
|
|
124
|
-
memory: WebAssembly.Memory,
|
|
125
|
-
basePtr: number,
|
|
126
|
-
): number {
|
|
127
|
-
const view = new DataView(memory.buffer);
|
|
128
|
-
const entries = Object.entries(data);
|
|
129
|
-
const length = entries.length;
|
|
130
|
-
|
|
131
|
-
// Write map length at basePtr
|
|
132
|
-
view.setUint32(basePtr, length, true);
|
|
133
|
-
|
|
134
|
-
// Allocate and write keys and values
|
|
135
|
-
let currentOffset = basePtr + 4 + length * 8; // Skip map structure
|
|
136
|
-
|
|
137
|
-
const writeValue = (value: unknown): number => {
|
|
138
|
-
// Returns pointer to a fully allocated Value structure
|
|
139
|
-
const valuePtr = currentOffset;
|
|
140
|
-
|
|
141
|
-
if (value === null || value === undefined) {
|
|
142
|
-
// Value.Null: [type: u32=0]
|
|
143
|
-
view.setUint32(valuePtr, 0, true); // TAG_NULL = 0
|
|
144
|
-
currentOffset += 4;
|
|
145
|
-
} else if (typeof value === 'boolean') {
|
|
146
|
-
// Value.Bool: [type: u32=1][value: u8]
|
|
147
|
-
view.setUint32(valuePtr, 1, true); // TAG_BOOLEAN = 1
|
|
148
|
-
view.setUint8(valuePtr + 4, value ? 1 : 0);
|
|
149
|
-
currentOffset += 5;
|
|
150
|
-
} else if (typeof value === 'number') {
|
|
151
|
-
// Value.Float: [type: u32=3][value: f64]
|
|
152
|
-
view.setUint32(valuePtr, 3, true); // TAG_FLOAT = 3
|
|
153
|
-
view.setFloat64(valuePtr + 4, value, true);
|
|
154
|
-
currentOffset += 12;
|
|
155
|
-
} else if (typeof value === 'string') {
|
|
156
|
-
// Value.String: [type: u32=4][stringPtr: u32]
|
|
157
|
-
// Allocate space for the Value structure
|
|
158
|
-
view.setUint32(valuePtr, 4, true); // TAG_STRING = 4
|
|
159
|
-
|
|
160
|
-
// Skip to allocate string data
|
|
161
|
-
currentOffset += 8;
|
|
162
|
-
const stringDataPtr = currentOffset;
|
|
163
|
-
|
|
164
|
-
// Write string data: [length: u32][utf16 chars...]
|
|
165
|
-
const len = value.length;
|
|
166
|
-
view.setUint32(stringDataPtr, len, true);
|
|
167
|
-
for (let i = 0; i < len; i++) {
|
|
168
|
-
view.setUint16(stringDataPtr + 4 + i * 2, value.charCodeAt(i), true);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
currentOffset += 4 + len * 2; // length + UTF-16 chars
|
|
172
|
-
|
|
173
|
-
// Write pointer back to Value structure
|
|
174
|
-
view.setUint32(valuePtr + 4, stringDataPtr, true);
|
|
175
|
-
} else if (Array.isArray(value)) {
|
|
176
|
-
const arrLength = value.length;
|
|
177
|
-
|
|
178
|
-
// Skip past the Value structure (will fill in later)
|
|
179
|
-
const _tempOffset = currentOffset;
|
|
180
|
-
currentOffset += 8;
|
|
181
|
-
|
|
182
|
-
// Allocate space for array structure: [length: u32][elementPtr1: u32][elementPtr2: u32]...
|
|
183
|
-
const arrayPtr = currentOffset;
|
|
184
|
-
currentOffset += 4 + arrLength * 4; // length field + element pointers
|
|
185
|
-
|
|
186
|
-
// Write array structure with value pointers
|
|
187
|
-
view.setUint32(arrayPtr, arrLength, true); // Array length
|
|
188
|
-
|
|
189
|
-
// Write each element pointer
|
|
190
|
-
let ptrOffset = arrayPtr + 4;
|
|
191
|
-
for (let i = 0; i < arrLength; i++) {
|
|
192
|
-
const elemPtr = writeValue(value[i]);
|
|
193
|
-
view.setUint32(ptrOffset, elemPtr, true);
|
|
194
|
-
ptrOffset += 4;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// Now write the Value pointing to this array
|
|
198
|
-
view.setUint32(valuePtr, 5, true); // TAG_ARRAY = 5
|
|
199
|
-
view.setUint32(valuePtr + 4, arrayPtr, true); // Pointer to array data
|
|
200
|
-
} else if (typeof value === 'object') {
|
|
201
|
-
// Value.Object: [type: u32=6][mapPtr: u32]
|
|
202
|
-
const obj = value as Record<string, unknown>;
|
|
203
|
-
const objEntries = Object.entries(obj);
|
|
204
|
-
|
|
205
|
-
// Skip past the Value structure (will fill in later)
|
|
206
|
-
currentOffset += 8;
|
|
207
|
-
|
|
208
|
-
// Allocate space for map structure: [length: u32][keyPtr1: u32][valuePtr1: u32]...
|
|
209
|
-
const mapPtr = currentOffset;
|
|
210
|
-
currentOffset += 4 + objEntries.length * 8; // length field + key/value pointer pairs
|
|
211
|
-
|
|
212
|
-
// Write map structure with key/value pointers
|
|
213
|
-
view.setUint32(mapPtr, objEntries.length, true); // Number of properties
|
|
214
|
-
|
|
215
|
-
// Write each key/value pair
|
|
216
|
-
let ptrOffset = mapPtr + 4;
|
|
217
|
-
for (const [key, val] of objEntries) {
|
|
218
|
-
// Write key: treat string as raw key string data (not a Value structure)
|
|
219
|
-
const keyStrPtr = currentOffset;
|
|
220
|
-
const keyLen = key.length;
|
|
221
|
-
// Allocate space for key string data: [length: u32][utf16 chars...]
|
|
222
|
-
view.setUint32(keyStrPtr, keyLen, true);
|
|
223
|
-
for (let i = 0; i < keyLen; i++) {
|
|
224
|
-
view.setUint16(keyStrPtr + 4 + i * 2, key.charCodeAt(i), true);
|
|
225
|
-
}
|
|
226
|
-
currentOffset += 4 + keyLen * 2;
|
|
227
|
-
view.setUint32(ptrOffset, keyStrPtr, true);
|
|
228
|
-
|
|
229
|
-
// Write value pointer
|
|
230
|
-
const nestedValuePtr = writeValue(val);
|
|
231
|
-
view.setUint32(ptrOffset + 4, nestedValuePtr, true);
|
|
232
|
-
|
|
233
|
-
ptrOffset += 8;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Now write the Value pointing to this map
|
|
237
|
-
view.setUint32(valuePtr, 6, true); // TAG_OBJECT = 6
|
|
238
|
-
view.setUint32(valuePtr + 4, mapPtr, true); // Pointer to map data
|
|
239
|
-
} else {
|
|
240
|
-
throw new Error(`Unsupported type: ${typeof value}`);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
return valuePtr;
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
// Write map structure: [length: u32][keyPtr1: u32][valuePtr1: u32]...
|
|
247
|
-
// Note: writeString now returns a pointer to the string DATA, not the full Value structure
|
|
248
|
-
let ptrOffset = basePtr + 4;
|
|
249
|
-
for (let i = 0; i < length; i++) {
|
|
250
|
-
const [key, value] = entries[i];
|
|
251
|
-
const keyStrPtr = currentOffset; // Pointer to the string data
|
|
252
|
-
const keyLen = key.length;
|
|
253
|
-
// Write key as raw string data (not a Value): [length: u32][utf16 chars...]
|
|
254
|
-
view.setUint32(keyStrPtr, keyLen, true);
|
|
255
|
-
for (let j = 0; j < keyLen; j++) {
|
|
256
|
-
view.setUint16(keyStrPtr + 4 + j * 2, key.charCodeAt(j), true);
|
|
257
|
-
}
|
|
258
|
-
currentOffset += 4 + keyLen * 2;
|
|
259
|
-
|
|
260
|
-
const valuePtr = writeValue(value);
|
|
261
|
-
view.setUint32(ptrOffset, keyStrPtr, true);
|
|
262
|
-
view.setUint32(ptrOffset + 4, valuePtr, true);
|
|
263
|
-
ptrOffset += 8;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
return basePtr;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Instantiate WASM module
|
|
270
|
-
const wasmArray = new Uint8Array(compiled.wasm);
|
|
271
|
-
const buffer = wasmArray.buffer.slice(
|
|
272
|
-
wasmArray.byteOffset,
|
|
273
|
-
wasmArray.byteOffset + wasmArray.byteLength,
|
|
274
|
-
);
|
|
275
|
-
const wasmModule = await WebAssembly.compile(buffer as ArrayBuffer);
|
|
276
|
-
const instance = await WebAssembly.instantiate(wasmModule, {
|
|
277
|
-
env: {
|
|
278
|
-
abort: () => {
|
|
279
|
-
throw new Error('WASM abort called');
|
|
280
|
-
},
|
|
281
|
-
'Date.now': () => Date.now(),
|
|
282
|
-
},
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
const memory = instance.exports.memory as WebAssembly.Memory;
|
|
286
|
-
const evaluate = instance.exports.evaluate as (ptr: number) => number;
|
|
287
|
-
|
|
288
|
-
// Create a simple bump allocator for marshaling
|
|
289
|
-
// Start after the AssemblyScript data section (static strings, etc.)
|
|
290
|
-
// The AS compiler places static data around 1036-16000 for typical modules
|
|
291
|
-
// We use 192KB offset to give the AS runtime plenty of room for heap allocations
|
|
292
|
-
// during reading of complex nested data structures
|
|
293
|
-
|
|
294
|
-
// Start at 192KB to avoid AS runtime heap growth - AssemblyScript allocates its own heap
|
|
295
|
-
// starting around 1KB-16KB, and complex nested structures during evaluation may cause heap
|
|
296
|
-
// expansion. 192KB gives sufficient headroom to prevent collision between our marshal buffer
|
|
297
|
-
// and AS runtime heap.
|
|
298
|
-
let heapOffset = 192 * 1024;
|
|
299
|
-
const allocate = (size: number) => {
|
|
300
|
-
const ptr = heapOffset;
|
|
301
|
-
heapOffset += size;
|
|
302
|
-
return ptr;
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
// Load the generated marshal code
|
|
306
|
-
const cleanedCode = compiled.marshalCode
|
|
307
|
-
.replace(/^export function marshalInput/gm, 'function marshalInput')
|
|
308
|
-
.replace(/^export function unmarshalOutput/gm, 'function unmarshalOutput')
|
|
309
|
-
.replace(/^export function readString/gm, 'function readString')
|
|
310
|
-
.replace(/^export function readArray/gm, 'function readArray')
|
|
311
|
-
.replace(/^export function readValue/gm, 'function readValue');
|
|
312
|
-
|
|
313
|
-
const marshalCodeModule: any = {};
|
|
314
|
-
try {
|
|
315
|
-
const executeCode = new Function(
|
|
316
|
-
'module',
|
|
317
|
-
cleanedCode +
|
|
318
|
-
'\nmodule.marshalInput = marshalInput;\nmodule.unmarshalOutput = unmarshalOutput;\nmodule.readString = readString;\nmodule.readArray = readArray;\nmodule.readValue = readValue;',
|
|
319
|
-
);
|
|
320
|
-
executeCode(marshalCodeModule);
|
|
321
|
-
} catch (e: unknown) {
|
|
322
|
-
console.error('Generated marshal code:');
|
|
323
|
-
console.error(cleanedCode);
|
|
324
|
-
console.error('---');
|
|
325
|
-
throw e;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (!marshalCodeModule.marshalInput || !marshalCodeModule.unmarshalOutput) {
|
|
329
|
-
throw new Error('Failed to load marshal functions');
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// Allocate memory and marshal input
|
|
333
|
-
// Use manual Map marshaling for now since schema has no fixed-size fields
|
|
334
|
-
const inputAllocSize = 1024 * 128; // 128KB - increase for complex nested objects
|
|
335
|
-
|
|
336
|
-
// Ensure we have enough memory for:
|
|
337
|
-
// 1. AS runtime heap (0 - ~128KB depending on evaluation complexity)
|
|
338
|
-
// 2. Input data buffer at heapOffset (192KB) with inputAllocSize (128KB)
|
|
339
|
-
// 3. WASM custom heap for output marshaling (starts at 512KB in WASM code)
|
|
340
|
-
// 4. Output data (variable, but usually <100KB)
|
|
341
|
-
// Total: 512KB + 128KB = 640KB minimum, use 768KB for headroom
|
|
342
|
-
const requiredMemory = 768 * 1024;
|
|
343
|
-
ensureMemory(memory, requiredMemory);
|
|
344
|
-
|
|
345
|
-
const inputPtr = allocate(inputAllocSize);
|
|
346
|
-
marshalMapInput(input, memory, inputPtr);
|
|
347
|
-
|
|
348
|
-
const outputPtr = evaluate(inputPtr);
|
|
349
|
-
return (marshalCodeModule.unmarshalOutput as Function)(outputPtr, memory);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Infer a TypeBox schema from a value (runtime inference).
|
|
354
|
-
* Less type-safe than explicit schemas, but useful for porting existing tests.
|
|
355
|
-
*/
|
|
356
|
-
export function inferSchema(value: unknown): TSchema {
|
|
357
|
-
if (value === null) {
|
|
358
|
-
return { type: 'null' } as unknown as TSchema;
|
|
359
|
-
}
|
|
360
|
-
if (typeof value === 'boolean') {
|
|
361
|
-
return { type: 'boolean' } as unknown as TSchema;
|
|
362
|
-
}
|
|
363
|
-
if (typeof value === 'number') {
|
|
364
|
-
return { type: 'number' } as unknown as TSchema;
|
|
365
|
-
}
|
|
366
|
-
if (typeof value === 'string') {
|
|
367
|
-
return { type: 'string' } as unknown as TSchema;
|
|
368
|
-
}
|
|
369
|
-
if (Array.isArray(value)) {
|
|
370
|
-
if (value.length === 0) {
|
|
371
|
-
return { type: 'array', items: {} } as unknown as TSchema;
|
|
372
|
-
}
|
|
373
|
-
return { type: 'array', items: inferSchema(value[0]) } as unknown as TSchema;
|
|
374
|
-
}
|
|
375
|
-
if (typeof value === 'object') {
|
|
376
|
-
const properties: Record<string, unknown> = {};
|
|
377
|
-
for (const [key, val] of Object.entries(value)) {
|
|
378
|
-
properties[key] = inferSchema(val);
|
|
379
|
-
}
|
|
380
|
-
return { type: 'object', properties } as unknown as TSchema;
|
|
381
|
-
}
|
|
382
|
-
return {} as unknown as TSchema;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
/**
|
|
386
|
-
* Run a WASM-only test (no zen-engine comparison).
|
|
387
|
-
*/
|
|
388
|
-
export async function runWasmTest(config: WasmTestConfig): Promise<void> {
|
|
389
|
-
// Skip if tests reference unsupported features
|
|
390
|
-
if (config.unsupported?.length) {
|
|
391
|
-
console.log(`⏭️ Skipping ${config.name} (unsupported: ${config.unsupported.join(', ')})`);
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// Convert string JDM to object if needed
|
|
396
|
-
const jdmContent = typeof config.jdm === 'string' ? JSON.parse(config.jdm) : config.jdm;
|
|
397
|
-
|
|
398
|
-
type TestCase = {
|
|
399
|
-
input: Record<string, unknown>;
|
|
400
|
-
output: Record<string, unknown>;
|
|
401
|
-
};
|
|
402
|
-
|
|
403
|
-
type JDMWithTests = typeof jdmContent & { tests?: TestCase[] };
|
|
404
|
-
|
|
405
|
-
const jdm = jdmContent as JDMWithTests;
|
|
406
|
-
|
|
407
|
-
// If JDM has embedded tests array, use those
|
|
408
|
-
const testCases = jdm.tests
|
|
409
|
-
? jdm.tests
|
|
410
|
-
: config.input && config.expected
|
|
411
|
-
? [{ input: config.input, output: config.expected }]
|
|
412
|
-
: [];
|
|
413
|
-
|
|
414
|
-
if (testCases.length === 0) {
|
|
415
|
-
console.log(`⏭️ Skipping ${config.name} (no test cases)`);
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
// WASM compilation takes ~250ms per decision, so compiling once and reusing the module
|
|
420
|
-
// for all test cases dramatically speeds up test execution (seconds vs minutes).
|
|
421
|
-
let compiled: CompilationResult | null = null;
|
|
422
|
-
let compilationError: Error | null = null;
|
|
423
|
-
try {
|
|
424
|
-
compiled = await compileWasm({
|
|
425
|
-
jdm: config.jdm as any,
|
|
426
|
-
inputSchema: config.inputSchema,
|
|
427
|
-
outputSchema: config.outputSchema,
|
|
428
|
-
debug: true,
|
|
429
|
-
});
|
|
430
|
-
// Debug: dump generated code for specific tests
|
|
431
|
-
if (config.name.includes('customer-eligibility') && compiled.assemblyScript) {
|
|
432
|
-
require('fs').writeFileSync('/tmp/eligibility-debug.ts', compiled.assemblyScript);
|
|
433
|
-
}
|
|
434
|
-
} catch (error: unknown) {
|
|
435
|
-
compilationError = error instanceof Error ? error : new Error(String(error));
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
for (let i = 0; i < testCases.length; i++) {
|
|
439
|
-
const testCase = testCases[i];
|
|
440
|
-
const testName = jdm.tests ? `${config.name} [test ${i + 1}/${testCases.length}]` : config.name;
|
|
441
|
-
|
|
442
|
-
// Run with our implementation
|
|
443
|
-
try {
|
|
444
|
-
// Handle compilation errors
|
|
445
|
-
if (compilationError) {
|
|
446
|
-
const message = compilationError.message;
|
|
447
|
-
if (message.includes('Function node')) {
|
|
448
|
-
console.log(`⏭️ Skipping ${testName} (function node not yet supported)`);
|
|
449
|
-
continue;
|
|
450
|
-
} else if (message.includes('compile() not yet implemented')) {
|
|
451
|
-
console.log(`⏭️ Skipping ${testName} (compile() not yet implemented)`);
|
|
452
|
-
continue;
|
|
453
|
-
} else {
|
|
454
|
-
throw compilationError;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
const asmResult = await evaluateCompiled(compiled!, testCase.input);
|
|
459
|
-
|
|
460
|
-
// Compare against expected output - only check keys present in expected
|
|
461
|
-
expectPartialMatch(asmResult, testCase.output, `${testName} - jdm-asm mismatch`);
|
|
462
|
-
console.log(`✅ ${testName}`);
|
|
463
|
-
} catch (error: unknown) {
|
|
464
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
465
|
-
if (message.includes('Function node')) {
|
|
466
|
-
console.log(`⏭️ Skipping ${testName} (function node not yet supported)`);
|
|
467
|
-
} else if (message.includes('compile() not yet implemented')) {
|
|
468
|
-
console.log(`⏭️ Skipping ${testName} (compile() not yet implemented)`);
|
|
469
|
-
} else {
|
|
470
|
-
throw error;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
/**
|
|
477
|
-
* Convenience wrapper for WASM tests without explicit schemas.
|
|
478
|
-
* Infers schemas from the input/expected shapes.
|
|
479
|
-
*/
|
|
480
|
-
export async function runSimpleWasmTest(config: SimpleWasmTestConfig): Promise<void> {
|
|
481
|
-
const inputSchema = inferSchema(config.input || {});
|
|
482
|
-
const outputSchema = inferSchema(config.expected || {});
|
|
483
|
-
|
|
484
|
-
return runWasmTest({
|
|
485
|
-
...config,
|
|
486
|
-
inputSchema,
|
|
487
|
-
outputSchema,
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
/**
|
|
492
|
-
* Reusable WASM evaluator that pre-instantiates the module once.
|
|
493
|
-
* Use this for benchmarking hot path performance where WASM instantiation
|
|
494
|
-
* should not be included in the timing.
|
|
495
|
-
*/
|
|
496
|
-
export class ReusableWasmEvaluator {
|
|
497
|
-
private instance: WebAssembly.Instance | null = null;
|
|
498
|
-
private memory: WebAssembly.Memory | null = null;
|
|
499
|
-
private evaluate: ((ptr: number) => number) | null = null;
|
|
500
|
-
private collect: (() => void) | null = null;
|
|
501
|
-
private unmarshalOutput:
|
|
502
|
-
| ((ptr: number, memory: WebAssembly.Memory) => Record<string, unknown>)
|
|
503
|
-
| null = null;
|
|
504
|
-
private marshalMapInput:
|
|
505
|
-
| ((data: Record<string, unknown>, memory: WebAssembly.Memory, basePtr: number) => number)
|
|
506
|
-
| null = null;
|
|
507
|
-
|
|
508
|
-
constructor(private compiled: CompilationResult) {}
|
|
509
|
-
|
|
510
|
-
/**
|
|
511
|
-
* Initialize the WASM instance. Call this once before evaluating.
|
|
512
|
-
*/
|
|
513
|
-
async initialize(): Promise<void> {
|
|
514
|
-
if (this.instance !== null) {
|
|
515
|
-
return;
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// Instantiate WASM module
|
|
519
|
-
const wasmArray = new Uint8Array(this.compiled.wasm);
|
|
520
|
-
const buffer = wasmArray.buffer.slice(
|
|
521
|
-
wasmArray.byteOffset,
|
|
522
|
-
wasmArray.byteOffset + wasmArray.byteLength,
|
|
523
|
-
);
|
|
524
|
-
const wasmModule = await WebAssembly.compile(buffer as ArrayBuffer);
|
|
525
|
-
this.instance = await WebAssembly.instantiate(wasmModule, {
|
|
526
|
-
env: {
|
|
527
|
-
abort: () => {
|
|
528
|
-
throw new Error('WASM abort called');
|
|
529
|
-
},
|
|
530
|
-
'Date.now': () => Date.now(),
|
|
531
|
-
},
|
|
532
|
-
});
|
|
533
|
-
|
|
534
|
-
this.memory = this.instance.exports.memory as WebAssembly.Memory;
|
|
535
|
-
this.evaluate = this.instance.exports.evaluate as (ptr: number) => number;
|
|
536
|
-
this.collect = this.instance.exports.__collect as () => void;
|
|
537
|
-
|
|
538
|
-
// Load the generated marshal code
|
|
539
|
-
const cleanedCode = this.compiled.marshalCode
|
|
540
|
-
.replace(/^export function marshalInput/gm, 'function marshalInput')
|
|
541
|
-
.replace(/^export function unmarshalOutput/gm, 'function unmarshalOutput')
|
|
542
|
-
.replace(/^export function readString/gm, 'function readString')
|
|
543
|
-
.replace(/^export function readArray/gm, 'function readArray')
|
|
544
|
-
.replace(/^export function readValue/gm, 'function readValue');
|
|
545
|
-
|
|
546
|
-
const marshalCodeModule: any = {};
|
|
547
|
-
const executeCode = new Function(
|
|
548
|
-
'module',
|
|
549
|
-
cleanedCode +
|
|
550
|
-
'\nmodule.marshalInput = marshalInput;\nmodule.unmarshalOutput = unmarshalOutput;\nmodule.readString = readString;\nmodule.readArray = readArray;\nmodule.readValue = readValue;',
|
|
551
|
-
);
|
|
552
|
-
executeCode(marshalCodeModule);
|
|
553
|
-
|
|
554
|
-
this.unmarshalOutput = marshalCodeModule.unmarshalOutput;
|
|
555
|
-
|
|
556
|
-
// Create the marshalMapInput function (inline copy from evaluateCompiled)
|
|
557
|
-
this.marshalMapInput = this.createMarshalMapInput();
|
|
558
|
-
|
|
559
|
-
// Ensure enough memory
|
|
560
|
-
const requiredMemory = 768 * 1024;
|
|
561
|
-
ensureMemory(this.memory, requiredMemory);
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
/**
|
|
565
|
-
* Evaluate with the given input. The WASM instance is reused.
|
|
566
|
-
*/
|
|
567
|
-
run(input: Record<string, unknown>): Record<string, unknown> {
|
|
568
|
-
if (
|
|
569
|
-
!this.instance ||
|
|
570
|
-
!this.memory ||
|
|
571
|
-
!this.evaluate ||
|
|
572
|
-
!this.unmarshalOutput ||
|
|
573
|
-
!this.marshalMapInput
|
|
574
|
-
) {
|
|
575
|
-
throw new Error('ReusableWasmEvaluator not initialized. Call initialize() first.');
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
// Place input data at 640KB - after the custom heap region (512KB+)
|
|
579
|
-
// Memory layout:
|
|
580
|
-
// - Static data: 0 - ~50KB
|
|
581
|
-
// - AS runtime heap: ~50KB - 192KB (grows during evaluation, stub runtime has no GC)
|
|
582
|
-
// - Reserved: 192KB - 512KB
|
|
583
|
-
// - Custom heap (output): 512KB - 640KB
|
|
584
|
-
// - Input data: 640KB - 768KB
|
|
585
|
-
// The stub runtime heap grows without GC, so putting input above the output heap
|
|
586
|
-
// ensures no collision even after many evaluations.
|
|
587
|
-
const inputPtr = 640 * 1024;
|
|
588
|
-
|
|
589
|
-
this.marshalMapInput(input, this.memory, inputPtr);
|
|
590
|
-
const outputPtr = this.evaluate(inputPtr);
|
|
591
|
-
const result = this.unmarshalOutput(outputPtr, this.memory);
|
|
592
|
-
|
|
593
|
-
// Run garbage collection to free memory used during evaluation
|
|
594
|
-
// Without this, AS runtime heap grows until it conflicts with our input buffer
|
|
595
|
-
if (this.collect) {
|
|
596
|
-
this.collect();
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
return result;
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
/**
|
|
603
|
-
* Create the marshalMapInput function (same logic as in evaluateCompiled).
|
|
604
|
-
*/
|
|
605
|
-
private createMarshalMapInput(): (
|
|
606
|
-
data: Record<string, unknown>,
|
|
607
|
-
memory: WebAssembly.Memory,
|
|
608
|
-
basePtr: number,
|
|
609
|
-
) => number {
|
|
610
|
-
return (data: Record<string, unknown>, memory: WebAssembly.Memory, basePtr: number): number => {
|
|
611
|
-
const view = new DataView(memory.buffer);
|
|
612
|
-
const entries = Object.entries(data);
|
|
613
|
-
const length = entries.length;
|
|
614
|
-
|
|
615
|
-
// Write map length at basePtr
|
|
616
|
-
view.setUint32(basePtr, length, true);
|
|
617
|
-
|
|
618
|
-
// Allocate and write keys and values
|
|
619
|
-
let currentOffset = basePtr + 4 + length * 8; // Skip map structure
|
|
620
|
-
|
|
621
|
-
const writeValue = (value: unknown): number => {
|
|
622
|
-
// Returns pointer to a fully allocated Value structure
|
|
623
|
-
const valuePtr = currentOffset;
|
|
624
|
-
|
|
625
|
-
if (value === null || value === undefined) {
|
|
626
|
-
view.setUint32(valuePtr, 0, true); // TAG_NULL = 0
|
|
627
|
-
currentOffset += 4;
|
|
628
|
-
} else if (typeof value === 'boolean') {
|
|
629
|
-
view.setUint32(valuePtr, 1, true); // TAG_BOOLEAN = 1
|
|
630
|
-
view.setUint8(valuePtr + 4, value ? 1 : 0);
|
|
631
|
-
currentOffset += 5;
|
|
632
|
-
} else if (typeof value === 'number') {
|
|
633
|
-
view.setUint32(valuePtr, 3, true); // TAG_FLOAT = 3
|
|
634
|
-
view.setFloat64(valuePtr + 4, value, true);
|
|
635
|
-
currentOffset += 12;
|
|
636
|
-
} else if (typeof value === 'string') {
|
|
637
|
-
view.setUint32(valuePtr, 4, true); // TAG_STRING = 4
|
|
638
|
-
currentOffset += 8;
|
|
639
|
-
const stringDataPtr = currentOffset;
|
|
640
|
-
const len = value.length;
|
|
641
|
-
view.setUint32(stringDataPtr, len, true);
|
|
642
|
-
for (let i = 0; i < len; i++) {
|
|
643
|
-
view.setUint16(stringDataPtr + 4 + i * 2, value.charCodeAt(i), true);
|
|
644
|
-
}
|
|
645
|
-
currentOffset += 4 + len * 2;
|
|
646
|
-
view.setUint32(valuePtr + 4, stringDataPtr, true);
|
|
647
|
-
} else if (Array.isArray(value)) {
|
|
648
|
-
const arrLength = value.length;
|
|
649
|
-
currentOffset += 8;
|
|
650
|
-
const arrayPtr = currentOffset;
|
|
651
|
-
currentOffset += 4 + arrLength * 4;
|
|
652
|
-
view.setUint32(arrayPtr, arrLength, true);
|
|
653
|
-
let ptrOffset = arrayPtr + 4;
|
|
654
|
-
for (let i = 0; i < arrLength; i++) {
|
|
655
|
-
const elemPtr = writeValue(value[i]);
|
|
656
|
-
view.setUint32(ptrOffset, elemPtr, true);
|
|
657
|
-
ptrOffset += 4;
|
|
658
|
-
}
|
|
659
|
-
view.setUint32(valuePtr, 5, true); // TAG_ARRAY = 5
|
|
660
|
-
view.setUint32(valuePtr + 4, arrayPtr, true);
|
|
661
|
-
} else if (typeof value === 'object') {
|
|
662
|
-
const obj = value as Record<string, unknown>;
|
|
663
|
-
const objEntries = Object.entries(obj);
|
|
664
|
-
currentOffset += 8;
|
|
665
|
-
const mapPtr = currentOffset;
|
|
666
|
-
currentOffset += 4 + objEntries.length * 8;
|
|
667
|
-
view.setUint32(mapPtr, objEntries.length, true);
|
|
668
|
-
let ptrOffset = mapPtr + 4;
|
|
669
|
-
for (const [key, val] of objEntries) {
|
|
670
|
-
const keyStrPtr = currentOffset;
|
|
671
|
-
const keyLen = key.length;
|
|
672
|
-
view.setUint32(keyStrPtr, keyLen, true);
|
|
673
|
-
for (let i = 0; i < keyLen; i++) {
|
|
674
|
-
view.setUint16(keyStrPtr + 4 + i * 2, key.charCodeAt(i), true);
|
|
675
|
-
}
|
|
676
|
-
currentOffset += 4 + keyLen * 2;
|
|
677
|
-
view.setUint32(ptrOffset, keyStrPtr, true);
|
|
678
|
-
const nestedValuePtr = writeValue(val);
|
|
679
|
-
view.setUint32(ptrOffset + 4, nestedValuePtr, true);
|
|
680
|
-
ptrOffset += 8;
|
|
681
|
-
}
|
|
682
|
-
view.setUint32(valuePtr, 6, true); // TAG_OBJECT = 6
|
|
683
|
-
view.setUint32(valuePtr + 4, mapPtr, true);
|
|
684
|
-
} else {
|
|
685
|
-
throw new Error(`Unsupported type: ${typeof value}`);
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
return valuePtr;
|
|
689
|
-
};
|
|
690
|
-
|
|
691
|
-
let ptrOffset = basePtr + 4;
|
|
692
|
-
for (let i = 0; i < length; i++) {
|
|
693
|
-
const [key, value] = entries[i];
|
|
694
|
-
const keyStrPtr = currentOffset;
|
|
695
|
-
const keyLen = key.length;
|
|
696
|
-
view.setUint32(keyStrPtr, keyLen, true);
|
|
697
|
-
for (let j = 0; j < keyLen; j++) {
|
|
698
|
-
view.setUint16(keyStrPtr + 4 + j * 2, key.charCodeAt(j), true);
|
|
699
|
-
}
|
|
700
|
-
currentOffset += 4 + keyLen * 2;
|
|
701
|
-
const valuePtr = writeValue(value);
|
|
702
|
-
view.setUint32(ptrOffset, keyStrPtr, true);
|
|
703
|
-
view.setUint32(ptrOffset + 4, valuePtr, true);
|
|
704
|
-
ptrOffset += 8;
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
return basePtr;
|
|
708
|
-
};
|
|
709
|
-
}
|
|
710
|
-
}
|