@divmain/jdm-asm 0.2.0 → 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,999 +0,0 @@
|
|
|
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
|
-
}
|