redscript-mc 2.6.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +11 -0
- package/CHANGELOG.md +18 -9
- package/README-benchmarks.md +48 -0
- package/README-vscode-test.md +251 -0
- package/RELEASE_NOTES.md +74 -0
- package/ROADMAP.md +131 -167
- package/benchmarks/_shared.ts +468 -0
- package/benchmarks/baseline.json +2816 -0
- package/benchmarks/baseline.md +13 -0
- package/benchmarks/compiler-perf.report.json +207 -0
- package/benchmarks/compiler-perf.ts +76 -0
- package/benchmarks/results.md +13 -0
- package/benchmarks/stdlib-complexity.report.json +2606 -0
- package/benchmarks/stdlib-complexity.ts +54 -0
- package/benchmarks/stdlib-size.md +57 -0
- package/benchmarks/stdlib-size.ts +91 -0
- package/coverage-report.md +177 -0
- package/dist/src/__tests__/budget.test.js +4 -0
- package/dist/src/__tests__/cache/cache-behavior.test.d.ts +10 -0
- package/dist/src/__tests__/cache/cache-behavior.test.js +425 -0
- package/dist/src/__tests__/cache-extra.test.d.ts +5 -0
- package/dist/src/__tests__/cache-extra.test.js +211 -0
- package/dist/src/__tests__/cli-init.test.d.ts +1 -0
- package/dist/src/__tests__/cli-init.test.js +97 -0
- package/dist/src/__tests__/cli-publish.test.d.ts +9 -0
- package/dist/src/__tests__/cli-publish.test.js +189 -0
- package/dist/src/__tests__/cli.test.js +76 -0
- package/dist/src/__tests__/compile-preprocess.test.d.ts +11 -0
- package/dist/src/__tests__/compile-preprocess.test.js +328 -0
- package/dist/src/__tests__/compiler/break-stmt.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/break-stmt.test.js +58 -0
- package/dist/src/__tests__/compiler/const-decl.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/const-decl.test.js +123 -0
- package/dist/src/__tests__/compiler/continue-stmt.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/continue-stmt.test.js +67 -0
- package/dist/src/__tests__/compiler/coroutine-extended.test.d.ts +17 -0
- package/dist/src/__tests__/compiler/coroutine-extended.test.js +565 -0
- package/dist/src/__tests__/compiler/deprecated.test.d.ts +4 -0
- package/dist/src/__tests__/compiler/deprecated.test.js +285 -0
- package/dist/src/__tests__/compiler/do-while.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/do-while.test.js +120 -0
- package/dist/src/__tests__/compiler/enum-payload.test.d.ts +9 -0
- package/dist/src/__tests__/compiler/enum-payload.test.js +272 -0
- package/dist/src/__tests__/compiler/interface.test.d.ts +10 -0
- package/dist/src/__tests__/compiler/interface.test.js +258 -0
- package/dist/src/__tests__/compiler/labeled-loops.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/labeled-loops.test.js +263 -0
- package/dist/src/__tests__/compiler/match-string.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/match-string.test.js +43 -0
- package/dist/src/__tests__/compiler/memoize.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/memoize.test.js +113 -0
- package/dist/src/__tests__/compiler/method-chain.test.d.ts +5 -0
- package/dist/src/__tests__/compiler/method-chain.test.js +115 -0
- package/dist/src/__tests__/compiler/module-import.test.d.ts +12 -0
- package/dist/src/__tests__/compiler/module-import.test.js +261 -0
- package/dist/src/__tests__/compiler/option-extensions.test.d.ts +6 -0
- package/dist/src/__tests__/compiler/option-extensions.test.js +191 -0
- package/dist/src/__tests__/compiler/profile-decorator.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/profile-decorator.test.js +69 -0
- package/dist/src/__tests__/compiler/string-advanced.test.d.ts +7 -0
- package/dist/src/__tests__/compiler/string-advanced.test.js +281 -0
- package/dist/src/__tests__/compiler/struct-extends.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/struct-extends.test.js +95 -0
- package/dist/src/__tests__/compiler/throttle-retry.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/throttle-retry.test.js +166 -0
- package/dist/src/__tests__/compiler/tuple-type.test.d.ts +10 -0
- package/dist/src/__tests__/compiler/tuple-type.test.js +229 -0
- package/dist/src/__tests__/compiler/watch-decorator.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/watch-decorator.test.js +65 -0
- package/dist/src/__tests__/config/project-config.test.d.ts +1 -0
- package/dist/src/__tests__/config/project-config.test.js +199 -0
- package/dist/src/__tests__/config-decorator.test.d.ts +8 -0
- package/dist/src/__tests__/config-decorator.test.js +142 -0
- package/dist/src/__tests__/diagnostics-extra.test.d.ts +6 -0
- package/dist/src/__tests__/diagnostics-extra.test.js +132 -0
- package/dist/src/__tests__/emit/compile-branches.test.d.ts +1 -0
- package/dist/src/__tests__/emit/compile-branches.test.js +123 -0
- package/dist/src/__tests__/emit/compile-coverage.test.d.ts +25 -0
- package/dist/src/__tests__/emit/compile-coverage.test.js +617 -0
- package/dist/src/__tests__/emit/compile-extra-branches.test.d.ts +12 -0
- package/dist/src/__tests__/emit/compile-extra-branches.test.js +225 -0
- package/dist/src/__tests__/emit/compile-mocked-branches.test.d.ts +0 -0
- package/dist/src/__tests__/emit/compile-mocked-branches.test.js +238 -0
- package/dist/src/__tests__/emit/execute-chain.test.d.ts +10 -0
- package/dist/src/__tests__/emit/execute-chain.test.js +94 -0
- package/dist/src/__tests__/emit/index.test.js +2 -1
- package/dist/src/__tests__/emit/modules-branches.test.d.ts +1 -0
- package/dist/src/__tests__/emit/modules-branches.test.js +88 -0
- package/dist/src/__tests__/emit/modules-coverage.test.d.ts +15 -0
- package/dist/src/__tests__/emit/modules-coverage.test.js +221 -0
- package/dist/src/__tests__/emit/modules-errors.test.d.ts +12 -0
- package/dist/src/__tests__/emit/modules-errors.test.js +169 -0
- package/dist/src/__tests__/emit/modules-rewrite.test.d.ts +17 -0
- package/dist/src/__tests__/emit/modules-rewrite.test.js +204 -0
- package/dist/src/__tests__/emit/source-map.test.d.ts +1 -0
- package/dist/src/__tests__/emit/source-map.test.js +167 -0
- package/dist/src/__tests__/enum.test.js +9 -4
- package/dist/src/__tests__/error-recovery.test.d.ts +7 -0
- package/dist/src/__tests__/error-recovery.test.js +217 -0
- package/dist/src/__tests__/events-types-extra.test.d.ts +10 -0
- package/dist/src/__tests__/events-types-extra.test.js +91 -0
- package/dist/src/__tests__/events-types.test.d.ts +4 -0
- package/dist/src/__tests__/events-types.test.js +56 -0
- package/dist/src/__tests__/formatter.test.js +13 -5
- package/dist/src/__tests__/hir/lower-extra.test.d.ts +9 -0
- package/dist/src/__tests__/hir/lower-extra.test.js +140 -0
- package/dist/src/__tests__/hir/monomorphize-extra.test.d.ts +15 -0
- package/dist/src/__tests__/hir/monomorphize-extra.test.js +200 -0
- package/dist/src/__tests__/hir/monomorphize-extra2.test.d.ts +16 -0
- package/dist/src/__tests__/hir/monomorphize-extra2.test.js +316 -0
- package/dist/src/__tests__/incremental.test.js +10 -2
- package/dist/src/__tests__/index-extra.test.d.ts +10 -0
- package/dist/src/__tests__/index-extra.test.js +71 -0
- package/dist/src/__tests__/lexer.test.js +2 -2
- package/dist/src/__tests__/lint/rules.test.d.ts +5 -0
- package/dist/src/__tests__/lint/rules.test.js +208 -0
- package/dist/src/__tests__/lir/lower.test.js +29 -0
- package/dist/src/__tests__/lir/verify.test.js +30 -0
- package/dist/src/__tests__/lsp/completion.test.d.ts +7 -0
- package/dist/src/__tests__/lsp/completion.test.js +583 -0
- package/dist/src/__tests__/lsp/definition.test.d.ts +7 -0
- package/dist/src/__tests__/lsp/definition.test.js +454 -0
- package/dist/src/__tests__/lsp/diagnostics.test.d.ts +10 -0
- package/dist/src/__tests__/lsp/diagnostics.test.js +98 -0
- package/dist/src/__tests__/lsp/hover-docs.test.d.ts +10 -0
- package/dist/src/__tests__/lsp/hover-docs.test.js +210 -0
- package/dist/src/__tests__/lsp.test.js +4 -1
- package/dist/src/__tests__/mc-integration/item-entity-events.test.js +4 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-2.test.js +4 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-3.test.d.ts +13 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-3.test.js +1227 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-4.test.d.ts +13 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-4.test.js +1509 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-5.test.d.ts +14 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-5.test.js +1374 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-6.test.d.ts +10 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-6.test.js +759 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-7.test.d.ts +13 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-7.test.js +855 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage.test.js +4 -0
- package/dist/src/__tests__/mc-integration/syntax-coverage.test.js +4 -0
- package/dist/src/__tests__/mc-validator-coverage.test.d.ts +13 -0
- package/dist/src/__tests__/mc-validator-coverage.test.js +296 -0
- package/dist/src/__tests__/mc-validator-extra.test.d.ts +13 -0
- package/dist/src/__tests__/mc-validator-extra.test.js +245 -0
- package/dist/src/__tests__/mir/lower-extra.test.d.ts +20 -0
- package/dist/src/__tests__/mir/lower-extra.test.js +361 -0
- package/dist/src/__tests__/mir/lower-extra2.test.d.ts +17 -0
- package/dist/src/__tests__/mir/lower-extra2.test.js +317 -0
- package/dist/src/__tests__/mir/lower-extra3.test.d.ts +19 -0
- package/dist/src/__tests__/mir/lower-extra3.test.js +249 -0
- package/dist/src/__tests__/mir/lower-extra4.test.d.ts +23 -0
- package/dist/src/__tests__/mir/lower-extra4.test.js +606 -0
- package/dist/src/__tests__/mir/lower-extra5.test.d.ts +25 -0
- package/dist/src/__tests__/mir/lower-extra5.test.js +543 -0
- package/dist/src/__tests__/mir/lower-extra6.test.d.ts +16 -0
- package/dist/src/__tests__/mir/lower-extra6.test.js +471 -0
- package/dist/src/__tests__/mir/lower-extra7.test.d.ts +35 -0
- package/dist/src/__tests__/mir/lower-extra7.test.js +921 -0
- package/dist/src/__tests__/mir/lower-extra8.test.d.ts +19 -0
- package/dist/src/__tests__/mir/lower-extra8.test.js +626 -0
- package/dist/src/__tests__/mir/lower-extra9.test.d.ts +14 -0
- package/dist/src/__tests__/mir/lower-extra9.test.js +717 -0
- package/dist/src/__tests__/optimizer/auto-inline.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/auto-inline.test.js +176 -0
- package/dist/src/__tests__/optimizer/cse.test.d.ts +4 -0
- package/dist/src/__tests__/optimizer/cse.test.js +178 -0
- package/dist/src/__tests__/optimizer/inline_fn.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/inline_fn.test.js +221 -0
- package/dist/src/__tests__/optimizer/licm.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/licm.test.js +244 -0
- package/dist/src/__tests__/optimizer/optimizer-extended.test.d.ts +12 -0
- package/dist/src/__tests__/optimizer/optimizer-extended.test.js +993 -0
- package/dist/src/__tests__/optimizer/strength-reduction.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/strength-reduction.test.js +86 -0
- package/dist/src/__tests__/optimizer/tco.test.d.ts +14 -0
- package/dist/src/__tests__/optimizer/tco.test.js +203 -0
- package/dist/src/__tests__/parser-coverage.test.d.ts +25 -0
- package/dist/src/__tests__/parser-coverage.test.js +491 -0
- package/dist/src/__tests__/parser-extra.test.d.ts +6 -0
- package/dist/src/__tests__/parser-extra.test.js +451 -0
- package/dist/src/__tests__/parser.test.js +12 -0
- package/dist/src/__tests__/repl-extra.test.d.ts +13 -0
- package/dist/src/__tests__/repl-extra.test.js +174 -0
- package/dist/src/__tests__/repl-server-extra.test.d.ts +10 -0
- package/dist/src/__tests__/repl-server-extra.test.js +161 -0
- package/dist/src/__tests__/repl-server.test.d.ts +6 -0
- package/dist/src/__tests__/repl-server.test.js +146 -0
- package/dist/src/__tests__/runtime-extra.test.d.ts +15 -0
- package/dist/src/__tests__/runtime-extra.test.js +732 -0
- package/dist/src/__tests__/singleton-decorator.test.d.ts +11 -0
- package/dist/src/__tests__/singleton-decorator.test.js +260 -0
- package/dist/src/__tests__/sourcemap.test.js +1 -1
- package/dist/src/__tests__/stdlib/advanced.test.d.ts +5 -0
- package/dist/src/__tests__/stdlib/advanced.test.js +301 -0
- package/dist/src/__tests__/stdlib/bigint.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/bigint.test.js +83 -0
- package/dist/src/__tests__/stdlib/bits.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/bits.test.js +96 -0
- package/dist/src/__tests__/stdlib/bossbar.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/bossbar.test.js +72 -0
- package/dist/src/__tests__/stdlib/color.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/color.test.js +84 -0
- package/dist/src/__tests__/stdlib/combat.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/combat.test.js +64 -0
- package/dist/src/__tests__/stdlib/cooldown.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/cooldown.test.js +64 -0
- package/dist/src/__tests__/stdlib/dialog.test.js +15 -7
- package/dist/src/__tests__/stdlib/ecs.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/ecs.test.js +81 -0
- package/dist/src/__tests__/stdlib/effects.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/effects.test.js +72 -0
- package/dist/src/__tests__/stdlib/events.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/events.test.js +55 -0
- package/dist/src/__tests__/stdlib/expr.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/expr.test.js +77 -0
- package/dist/src/__tests__/stdlib/fft.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/fft.test.js +82 -0
- package/dist/src/__tests__/stdlib/graph.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/graph.test.js +102 -0
- package/dist/src/__tests__/stdlib/interactions.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/interactions.test.js +60 -0
- package/dist/src/__tests__/stdlib/inventory.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/inventory.test.js +68 -0
- package/dist/src/__tests__/stdlib/linalg.test.d.ts +5 -0
- package/dist/src/__tests__/stdlib/linalg.test.js +78 -0
- package/dist/src/__tests__/stdlib/map.test.d.ts +1 -0
- package/dist/src/__tests__/stdlib/map.test.js +84 -0
- package/dist/src/__tests__/stdlib/math.test.js +19 -6
- package/dist/src/__tests__/stdlib/math_hp.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/math_hp.test.js +80 -0
- package/dist/src/__tests__/stdlib/mobs.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/mobs.test.js +61 -0
- package/dist/src/__tests__/stdlib/noise.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/noise.test.js +73 -0
- package/dist/src/__tests__/stdlib/ode.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/ode.test.js +68 -0
- package/dist/src/__tests__/stdlib/parabola.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/parabola.test.js +77 -0
- package/dist/src/__tests__/stdlib/particles.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/particles.test.js +68 -0
- package/dist/src/__tests__/stdlib/physics.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/physics.test.js +76 -0
- package/dist/src/__tests__/stdlib/player.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/player.test.js +64 -0
- package/dist/src/__tests__/stdlib/quaternion.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/quaternion.test.js +73 -0
- package/dist/src/__tests__/stdlib/queue.test.d.ts +1 -0
- package/dist/src/__tests__/stdlib/queue.test.js +97 -0
- package/dist/src/__tests__/stdlib/random.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/random.test.js +76 -0
- package/dist/src/__tests__/stdlib/result.test.d.ts +12 -0
- package/dist/src/__tests__/stdlib/result.test.js +329 -0
- package/dist/src/__tests__/stdlib/scheduler.test.js +19 -8
- package/dist/src/__tests__/stdlib/set_int.test.d.ts +1 -0
- package/dist/src/__tests__/stdlib/set_int.test.js +88 -0
- package/dist/src/__tests__/stdlib/sets.test.d.ts +6 -0
- package/dist/src/__tests__/stdlib/sets.test.js +60 -0
- package/dist/src/__tests__/stdlib/signal.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/signal.test.js +84 -0
- package/dist/src/__tests__/stdlib/spawn.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/spawn.test.js +68 -0
- package/dist/src/__tests__/stdlib/string.test.d.ts +12 -0
- package/dist/src/__tests__/stdlib/string.test.js +231 -0
- package/dist/src/__tests__/stdlib/strings.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/strings.test.js +83 -0
- package/dist/src/__tests__/stdlib/tags.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/tags.test.js +57 -0
- package/dist/src/__tests__/stdlib/teams.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/teams.test.js +72 -0
- package/dist/src/__tests__/stdlib/timer.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/timer.test.js +79 -0
- package/dist/src/__tests__/stdlib/vec.test.d.ts +5 -0
- package/dist/src/__tests__/stdlib/vec.test.js +94 -0
- package/dist/src/__tests__/stdlib/world.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/world.test.js +72 -0
- package/dist/src/__tests__/struct-display.test.d.ts +1 -0
- package/dist/src/__tests__/struct-display.test.js +64 -0
- package/dist/src/__tests__/test-framework/runner.test.d.ts +10 -0
- package/dist/src/__tests__/test-framework/runner.test.js +193 -0
- package/dist/src/__tests__/tuner/adapters.test.d.ts +14 -0
- package/dist/src/__tests__/tuner/adapters.test.js +194 -0
- package/dist/src/__tests__/tuner/simulator-extra.test.d.ts +4 -0
- package/dist/src/__tests__/tuner/simulator-extra.test.js +193 -0
- package/dist/src/__tests__/typechecker-coverage.test.d.ts +30 -0
- package/dist/src/__tests__/typechecker-coverage.test.js +627 -0
- package/dist/src/__tests__/typechecker.test.js +3 -3
- package/dist/src/__tests__/watch-decorator.test.d.ts +1 -0
- package/dist/src/__tests__/watch-decorator.test.js +54 -0
- package/dist/src/ast/types.d.ts +102 -3
- package/dist/src/cache/incremental.d.ts +13 -14
- package/dist/src/cache/incremental.js +106 -89
- package/dist/src/cache/index.d.ts +8 -2
- package/dist/src/cache/index.js +18 -6
- package/dist/src/cli.d.ts +1 -0
- package/dist/src/cli.js +466 -17
- package/dist/src/config/project-config.d.ts +29 -0
- package/dist/src/config/project-config.js +180 -0
- package/dist/src/diagnostics/index.d.ts +9 -0
- package/dist/src/diagnostics/index.js +18 -1
- package/dist/src/emit/compile.d.ts +10 -0
- package/dist/src/emit/compile.js +395 -50
- package/dist/src/emit/index.d.ts +40 -0
- package/dist/src/emit/index.js +307 -14
- package/dist/src/emit/modules.js +21 -3
- package/dist/src/emit/sourcemap.d.ts +23 -27
- package/dist/src/emit/sourcemap.js +52 -30
- package/dist/src/formatter/index.js +33 -8
- package/dist/src/hir/deprecated.d.ts +13 -0
- package/dist/src/hir/deprecated.js +218 -0
- package/dist/src/hir/lower.js +114 -8
- package/dist/src/hir/monomorphize.js +22 -2
- package/dist/src/hir/types.d.ts +65 -1
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.js +18 -3
- package/dist/src/lexer/index.d.ts +2 -1
- package/dist/src/lexer/index.js +39 -3
- package/dist/src/lint/index.d.ts +45 -0
- package/dist/src/lint/index.js +930 -0
- package/dist/src/lir/lower.js +29 -2
- package/dist/src/lir/types.d.ts +2 -0
- package/dist/src/lsp/server.js +92 -5
- package/dist/src/mir/lower.js +775 -34
- package/dist/src/mir/macro.js +36 -2
- package/dist/src/mir/types.d.ts +12 -0
- package/dist/src/mir/verify.js +9 -0
- package/dist/src/optimizer/auto-inline.d.ts +2 -0
- package/dist/src/optimizer/auto-inline.js +67 -0
- package/dist/src/optimizer/cse.d.ts +20 -0
- package/dist/src/optimizer/cse.js +234 -0
- package/dist/src/optimizer/inline.d.ts +26 -0
- package/dist/src/optimizer/inline.js +286 -0
- package/dist/src/optimizer/interprocedural.js +4 -0
- package/dist/src/optimizer/licm.d.ts +32 -0
- package/dist/src/optimizer/licm.js +371 -0
- package/dist/src/optimizer/pipeline.js +12 -2
- package/dist/src/optimizer/strength_reduction.d.ts +15 -0
- package/dist/src/optimizer/strength_reduction.js +90 -0
- package/dist/src/optimizer/tco.d.ts +53 -0
- package/dist/src/optimizer/tco.js +238 -0
- package/dist/src/parser/index.d.ts +32 -0
- package/dist/src/parser/index.js +421 -59
- package/dist/src/repl-server.d.ts +13 -0
- package/dist/src/repl-server.js +127 -0
- package/dist/src/structs/expand.d.ts +15 -0
- package/dist/src/structs/expand.js +46 -0
- package/dist/src/testing/runner.d.ts +40 -0
- package/dist/src/testing/runner.js +237 -0
- package/dist/src/typechecker/index.d.ts +3 -0
- package/dist/src/typechecker/index.js +254 -9
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/doc-drafts/redscript-docs/docs/en/stdlib/graph.md +104 -0
- package/doc-drafts/redscript-docs/docs/en/stdlib/parabola.md +113 -0
- package/doc-drafts/redscript-docs/docs/en/stdlib/pathfind.md +104 -0
- package/doc-drafts/redscript-docs/docs/en/stdlib/physics.md +134 -0
- package/doc-drafts/redscript-docs/docs/en/stdlib/quaternion.md +135 -0
- package/doc-drafts/redscript-docs/docs/zh/stdlib/graph.md +104 -0
- package/doc-drafts/redscript-docs/docs/zh/stdlib/parabola.md +113 -0
- package/doc-drafts/redscript-docs/docs/zh/stdlib/pathfind.md +104 -0
- package/doc-drafts/redscript-docs/docs/zh/stdlib/physics.md +134 -0
- package/doc-drafts/redscript-docs/docs/zh/stdlib/quaternion.md +135 -0
- package/docs/stdlib/result.md +156 -0
- package/docs/stdlib/result.zh.md +156 -0
- package/editors/vscode/fixtures/test.mcrs +7 -0
- package/editors/vscode/out/extension.js +2095 -225
- package/editors/vscode/out/lsp-server.js +519 -51
- package/editors/vscode/package-lock.json +9 -4
- package/editors/vscode/package.json +1 -1
- package/examples/display-demo.mcrs +64 -0
- package/examples/game/racing.mcrs +301 -0
- package/examples/game/tower_defense.mcrs +311 -0
- package/examples/math/physics_sim.mcrs +322 -0
- package/examples/rpg/boss_fight.mcrs +313 -0
- package/examples/rpg/health_system.mcrs +237 -0
- package/examples/rpg/inventory.mcrs +265 -0
- package/examples/util/debug_hud.mcrs +279 -0
- package/jest.config.js +10 -0
- package/package.json +12 -3
- package/playground/index.html +823 -0
- package/scripts/gen-docs.ts +533 -0
- package/scripts/update-redscript-docs-stdlib.sh +770 -0
- package/src/__tests__/budget.test.ts +5 -0
- package/src/__tests__/cache/cache-behavior.test.ts +480 -0
- package/src/__tests__/cache-extra.test.ts +199 -0
- package/src/__tests__/cli-docs.test.ts +77 -0
- package/src/__tests__/cli-init.test.ts +91 -0
- package/src/__tests__/cli-publish.test.ts +190 -0
- package/src/__tests__/cli.test.ts +117 -1
- package/src/__tests__/compile-preprocess.test.ts +366 -0
- package/src/__tests__/compiler/break-stmt.test.ts +66 -0
- package/src/__tests__/compiler/const-decl.test.ts +141 -0
- package/src/__tests__/compiler/continue-stmt.test.ts +81 -0
- package/src/__tests__/compiler/coroutine-extended.test.ts +723 -0
- package/src/__tests__/compiler/deprecated.test.ts +305 -0
- package/src/__tests__/compiler/do-while.test.ts +130 -0
- package/src/__tests__/compiler/enum-payload.test.ts +299 -0
- package/src/__tests__/compiler/interface.test.ts +287 -0
- package/src/__tests__/compiler/labeled-loops.test.ts +279 -0
- package/src/__tests__/compiler/match-string.test.ts +45 -0
- package/src/__tests__/compiler/memoize.test.ts +126 -0
- package/src/__tests__/compiler/method-chain.test.ts +121 -0
- package/src/__tests__/compiler/module-import.test.ts +240 -0
- package/src/__tests__/compiler/option-extensions.test.ts +207 -0
- package/src/__tests__/compiler/profile-decorator.test.ts +79 -0
- package/src/__tests__/compiler/string-advanced.test.ts +310 -0
- package/src/__tests__/compiler/struct-extends.test.ts +109 -0
- package/src/__tests__/compiler/throttle-retry.test.ts +191 -0
- package/src/__tests__/compiler/tuple-type.test.ts +263 -0
- package/src/__tests__/compiler/watch-decorator.test.ts +72 -0
- package/src/__tests__/config/project-config.test.ts +181 -0
- package/src/__tests__/config-decorator.test.ts +157 -0
- package/src/__tests__/diagnostics-extra.test.ts +155 -0
- package/src/__tests__/emit/compile-branches.test.ts +135 -0
- package/src/__tests__/emit/compile-coverage.test.ts +696 -0
- package/src/__tests__/emit/compile-extra-branches.test.ts +228 -0
- package/src/__tests__/emit/compile-mocked-branches.test.ts +249 -0
- package/src/__tests__/emit/compile.test.ts +6 -1
- package/src/__tests__/emit/execute-chain.test.ts +114 -0
- package/src/__tests__/emit/index.test.ts +2 -1
- package/src/__tests__/emit/modules-branches.test.ts +90 -0
- package/src/__tests__/emit/modules-coverage.test.ts +241 -0
- package/src/__tests__/emit/modules-errors.test.ts +192 -0
- package/src/__tests__/emit/modules-rewrite.test.ts +232 -0
- package/src/__tests__/emit/source-map.test.ts +152 -0
- package/src/__tests__/enum.test.ts +9 -4
- package/src/__tests__/error-recovery.test.ts +226 -0
- package/src/__tests__/events-types-extra.test.ts +110 -0
- package/src/__tests__/events-types.test.ts +66 -0
- package/src/__tests__/formatter.test.ts +15 -5
- package/src/__tests__/generics.test.ts +16 -9
- package/src/__tests__/hir/lower-extra.test.ts +151 -0
- package/src/__tests__/hir/monomorphize-coverage.test.ts +432 -0
- package/src/__tests__/hir/monomorphize-extra.test.ts +220 -0
- package/src/__tests__/hir/monomorphize-extra2.test.ts +350 -0
- package/src/__tests__/impl.test.ts +12 -8
- package/src/__tests__/incremental.test.ts +10 -2
- package/src/__tests__/index-extra.test.ts +79 -0
- package/src/__tests__/lexer.test.ts +2 -2
- package/src/__tests__/lint/hir-coverage.test.ts +1716 -0
- package/src/__tests__/lint/rules-coverage.test.ts +598 -0
- package/src/__tests__/lint/rules.test.ts +230 -0
- package/src/__tests__/lir/lower.test.ts +33 -0
- package/src/__tests__/lir/verify.test.ts +33 -0
- package/src/__tests__/lsp/completion.test.ts +687 -0
- package/src/__tests__/lsp/definition.test.ts +499 -0
- package/src/__tests__/lsp/diagnostics.test.ts +108 -0
- package/src/__tests__/lsp/hover-docs.test.ts +222 -0
- package/src/__tests__/lsp.test.ts +4 -1
- package/src/__tests__/mc-integration/item-entity-events.test.ts +5 -0
- package/src/__tests__/mc-integration/stdlib-coverage-2.test.ts +5 -0
- package/src/__tests__/mc-integration/stdlib-coverage-3.test.ts +1105 -0
- package/src/__tests__/mc-integration/stdlib-coverage-4.test.ts +1366 -0
- package/src/__tests__/mc-integration/stdlib-coverage-5.test.ts +1245 -0
- package/src/__tests__/mc-integration/stdlib-coverage-6.test.ts +755 -0
- package/src/__tests__/mc-integration/stdlib-coverage-7.test.ts +771 -0
- package/src/__tests__/mc-integration/stdlib-coverage.test.ts +5 -0
- package/src/__tests__/mc-integration/syntax-coverage.test.ts +5 -0
- package/src/__tests__/mc-validator-coverage.test.ts +325 -0
- package/src/__tests__/mc-validator-extra.test.ts +252 -0
- package/src/__tests__/mir/lower-extra.test.ts +402 -0
- package/src/__tests__/mir/lower-extra2.test.ts +348 -0
- package/src/__tests__/mir/lower-extra3.test.ts +277 -0
- package/src/__tests__/mir/lower-extra4.test.ts +636 -0
- package/src/__tests__/mir/lower-extra5.test.ts +612 -0
- package/src/__tests__/mir/lower-extra6.test.ts +520 -0
- package/src/__tests__/mir/lower-extra7.test.ts +1045 -0
- package/src/__tests__/mir/lower-extra8.test.ts +704 -0
- package/src/__tests__/mir/lower-extra9.test.ts +821 -0
- package/src/__tests__/optimizer/auto-inline.test.ts +206 -0
- package/src/__tests__/optimizer/cse.test.ts +195 -0
- package/src/__tests__/optimizer/inline_fn.test.ts +263 -0
- package/src/__tests__/optimizer/licm.test.ts +358 -0
- package/src/__tests__/optimizer/nbt-coalesce.test.ts +147 -0
- package/src/__tests__/optimizer/optimizer-extended.test.ts +1081 -0
- package/src/__tests__/optimizer/scoreboard-batch.test.ts +141 -0
- package/src/__tests__/optimizer/strength-reduction.test.ts +111 -0
- package/src/__tests__/optimizer/tco-coverage.test.ts +309 -0
- package/src/__tests__/optimizer/tco.test.ts +238 -0
- package/src/__tests__/option.test.ts +14 -7
- package/src/__tests__/parser-coverage.test.ts +576 -0
- package/src/__tests__/parser-extra.test.ts +531 -0
- package/src/__tests__/parser.test.ts +14 -0
- package/src/__tests__/repl-extra.test.ts +195 -0
- package/src/__tests__/repl-server-extra.test.ts +150 -0
- package/src/__tests__/repl-server.test.ts +122 -0
- package/src/__tests__/runtime-extra.test.ts +862 -0
- package/src/__tests__/singleton-decorator.test.ts +285 -0
- package/src/__tests__/sourcemap.test.ts +1 -1
- package/src/__tests__/stdlib/advanced.test.ts +312 -0
- package/src/__tests__/stdlib/bigint.test.ts +57 -0
- package/src/__tests__/stdlib/bits.test.ts +75 -0
- package/src/__tests__/stdlib/bossbar.test.ts +45 -0
- package/src/__tests__/stdlib/color.test.ts +60 -0
- package/src/__tests__/stdlib/combat.test.ts +35 -0
- package/src/__tests__/stdlib/cooldown.test.ts +35 -0
- package/src/__tests__/stdlib/dialog.test.ts +14 -6
- package/src/__tests__/stdlib/ecs.test.ts +54 -0
- package/src/__tests__/stdlib/effects.test.ts +45 -0
- package/src/__tests__/stdlib/events.test.ts +23 -0
- package/src/__tests__/stdlib/expr.test.ts +48 -0
- package/src/__tests__/stdlib/fft.test.ts +54 -0
- package/src/__tests__/stdlib/graph.test.ts +77 -0
- package/src/__tests__/stdlib/interactions.test.ts +30 -0
- package/src/__tests__/stdlib/inventory.test.ts +40 -0
- package/src/__tests__/stdlib/linalg.test.ts +52 -0
- package/src/__tests__/stdlib/map.test.ts +55 -0
- package/src/__tests__/stdlib/math.test.ts +19 -5
- package/src/__tests__/stdlib/math_hp.test.ts +55 -0
- package/src/__tests__/stdlib/mobs.test.ts +40 -0
- package/src/__tests__/stdlib/noise.test.ts +46 -0
- package/src/__tests__/stdlib/ode.test.ts +40 -0
- package/src/__tests__/stdlib/parabola.test.ts +51 -0
- package/src/__tests__/stdlib/particles.test.ts +40 -0
- package/src/__tests__/stdlib/physics.test.ts +50 -0
- package/src/__tests__/stdlib/player.test.ts +35 -0
- package/src/__tests__/stdlib/quaternion.test.ts +46 -0
- package/src/__tests__/stdlib/queue.test.ts +73 -0
- package/src/__tests__/stdlib/random.test.ts +50 -0
- package/src/__tests__/stdlib/result.test.ts +326 -0
- package/src/__tests__/stdlib/scheduler.test.ts +18 -7
- package/src/__tests__/stdlib/set_int.test.ts +62 -0
- package/src/__tests__/stdlib/sets.test.ts +28 -0
- package/src/__tests__/stdlib/signal.test.ts +60 -0
- package/src/__tests__/stdlib/spawn.test.ts +40 -0
- package/src/__tests__/stdlib/string.test.ts +224 -0
- package/src/__tests__/stdlib/strings.test.ts +55 -0
- package/src/__tests__/stdlib/tags.test.ts +32 -0
- package/src/__tests__/stdlib/teams.test.ts +45 -0
- package/src/__tests__/stdlib/timer.test.ts +53 -0
- package/src/__tests__/stdlib/vec.test.ts +72 -0
- package/src/__tests__/stdlib/world.test.ts +45 -0
- package/src/__tests__/struct-display.test.ts +69 -0
- package/src/__tests__/test-framework/runner.test.ts +208 -0
- package/src/__tests__/tuner/adapters.test.ts +232 -0
- package/src/__tests__/tuner/simulator-extra.test.ts +222 -0
- package/src/__tests__/tuple.test.ts +11 -4
- package/src/__tests__/typechecker-coverage.test.ts +671 -0
- package/src/__tests__/typechecker.test.ts +4 -3
- package/src/__tests__/watch-decorator.test.ts +59 -0
- package/src/ast/types.ts +65 -3
- package/src/cache/incremental.ts +128 -99
- package/src/cache/index.ts +35 -8
- package/src/cli.ts +538 -29
- package/src/config/project-config.ts +176 -0
- package/src/diagnostics/index.ts +22 -0
- package/src/docs.ts +98 -0
- package/src/emit/compile.ts +408 -51
- package/src/emit/index.ts +366 -18
- package/src/emit/modules.ts +19 -3
- package/src/emit/sourcemap.ts +64 -43
- package/src/formatter/index.ts +35 -8
- package/src/hir/deprecated.ts +212 -0
- package/src/hir/lower.ts +128 -8
- package/src/hir/monomorphize.ts +24 -2
- package/src/hir/types.ts +26 -1
- package/src/index.ts +23 -3
- package/src/lexer/index.ts +45 -6
- package/src/lint/index.ts +922 -0
- package/src/lir/lower.ts +30 -2
- package/src/lir/types.ts +4 -0
- package/src/lsp/server.ts +100 -1
- package/src/mir/lower.ts +785 -40
- package/src/mir/macro.ts +30 -2
- package/src/mir/types.ts +13 -0
- package/src/mir/verify.ts +10 -2
- package/src/optimizer/auto-inline.ts +86 -0
- package/src/optimizer/copy_prop.ts +2 -2
- package/src/optimizer/coroutine.ts +3 -3
- package/src/optimizer/cse.ts +205 -0
- package/src/optimizer/dce.ts +2 -2
- package/src/optimizer/inline.ts +335 -0
- package/src/optimizer/interprocedural.ts +5 -1
- package/src/optimizer/licm.ts +454 -0
- package/src/optimizer/nbt-coalesce.ts +109 -0
- package/src/optimizer/pipeline.ts +16 -2
- package/src/optimizer/scoreboard-batch.ts +52 -0
- package/src/optimizer/strength_reduction.ts +95 -0
- package/src/optimizer/tco.ts +267 -0
- package/src/optimizer/unroll.ts +2 -2
- package/src/parser/index.ts +426 -53
- package/src/repl-server.ts +102 -0
- package/src/stdlib/advanced.mcrs +271 -101
- package/src/stdlib/bigint.mcrs +97 -11
- package/src/stdlib/bits.mcrs +75 -12
- package/src/stdlib/bossbar.mcrs +37 -8
- package/src/stdlib/calculus.mcrs +82 -26
- package/src/stdlib/color.mcrs +98 -16
- package/src/stdlib/combat.mcrs +23 -5
- package/src/stdlib/cooldown.mcrs +19 -0
- package/src/stdlib/dialog.mcrs +45 -7
- package/src/stdlib/easing.mcrs +132 -12
- package/src/stdlib/ecs.mcrs +142 -25
- package/src/stdlib/effects.mcrs +88 -12
- package/src/stdlib/events.mcrs +21 -2
- package/src/stdlib/expr.mcrs +18 -3
- package/src/stdlib/fft.mcrs +66 -56
- package/src/stdlib/geometry.mcrs +137 -39
- package/src/stdlib/graph.mcrs +73 -0
- package/src/stdlib/heap.mcrs +49 -8
- package/src/stdlib/i18n/zh.yaml +2891 -0
- package/src/stdlib/interactions.mcrs +43 -20
- package/src/stdlib/inventory.mcrs +14 -3
- package/src/stdlib/linalg.mcrs +185 -30
- package/src/stdlib/list.mcrs +168 -18
- package/src/stdlib/map.mcrs +112 -0
- package/src/stdlib/math.mcrs +68 -18
- package/src/stdlib/math_hp.mcrs +124 -33
- package/src/stdlib/matrix.mcrs +133 -20
- package/src/stdlib/mobs.mcrs +87 -0
- package/src/stdlib/noise.mcrs +65 -21
- package/src/stdlib/ode.mcrs +96 -0
- package/src/stdlib/parabola.mcrs +104 -29
- package/src/stdlib/particles.mcrs +78 -21
- package/src/stdlib/pathfind.mcrs +89 -35
- package/src/stdlib/physics.mcrs +134 -26
- package/src/stdlib/player.mcrs +18 -0
- package/src/stdlib/quaternion.mcrs +213 -9
- package/src/stdlib/queue.mcrs +123 -0
- package/src/stdlib/random.mcrs +63 -18
- package/src/stdlib/result.mcrs +111 -0
- package/src/stdlib/scheduler.mcrs +59 -10
- package/src/stdlib/set_int.mcrs +240 -0
- package/src/stdlib/sets.mcrs +49 -19
- package/src/stdlib/signal.mcrs +151 -79
- package/src/stdlib/sort.mcrs +44 -24
- package/src/stdlib/spawn.mcrs +30 -7
- package/src/stdlib/state.mcrs +40 -5
- package/src/stdlib/strings.mcrs +131 -3
- package/src/stdlib/tags.mcrs +2 -2
- package/src/stdlib/teams.mcrs +22 -10
- package/src/stdlib/timer.mcrs +36 -6
- package/src/stdlib/vec.mcrs +44 -9
- package/src/stdlib/world.mcrs +57 -25
- package/src/structs/expand.ts +64 -0
- package/src/testing/runner.ts +271 -0
- package/src/typechecker/index.ts +273 -9
|
@@ -0,0 +1,862 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extra coverage for src/runtime/index.ts
|
|
3
|
+
*
|
|
4
|
+
* Targets:
|
|
5
|
+
* - parseSelector: @s with/without executor, @e with type/notType/notTag/scores/limit filters
|
|
6
|
+
* - execScoreboard: all operation variants (=, +=, -=, *=, /=, %=, <, >, ><, reset, enable)
|
|
7
|
+
* - execExecute: store success, unless entity, unless score compare, if score compare ops
|
|
8
|
+
* - execData: append, getArr, getMatch boolean/numeric/array, removeStorageField
|
|
9
|
+
* - execTag: tag remove
|
|
10
|
+
* - execReturn: return run, return value
|
|
11
|
+
* - execSummon: simple summon without NBT, entity type filters
|
|
12
|
+
* - execEffect: with explicit duration/amplifier, no executor
|
|
13
|
+
* - MCRuntime: spawnEntity, getEntities, tick, loadFunction
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
MCRuntime,
|
|
18
|
+
parseRange,
|
|
19
|
+
matchesRange,
|
|
20
|
+
parseSelector,
|
|
21
|
+
type Entity,
|
|
22
|
+
} from '../runtime'
|
|
23
|
+
|
|
24
|
+
// ── parseSelector ───────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
describe('runtime — parseSelector', () => {
|
|
27
|
+
const makeEntity = (id: string, tags: string[], type: string, scores: Record<string, number> = {}): Entity => ({
|
|
28
|
+
id,
|
|
29
|
+
tags: new Set(tags),
|
|
30
|
+
scores: new Map(Object.entries(scores)),
|
|
31
|
+
selector: '@e',
|
|
32
|
+
type,
|
|
33
|
+
position: { x: 0, y: 64, z: 0 },
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('@s with no executor returns empty', () => {
|
|
37
|
+
const result = parseSelector('@s', [])
|
|
38
|
+
expect(result).toEqual([])
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
test('@s with executor returns executor', () => {
|
|
42
|
+
const executor = makeEntity('player', [], 'minecraft:player')
|
|
43
|
+
const result = parseSelector('@s', [executor], executor)
|
|
44
|
+
expect(result).toHaveLength(1)
|
|
45
|
+
expect(result[0].id).toBe('player')
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('@e returns all entities', () => {
|
|
49
|
+
const entities = [makeEntity('a', [], 'zombie'), makeEntity('b', [], 'player')]
|
|
50
|
+
expect(parseSelector('@e', entities)).toHaveLength(2)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
test('@a returns all entities', () => {
|
|
54
|
+
const entities = [makeEntity('a', [], 'zombie'), makeEntity('b', [], 'player')]
|
|
55
|
+
expect(parseSelector('@a', entities)).toHaveLength(2)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test('invalid selector returns empty', () => {
|
|
59
|
+
expect(parseSelector('notasel', [])).toEqual([])
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('@s with filters matches executor if filters pass', () => {
|
|
63
|
+
const executor = makeEntity('p', ['runner'], 'minecraft:player', { rs: 5 })
|
|
64
|
+
const result = parseSelector('@s[tag=runner]', [executor], executor)
|
|
65
|
+
expect(result).toHaveLength(1)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('@s with filters returns empty if executor missing', () => {
|
|
69
|
+
const result = parseSelector('@s[tag=runner]', [])
|
|
70
|
+
expect(result).toHaveLength(0)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
test('@e with type filter', () => {
|
|
74
|
+
const entities = [
|
|
75
|
+
makeEntity('zombie1', [], 'zombie'),
|
|
76
|
+
makeEntity('player1', [], 'minecraft:player'),
|
|
77
|
+
]
|
|
78
|
+
const result = parseSelector('@e[type=zombie]', entities)
|
|
79
|
+
expect(result).toHaveLength(1)
|
|
80
|
+
expect(result[0].id).toBe('zombie1')
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
test('@e with notType filter', () => {
|
|
84
|
+
const entities = [
|
|
85
|
+
makeEntity('zombie1', [], 'zombie'),
|
|
86
|
+
makeEntity('player1', [], 'minecraft:player'),
|
|
87
|
+
]
|
|
88
|
+
const result = parseSelector('@e[type=!zombie]', entities)
|
|
89
|
+
expect(result).toHaveLength(1)
|
|
90
|
+
expect(result[0].id).toBe('player1')
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
test('@e with notTag filter', () => {
|
|
94
|
+
const entities = [
|
|
95
|
+
makeEntity('tagged', ['boss'], 'zombie'),
|
|
96
|
+
makeEntity('plain', [], 'zombie'),
|
|
97
|
+
]
|
|
98
|
+
const result = parseSelector('@e[tag=!boss]', entities)
|
|
99
|
+
expect(result).toHaveLength(1)
|
|
100
|
+
expect(result[0].id).toBe('plain')
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
test('@e with limit filter', () => {
|
|
104
|
+
const entities = [
|
|
105
|
+
makeEntity('a', [], 'zombie'),
|
|
106
|
+
makeEntity('b', [], 'zombie'),
|
|
107
|
+
makeEntity('c', [], 'zombie'),
|
|
108
|
+
]
|
|
109
|
+
const result = parseSelector('@e[limit=2]', entities)
|
|
110
|
+
expect(result).toHaveLength(2)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
test('@e with scores filter', () => {
|
|
114
|
+
const entities = [
|
|
115
|
+
makeEntity('high', [], 'player', { rs: 10 }),
|
|
116
|
+
makeEntity('low', [], 'player', { rs: 2 }),
|
|
117
|
+
]
|
|
118
|
+
const result = parseSelector('@e[scores={rs=5..15}]', entities)
|
|
119
|
+
expect(result).toHaveLength(1)
|
|
120
|
+
expect(result[0].id).toBe('high')
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
test('entity without type falls back to minecraft:armor_stand for type matching', () => {
|
|
124
|
+
const entity: Entity = { id: 'notype', tags: new Set(), scores: new Map(), selector: '@e' }
|
|
125
|
+
const result = parseSelector('@e[type=armor_stand]', [entity])
|
|
126
|
+
expect(result).toHaveLength(1)
|
|
127
|
+
})
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
// ── Scoreboard operations ───────────────────────────────────────────────────
|
|
131
|
+
|
|
132
|
+
describe('runtime — scoreboard operations', () => {
|
|
133
|
+
test('objectives add creates new objective', () => {
|
|
134
|
+
const rt = new MCRuntime('test')
|
|
135
|
+
rt.execCommand('scoreboard objectives add kills dummy')
|
|
136
|
+
expect(rt.scoreboard.has('kills')).toBe(true)
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
test('objectives add is idempotent', () => {
|
|
140
|
+
const rt = new MCRuntime('test')
|
|
141
|
+
rt.execCommand('scoreboard objectives add coins dummy')
|
|
142
|
+
rt.execCommand('scoreboard objectives add coins dummy')
|
|
143
|
+
expect(rt.scoreboard.has('coins')).toBe(true)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
test('scoreboard players set/get', () => {
|
|
147
|
+
const rt = new MCRuntime('test')
|
|
148
|
+
rt.execCommand('scoreboard players set alice rs 42')
|
|
149
|
+
expect(rt.getScore('alice', 'rs')).toBe(42)
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
test('scoreboard players add', () => {
|
|
153
|
+
const rt = new MCRuntime('test')
|
|
154
|
+
rt.setScore('alice', 'rs', 10)
|
|
155
|
+
rt.execCommand('scoreboard players add alice rs 5')
|
|
156
|
+
expect(rt.getScore('alice', 'rs')).toBe(15)
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
test('scoreboard players remove', () => {
|
|
160
|
+
const rt = new MCRuntime('test')
|
|
161
|
+
rt.setScore('alice', 'rs', 10)
|
|
162
|
+
rt.execCommand('scoreboard players remove alice rs 3')
|
|
163
|
+
expect(rt.getScore('alice', 'rs')).toBe(7)
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
test('scoreboard players reset', () => {
|
|
167
|
+
const rt = new MCRuntime('test')
|
|
168
|
+
rt.setScore('alice', 'rs', 99)
|
|
169
|
+
rt.execCommand('scoreboard players reset alice rs')
|
|
170
|
+
expect(rt.getScore('alice', 'rs')).toBe(0)
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
test('scoreboard players enable (no-op)', () => {
|
|
174
|
+
const rt = new MCRuntime('test')
|
|
175
|
+
const result = rt.execCommand('scoreboard players enable @s trigger')
|
|
176
|
+
expect(result).toBe(true)
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
test('scoreboard operation = (copy)', () => {
|
|
180
|
+
const rt = new MCRuntime('test')
|
|
181
|
+
rt.setScore('src', 'rs', 77)
|
|
182
|
+
rt.setScore('dst', 'rs', 0)
|
|
183
|
+
rt.execCommand('scoreboard players operation dst rs = src rs')
|
|
184
|
+
expect(rt.getScore('dst', 'rs')).toBe(77)
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
test('scoreboard operation += ', () => {
|
|
188
|
+
const rt = new MCRuntime('test')
|
|
189
|
+
rt.setScore('x', 'rs', 10)
|
|
190
|
+
rt.setScore('y', 'rs', 5)
|
|
191
|
+
rt.execCommand('scoreboard players operation x rs += y rs')
|
|
192
|
+
expect(rt.getScore('x', 'rs')).toBe(15)
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
test('scoreboard operation -=', () => {
|
|
196
|
+
const rt = new MCRuntime('test')
|
|
197
|
+
rt.setScore('x', 'rs', 10)
|
|
198
|
+
rt.setScore('y', 'rs', 3)
|
|
199
|
+
rt.execCommand('scoreboard players operation x rs -= y rs')
|
|
200
|
+
expect(rt.getScore('x', 'rs')).toBe(7)
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
test('scoreboard operation *=', () => {
|
|
204
|
+
const rt = new MCRuntime('test')
|
|
205
|
+
rt.setScore('x', 'rs', 4)
|
|
206
|
+
rt.setScore('y', 'rs', 3)
|
|
207
|
+
rt.execCommand('scoreboard players operation x rs *= y rs')
|
|
208
|
+
expect(rt.getScore('x', 'rs')).toBe(12)
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
test('scoreboard operation /= (truncate)', () => {
|
|
212
|
+
const rt = new MCRuntime('test')
|
|
213
|
+
rt.setScore('x', 'rs', 10)
|
|
214
|
+
rt.setScore('y', 'rs', 3)
|
|
215
|
+
rt.execCommand('scoreboard players operation x rs /= y rs')
|
|
216
|
+
expect(rt.getScore('x', 'rs')).toBe(3) // truncate(10/3)
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
test('scoreboard operation %=', () => {
|
|
220
|
+
const rt = new MCRuntime('test')
|
|
221
|
+
rt.setScore('x', 'rs', 10)
|
|
222
|
+
rt.setScore('y', 'rs', 3)
|
|
223
|
+
rt.execCommand('scoreboard players operation x rs %= y rs')
|
|
224
|
+
expect(rt.getScore('x', 'rs')).toBe(1)
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
test('scoreboard operation < (min)', () => {
|
|
228
|
+
const rt = new MCRuntime('test')
|
|
229
|
+
rt.setScore('x', 'rs', 10)
|
|
230
|
+
rt.setScore('y', 'rs', 5)
|
|
231
|
+
rt.execCommand('scoreboard players operation x rs < y rs')
|
|
232
|
+
expect(rt.getScore('x', 'rs')).toBe(5)
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
test('scoreboard operation > (max)', () => {
|
|
236
|
+
const rt = new MCRuntime('test')
|
|
237
|
+
rt.setScore('x', 'rs', 3)
|
|
238
|
+
rt.setScore('y', 'rs', 8)
|
|
239
|
+
rt.execCommand('scoreboard players operation x rs > y rs')
|
|
240
|
+
expect(rt.getScore('x', 'rs')).toBe(8)
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
test('scoreboard operation >< (swap)', () => {
|
|
244
|
+
const rt = new MCRuntime('test')
|
|
245
|
+
rt.setScore('x', 'rs', 10)
|
|
246
|
+
rt.setScore('y', 'rs', 20)
|
|
247
|
+
rt.execCommand('scoreboard players operation x rs >< y rs')
|
|
248
|
+
expect(rt.getScore('x', 'rs')).toBe(20)
|
|
249
|
+
expect(rt.getScore('y', 'rs')).toBe(10)
|
|
250
|
+
})
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
// ── Execute subcommands ────────────────────────────────────────────────────
|
|
254
|
+
|
|
255
|
+
describe('runtime — execute subcommands', () => {
|
|
256
|
+
test('store success score stores 1 on success', () => {
|
|
257
|
+
const rt = new MCRuntime('test')
|
|
258
|
+
rt.setScore('p', 'rs', 5)
|
|
259
|
+
rt.execCommand('execute store success score result rs if score p rs matches 1..10 run scoreboard players set noop rs 0')
|
|
260
|
+
expect(rt.getScore('result', 'rs')).toBe(1)
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
test('unless entity fires when no matching entity', () => {
|
|
264
|
+
const rt = new MCRuntime('test')
|
|
265
|
+
rt.execCommand('execute unless entity @e[tag=nonexistent] run scoreboard players set fired rs 1')
|
|
266
|
+
expect(rt.getScore('fired', 'rs')).toBe(1)
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
test('unless entity skips when entity exists', () => {
|
|
270
|
+
const rt = new MCRuntime('test')
|
|
271
|
+
rt.spawnEntity(['target'], 'zombie', { x: 0, y: 0, z: 0 })
|
|
272
|
+
rt.execCommand('execute unless entity @e[tag=target] run scoreboard players set fired rs 1')
|
|
273
|
+
expect(rt.getScore('fired', 'rs')).toBe(0)
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
test('if score compare operators: = < <= > >=', () => {
|
|
277
|
+
const rt = new MCRuntime('test')
|
|
278
|
+
rt.setScore('a', 'rs', 5)
|
|
279
|
+
rt.setScore('b', 'rs', 5)
|
|
280
|
+
|
|
281
|
+
rt.execCommand('execute if score a rs = b rs run scoreboard players set eq rs 1')
|
|
282
|
+
expect(rt.getScore('eq', 'rs')).toBe(1)
|
|
283
|
+
|
|
284
|
+
rt.setScore('a', 'rs', 3)
|
|
285
|
+
rt.execCommand('execute if score a rs < b rs run scoreboard players set lt rs 1')
|
|
286
|
+
expect(rt.getScore('lt', 'rs')).toBe(1)
|
|
287
|
+
|
|
288
|
+
rt.execCommand('execute if score a rs <= b rs run scoreboard players set lte rs 1')
|
|
289
|
+
expect(rt.getScore('lte', 'rs')).toBe(1)
|
|
290
|
+
|
|
291
|
+
rt.setScore('a', 'rs', 7)
|
|
292
|
+
rt.execCommand('execute if score a rs > b rs run scoreboard players set gt rs 1')
|
|
293
|
+
expect(rt.getScore('gt', 'rs')).toBe(1)
|
|
294
|
+
|
|
295
|
+
rt.execCommand('execute if score a rs >= b rs run scoreboard players set gte rs 1')
|
|
296
|
+
expect(rt.getScore('gte', 'rs')).toBe(1)
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
test('unless score compare negates condition', () => {
|
|
300
|
+
const rt = new MCRuntime('test')
|
|
301
|
+
rt.setScore('a', 'rs', 3)
|
|
302
|
+
rt.setScore('b', 'rs', 5)
|
|
303
|
+
rt.execCommand('execute unless score a rs = b rs run scoreboard players set neq rs 1')
|
|
304
|
+
expect(rt.getScore('neq', 'rs')).toBe(1)
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
test('execute as multiple entities runs for each', () => {
|
|
308
|
+
const rt = new MCRuntime('test')
|
|
309
|
+
rt.spawnEntity(['target'], 'zombie', { x: 0, y: 0, z: 0 })
|
|
310
|
+
rt.spawnEntity(['target'], 'zombie', { x: 1, y: 0, z: 0 })
|
|
311
|
+
rt.execCommand('execute as @e[tag=target] run tag @s add processed')
|
|
312
|
+
const processed = rt.getEntities('@e[tag=processed]')
|
|
313
|
+
expect(processed).toHaveLength(2)
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
test('execute at selector continues', () => {
|
|
317
|
+
const rt = new MCRuntime('test')
|
|
318
|
+
rt.spawnEntity(['walker'], 'player', { x: 5, y: 64, z: 5 })
|
|
319
|
+
rt.execCommand('execute at @e[tag=walker] run scoreboard players set walked rs 1')
|
|
320
|
+
expect(rt.getScore('walked', 'rs')).toBe(1)
|
|
321
|
+
})
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
// ── Data commands ──────────────────────────────────────────────────────────
|
|
325
|
+
|
|
326
|
+
describe('runtime — data commands', () => {
|
|
327
|
+
test('data append and get array length', () => {
|
|
328
|
+
const rt = new MCRuntime('test')
|
|
329
|
+
rt.execCommand('data modify storage test:arr list set value []')
|
|
330
|
+
rt.execCommand('data modify storage test:arr list append value 10')
|
|
331
|
+
rt.execCommand('data modify storage test:arr list append value 20')
|
|
332
|
+
rt.execCommand('execute store result score count rs run data get storage test:arr list')
|
|
333
|
+
expect(rt.getScore('count', 'rs')).toBe(2)
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
test('data remove storage field', () => {
|
|
337
|
+
const rt = new MCRuntime('test')
|
|
338
|
+
rt.execCommand('data modify storage test:del value set value 42')
|
|
339
|
+
rt.execCommand('data remove storage test:del value')
|
|
340
|
+
expect(rt.getStorage('test:del.value')).toBeUndefined()
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
test('data modify append to non-array does nothing', () => {
|
|
344
|
+
const rt = new MCRuntime('test')
|
|
345
|
+
rt.execCommand('data modify storage test:scalar x set value 99')
|
|
346
|
+
// append to non-array - should not crash
|
|
347
|
+
rt.execCommand('data modify storage test:scalar x append value 1')
|
|
348
|
+
expect(rt.getStorage('test:scalar.x')).toBe(99)
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
test('data get storage returns 0 for undefined', () => {
|
|
352
|
+
const rt = new MCRuntime('test')
|
|
353
|
+
const result = rt.execCommand('data get storage test:empty missingfield')
|
|
354
|
+
expect(result).toBe(true)
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
test('data get storage array element', () => {
|
|
358
|
+
const rt = new MCRuntime('test')
|
|
359
|
+
rt.execCommand('data modify storage test:arr nums set value [10,20,30]')
|
|
360
|
+
rt.execCommand('execute store result score elem rs run data get storage test:arr nums[1]')
|
|
361
|
+
expect(rt.getScore('elem', 'rs')).toBe(20)
|
|
362
|
+
})
|
|
363
|
+
|
|
364
|
+
test('data get storage on array returns length', () => {
|
|
365
|
+
const rt = new MCRuntime('test')
|
|
366
|
+
rt.execCommand('data modify storage test:arr items set value [1,2,3,4]')
|
|
367
|
+
rt.execCommand('execute store result score len rs run data get storage test:arr items')
|
|
368
|
+
expect(rt.getScore('len', 'rs')).toBe(4)
|
|
369
|
+
})
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
// ── Tag commands ─────────────────────────────────────────────────────────────
|
|
373
|
+
|
|
374
|
+
describe('runtime — tag commands', () => {
|
|
375
|
+
test('tag add via @e selector', () => {
|
|
376
|
+
const rt = new MCRuntime('test')
|
|
377
|
+
rt.spawnEntity(['enemy'], 'zombie', { x: 0, y: 0, z: 0 })
|
|
378
|
+
rt.execCommand('tag @e[tag=enemy] add hostile')
|
|
379
|
+
const entities = rt.getEntities('@e[tag=hostile]')
|
|
380
|
+
expect(entities).toHaveLength(1)
|
|
381
|
+
})
|
|
382
|
+
|
|
383
|
+
test('tag remove via @s', () => {
|
|
384
|
+
const rt = new MCRuntime('test')
|
|
385
|
+
const p = rt.spawnEntity(['runner', 'active'], 'player', { x: 0, y: 0, z: 0 })
|
|
386
|
+
rt.execCommand('tag @s remove active', p)
|
|
387
|
+
expect(p.tags.has('active')).toBe(false)
|
|
388
|
+
expect(p.tags.has('runner')).toBe(true)
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
test('tag remove via @e selector', () => {
|
|
392
|
+
const rt = new MCRuntime('test')
|
|
393
|
+
rt.spawnEntity(['marked'], 'zombie', { x: 0, y: 0, z: 0 })
|
|
394
|
+
rt.execCommand('tag @e[tag=marked] remove marked')
|
|
395
|
+
const entities = rt.getEntities('@e[tag=marked]')
|
|
396
|
+
expect(entities).toHaveLength(0)
|
|
397
|
+
})
|
|
398
|
+
|
|
399
|
+
test('tag command returns false for invalid', () => {
|
|
400
|
+
const rt = new MCRuntime('test')
|
|
401
|
+
const result = rt.execCommand('tag badformat')
|
|
402
|
+
expect(result).toBe(false)
|
|
403
|
+
})
|
|
404
|
+
})
|
|
405
|
+
|
|
406
|
+
// ── Return command ────────────────────────────────────────────────────────────
|
|
407
|
+
|
|
408
|
+
describe('runtime — return command', () => {
|
|
409
|
+
test('return <value> can be captured via store result', () => {
|
|
410
|
+
const rt = new MCRuntime('test')
|
|
411
|
+
rt.loadFunction('test:myfn', ['return 99'])
|
|
412
|
+
rt.execCommand('execute store result score ret rs run function test:myfn')
|
|
413
|
+
expect(rt.getScore('ret', 'rs')).toBe(99)
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
test('bare return command stops execution', () => {
|
|
417
|
+
const rt = new MCRuntime('test')
|
|
418
|
+
rt.loadFunction('test:early', [
|
|
419
|
+
'scoreboard players set before rs 1',
|
|
420
|
+
'return',
|
|
421
|
+
'scoreboard players set after rs 1',
|
|
422
|
+
])
|
|
423
|
+
rt.execFunction('early')
|
|
424
|
+
expect(rt.getScore('before', 'rs')).toBe(1)
|
|
425
|
+
expect(rt.getScore('after', 'rs')).toBe(0)
|
|
426
|
+
})
|
|
427
|
+
|
|
428
|
+
test('return run <cmd> executes inner cmd then stops', () => {
|
|
429
|
+
const rt = new MCRuntime('test')
|
|
430
|
+
rt.loadFunction('test:retrun', [
|
|
431
|
+
'return run scoreboard players set ret rs 42',
|
|
432
|
+
'scoreboard players set nope rs 1',
|
|
433
|
+
])
|
|
434
|
+
rt.execFunction('retrun')
|
|
435
|
+
expect(rt.getScore('ret', 'rs')).toBe(42)
|
|
436
|
+
expect(rt.getScore('nope', 'rs')).toBe(0)
|
|
437
|
+
})
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
// ── Summon ───────────────────────────────────────────────────────────────────
|
|
441
|
+
|
|
442
|
+
describe('runtime — summon', () => {
|
|
443
|
+
test('simple summon without NBT creates entity', () => {
|
|
444
|
+
const rt = new MCRuntime('test')
|
|
445
|
+
rt.execCommand('summon minecraft:zombie 10 65 10')
|
|
446
|
+
const zombies = rt.getEntities('@e[type=zombie]')
|
|
447
|
+
expect(zombies.length).toBeGreaterThan(0)
|
|
448
|
+
})
|
|
449
|
+
|
|
450
|
+
test('summon with NBT creates tagged entity', () => {
|
|
451
|
+
const rt = new MCRuntime('test')
|
|
452
|
+
rt.execCommand('summon minecraft:armor_stand 0 64 0 {Tags:["marker","special"]}')
|
|
453
|
+
const markers = rt.getEntities('@e[tag=marker]')
|
|
454
|
+
expect(markers.length).toBeGreaterThan(0)
|
|
455
|
+
expect(markers[0].tags.has('special')).toBe(true)
|
|
456
|
+
})
|
|
457
|
+
|
|
458
|
+
test('summon without position creates entity at origin', () => {
|
|
459
|
+
const rt = new MCRuntime('test')
|
|
460
|
+
rt.execCommand('summon minecraft:chicken')
|
|
461
|
+
const chickens = rt.getEntities('@e[type=chicken]')
|
|
462
|
+
expect(chickens.length).toBeGreaterThan(0)
|
|
463
|
+
})
|
|
464
|
+
})
|
|
465
|
+
|
|
466
|
+
// ── Effect ───────────────────────────────────────────────────────────────────
|
|
467
|
+
|
|
468
|
+
describe('runtime — effect command', () => {
|
|
469
|
+
test('effect give with defaults (no duration/amplifier)', () => {
|
|
470
|
+
const rt = new MCRuntime('test')
|
|
471
|
+
const p = rt.spawnEntity(['player'], 'minecraft:player', { x: 0, y: 64, z: 0 })
|
|
472
|
+
rt.execCommand('effect give @e[tag=player] minecraft:speed')
|
|
473
|
+
const fx = rt.effects.get(p.id)!
|
|
474
|
+
expect(fx).toBeDefined()
|
|
475
|
+
expect(fx[0].effect).toBe('minecraft:speed')
|
|
476
|
+
expect(fx[0].duration).toBe(30) // default
|
|
477
|
+
expect(fx[0].amplifier).toBe(0) // default
|
|
478
|
+
})
|
|
479
|
+
|
|
480
|
+
test('effect give to no matching entity returns false', () => {
|
|
481
|
+
const rt = new MCRuntime('test')
|
|
482
|
+
const result = rt.execCommand('effect give @e[tag=nobody] minecraft:speed')
|
|
483
|
+
expect(result).toBe(false)
|
|
484
|
+
})
|
|
485
|
+
})
|
|
486
|
+
|
|
487
|
+
// ── MCRuntime misc ────────────────────────────────────────────────────────────
|
|
488
|
+
|
|
489
|
+
describe('runtime — MCRuntime misc', () => {
|
|
490
|
+
test('tick increments tickCount', () => {
|
|
491
|
+
const rt = new MCRuntime('test')
|
|
492
|
+
rt.tick()
|
|
493
|
+
rt.tick()
|
|
494
|
+
expect(rt.tickCount).toBe(2)
|
|
495
|
+
})
|
|
496
|
+
|
|
497
|
+
test('getEntities with @e selector', () => {
|
|
498
|
+
const rt = new MCRuntime('test')
|
|
499
|
+
rt.spawnEntity(['a'], 'zombie', { x: 0, y: 0, z: 0 })
|
|
500
|
+
rt.spawnEntity(['b'], 'zombie', { x: 1, y: 0, z: 0 })
|
|
501
|
+
expect(rt.getEntities('@e').length).toBe(2)
|
|
502
|
+
})
|
|
503
|
+
|
|
504
|
+
test('loadFunction stores function by name', () => {
|
|
505
|
+
const rt = new MCRuntime('test')
|
|
506
|
+
rt.loadFunction('test:ping', ['say pong'])
|
|
507
|
+
expect(rt.functions.has('test:ping')).toBe(true)
|
|
508
|
+
})
|
|
509
|
+
|
|
510
|
+
test('execFunction runs loaded function', () => {
|
|
511
|
+
const rt = new MCRuntime('test')
|
|
512
|
+
rt.loadFunction('test:greet', ['say hello'])
|
|
513
|
+
rt.execFunction('greet')
|
|
514
|
+
expect(rt.getLastSaid()).toBe('[Server] hello')
|
|
515
|
+
})
|
|
516
|
+
|
|
517
|
+
test('unknown command succeeds silently', () => {
|
|
518
|
+
const rt = new MCRuntime('test')
|
|
519
|
+
expect(rt.execCommand('gamemode creative @a')).toBe(true)
|
|
520
|
+
})
|
|
521
|
+
|
|
522
|
+
test('getChatLog returns all messages', () => {
|
|
523
|
+
const rt = new MCRuntime('test')
|
|
524
|
+
rt.execCommand('say first')
|
|
525
|
+
rt.execCommand('say second')
|
|
526
|
+
expect(rt.getChatLog()).toEqual(['[Server] first', '[Server] second'])
|
|
527
|
+
})
|
|
528
|
+
|
|
529
|
+
test('getStorage with nested path', () => {
|
|
530
|
+
const rt = new MCRuntime('test')
|
|
531
|
+
rt.execCommand('data modify storage test:ns a set value {"b":42}')
|
|
532
|
+
expect(rt.getStorage('test:ns.a.b')).toBe(42)
|
|
533
|
+
})
|
|
534
|
+
|
|
535
|
+
test('weather command sets weather', () => {
|
|
536
|
+
const rt = new MCRuntime('test')
|
|
537
|
+
rt.execCommand('weather thunder')
|
|
538
|
+
expect(rt.weather).toBe('thunder')
|
|
539
|
+
rt.execCommand('weather clear')
|
|
540
|
+
expect(rt.weather).toBe('clear')
|
|
541
|
+
})
|
|
542
|
+
|
|
543
|
+
test('time set and add', () => {
|
|
544
|
+
const rt = new MCRuntime('test')
|
|
545
|
+
rt.execCommand('time set 1000')
|
|
546
|
+
expect(rt.worldTime).toBe(1000)
|
|
547
|
+
rt.execCommand('time add 500')
|
|
548
|
+
expect(rt.worldTime).toBe(1500)
|
|
549
|
+
})
|
|
550
|
+
|
|
551
|
+
test('time set noon', () => {
|
|
552
|
+
const rt = new MCRuntime('test')
|
|
553
|
+
rt.execCommand('time set noon')
|
|
554
|
+
expect(rt.worldTime).toBe(6000)
|
|
555
|
+
})
|
|
556
|
+
|
|
557
|
+
test('time set midnight', () => {
|
|
558
|
+
const rt = new MCRuntime('test')
|
|
559
|
+
rt.execCommand('time set midnight')
|
|
560
|
+
expect(rt.worldTime).toBe(18000)
|
|
561
|
+
})
|
|
562
|
+
|
|
563
|
+
test('time set day/night', () => {
|
|
564
|
+
const rt = new MCRuntime('test')
|
|
565
|
+
rt.execCommand('time set day')
|
|
566
|
+
expect(rt.worldTime).toBe(1000)
|
|
567
|
+
rt.execCommand('time set night')
|
|
568
|
+
expect(rt.worldTime).toBe(13000)
|
|
569
|
+
})
|
|
570
|
+
|
|
571
|
+
test('tp with relative coords', () => {
|
|
572
|
+
const rt = new MCRuntime('test')
|
|
573
|
+
const p = rt.spawnEntity(['mover'], 'player', { x: 10, y: 64, z: 10 })
|
|
574
|
+
rt.execCommand('tp @s ~5 ~ ~-3', p)
|
|
575
|
+
expect(p.position).toEqual({ x: 15, y: 64, z: 7 })
|
|
576
|
+
})
|
|
577
|
+
|
|
578
|
+
test('compileAndLoad runs compiled code', () => {
|
|
579
|
+
const rt = new MCRuntime('test')
|
|
580
|
+
rt.compileAndLoad('fn greet(): int { return 1; }')
|
|
581
|
+
expect(rt.functions.size).toBeGreaterThan(0)
|
|
582
|
+
})
|
|
583
|
+
})
|
|
584
|
+
|
|
585
|
+
// ── Additional tp coverage ────────────────────────────────────────────────
|
|
586
|
+
|
|
587
|
+
describe('runtime — tp additional variants', () => {
|
|
588
|
+
test('tp self to absolute coords (3 args)', () => {
|
|
589
|
+
const rt = new MCRuntime('test')
|
|
590
|
+
const p = rt.spawnEntity(['p'], 'player', { x: 0, y: 0, z: 0 })
|
|
591
|
+
rt.execCommand('tp 5 10 15', p)
|
|
592
|
+
expect(p.position).toEqual({ x: 5, y: 10, z: 15 })
|
|
593
|
+
})
|
|
594
|
+
|
|
595
|
+
test('tp entity to entity', () => {
|
|
596
|
+
const rt = new MCRuntime('test')
|
|
597
|
+
const src = rt.spawnEntity(['mover'], 'player', { x: 10, y: 64, z: 10 })
|
|
598
|
+
const dst = rt.spawnEntity(['target'], 'player', { x: 50, y: 70, z: 50 })
|
|
599
|
+
rt.execCommand('execute as @e[tag=mover] run tp @s @e[tag=target]', src)
|
|
600
|
+
expect(src.position).toEqual({ x: 50, y: 70, z: 50 })
|
|
601
|
+
})
|
|
602
|
+
|
|
603
|
+
test('tp selector to coords', () => {
|
|
604
|
+
const rt = new MCRuntime('test')
|
|
605
|
+
rt.spawnEntity(['mob'], 'zombie', { x: 0, y: 64, z: 0 })
|
|
606
|
+
rt.execCommand('tp @e[tag=mob] 100 64 100')
|
|
607
|
+
const mobs = rt.getEntities('@e[tag=mob]')
|
|
608
|
+
expect(mobs[0].position).toEqual({ x: 100, y: 64, z: 100 })
|
|
609
|
+
})
|
|
610
|
+
})
|
|
611
|
+
|
|
612
|
+
// ── Kill command ──────────────────────────────────────────────────────────
|
|
613
|
+
|
|
614
|
+
describe('runtime — kill command', () => {
|
|
615
|
+
test('kill self entity removes from entities list', () => {
|
|
616
|
+
const rt = new MCRuntime('test')
|
|
617
|
+
const p = rt.spawnEntity(['victim'], 'player', { x: 0, y: 0, z: 0 })
|
|
618
|
+
rt.execCommand('kill @s', p)
|
|
619
|
+
expect(rt.getEntities('@e[tag=victim]')).toHaveLength(0)
|
|
620
|
+
})
|
|
621
|
+
|
|
622
|
+
test('kill by selector removes matching entities', () => {
|
|
623
|
+
const rt = new MCRuntime('test')
|
|
624
|
+
rt.spawnEntity(['dead1'], 'zombie', { x: 0, y: 0, z: 0 })
|
|
625
|
+
rt.spawnEntity(['dead2'], 'zombie', { x: 1, y: 0, z: 0 })
|
|
626
|
+
rt.spawnEntity(['alive'], 'player', { x: 2, y: 0, z: 0 })
|
|
627
|
+
rt.execCommand('kill @e[type=zombie]')
|
|
628
|
+
expect(rt.getEntities('@e[type=zombie]')).toHaveLength(0)
|
|
629
|
+
expect(rt.getEntities('@e[tag=alive]')).toHaveLength(1)
|
|
630
|
+
})
|
|
631
|
+
})
|
|
632
|
+
|
|
633
|
+
// ── xp and effect edge cases ──────────────────────────────────────────────
|
|
634
|
+
|
|
635
|
+
describe('runtime — xp edge cases', () => {
|
|
636
|
+
test('xp add to @s executor', () => {
|
|
637
|
+
const rt = new MCRuntime('test')
|
|
638
|
+
const p = rt.spawnEntity(['p'], 'player', { x: 0, y: 0, z: 0 })
|
|
639
|
+
rt.execCommand('xp add @s 100 points', p)
|
|
640
|
+
expect(rt.xp.get(p.id)).toBe(100)
|
|
641
|
+
})
|
|
642
|
+
|
|
643
|
+
test('xp set with selector', () => {
|
|
644
|
+
const rt = new MCRuntime('test')
|
|
645
|
+
const p = rt.spawnEntity(['p'], 'player', { x: 0, y: 0, z: 0 })
|
|
646
|
+
rt.execCommand('xp set @e[tag=p] 50 points')
|
|
647
|
+
expect(rt.xp.get(p.id)).toBe(50)
|
|
648
|
+
})
|
|
649
|
+
})
|
|
650
|
+
|
|
651
|
+
// ── tellraw extractJsonText edge cases ────────────────────────────────────
|
|
652
|
+
|
|
653
|
+
describe('runtime — tellraw extractJsonText', () => {
|
|
654
|
+
test('tellraw with text component', () => {
|
|
655
|
+
const rt = new MCRuntime('test')
|
|
656
|
+
rt.execCommand('tellraw @a {"text":"hello"}')
|
|
657
|
+
expect(rt.getChatLog()).toContain('hello')
|
|
658
|
+
})
|
|
659
|
+
|
|
660
|
+
test('tellraw with plain string JSON', () => {
|
|
661
|
+
const rt = new MCRuntime('test')
|
|
662
|
+
rt.execCommand('tellraw @a "plain text"')
|
|
663
|
+
expect(rt.getChatLog()).toContain('plain text')
|
|
664
|
+
})
|
|
665
|
+
|
|
666
|
+
test('tellraw with array of text parts', () => {
|
|
667
|
+
const rt = new MCRuntime('test')
|
|
668
|
+
rt.execCommand('tellraw @a [{"text":"hello"},{"text":" world"}]')
|
|
669
|
+
expect(rt.getChatLog().some(m => m.includes('hello'))).toBe(true)
|
|
670
|
+
})
|
|
671
|
+
|
|
672
|
+
test('title with subtitle', () => {
|
|
673
|
+
const rt = new MCRuntime('test')
|
|
674
|
+
rt.execCommand('title @a title {"text":"big title"}')
|
|
675
|
+
expect(rt.getChatLog().some(m => m.includes('[TITLE]'))).toBe(true)
|
|
676
|
+
})
|
|
677
|
+
|
|
678
|
+
test('title with subtitle kind', () => {
|
|
679
|
+
const rt = new MCRuntime('test')
|
|
680
|
+
rt.execCommand('title @a subtitle {"text":"small title"}')
|
|
681
|
+
expect(rt.getChatLog().some(m => m.includes('[SUBTITLE]'))).toBe(true)
|
|
682
|
+
})
|
|
683
|
+
})
|
|
684
|
+
|
|
685
|
+
// ── scoreboard players get ────────────────────────────────────────────────
|
|
686
|
+
|
|
687
|
+
describe('runtime — scoreboard players get', () => {
|
|
688
|
+
test('scoreboard players get returns score via store result', () => {
|
|
689
|
+
const rt = new MCRuntime('test')
|
|
690
|
+
rt.setScore('player1', 'rs', 55)
|
|
691
|
+
rt.execCommand('execute store result score result rs run scoreboard players get player1 rs')
|
|
692
|
+
expect(rt.getScore('result', 'rs')).toBe(55)
|
|
693
|
+
})
|
|
694
|
+
})
|
|
695
|
+
|
|
696
|
+
// ── Storage path parsing ────────────────────────────────────────────────────
|
|
697
|
+
|
|
698
|
+
describe('runtime — storage path edge cases', () => {
|
|
699
|
+
test('getStorage without colon returns raw storage key', () => {
|
|
700
|
+
const rt = new MCRuntime('test')
|
|
701
|
+
rt.execCommand('data modify storage simple-key field set value 42')
|
|
702
|
+
// Simple key (no colon) should work
|
|
703
|
+
expect(rt.execCommand('data get storage simple-key field')).toBe(true)
|
|
704
|
+
})
|
|
705
|
+
|
|
706
|
+
test('setStorage without colon', () => {
|
|
707
|
+
const rt = new MCRuntime('test')
|
|
708
|
+
rt.setStorage('simple-key', { x: 1 })
|
|
709
|
+
// Should not throw
|
|
710
|
+
expect(true).toBe(true)
|
|
711
|
+
})
|
|
712
|
+
|
|
713
|
+
test('getStorage with no dot after colon returns top-level ns', () => {
|
|
714
|
+
const rt = new MCRuntime('test')
|
|
715
|
+
rt.execCommand('data modify storage test:bucket field set value 42')
|
|
716
|
+
// getStorage returns the field
|
|
717
|
+
const val = rt.getStorage('test:bucket.field')
|
|
718
|
+
expect(val).toBe(42)
|
|
719
|
+
})
|
|
720
|
+
|
|
721
|
+
test('setStorage with dotted path sets nested field', () => {
|
|
722
|
+
const rt = new MCRuntime('test')
|
|
723
|
+
rt.setStorage('test:ns.field', 99)
|
|
724
|
+
expect(rt.getStorage('test:ns.field')).toBe(99)
|
|
725
|
+
})
|
|
726
|
+
})
|
|
727
|
+
|
|
728
|
+
// ── matchesRange ──────────────────────────────────────────────────────────
|
|
729
|
+
|
|
730
|
+
describe('runtime — matchesRange / parseRange', () => {
|
|
731
|
+
test('matchesRange works for exact value', () => {
|
|
732
|
+
const rt = new MCRuntime('test')
|
|
733
|
+
rt.setScore('p', 'rs', 5)
|
|
734
|
+
rt.execCommand('execute if score p rs matches 5 run scoreboard players set exact rs 1')
|
|
735
|
+
expect(rt.getScore('exact', 'rs')).toBe(1)
|
|
736
|
+
})
|
|
737
|
+
|
|
738
|
+
test('matchesRange works for open-ended range ..N', () => {
|
|
739
|
+
const rt = new MCRuntime('test')
|
|
740
|
+
rt.setScore('p', 'rs', 3)
|
|
741
|
+
rt.execCommand('execute if score p rs matches ..5 run scoreboard players set open rs 1')
|
|
742
|
+
expect(rt.getScore('open', 'rs')).toBe(1)
|
|
743
|
+
})
|
|
744
|
+
|
|
745
|
+
test('matchesRange works for open-start range N..', () => {
|
|
746
|
+
const rt = new MCRuntime('test')
|
|
747
|
+
rt.setScore('p', 'rs', 10)
|
|
748
|
+
rt.execCommand('execute if score p rs matches 5.. run scoreboard players set start rs 1')
|
|
749
|
+
expect(rt.getScore('start', 'rs')).toBe(1)
|
|
750
|
+
})
|
|
751
|
+
|
|
752
|
+
test('matchesRange fails for out-of-range', () => {
|
|
753
|
+
const rt = new MCRuntime('test')
|
|
754
|
+
rt.setScore('p', 'rs', 20)
|
|
755
|
+
rt.execCommand('execute if score p rs matches 1..10 run scoreboard players set inrange rs 1')
|
|
756
|
+
expect(rt.getScore('inrange', 'rs')).toBe(0)
|
|
757
|
+
})
|
|
758
|
+
})
|
|
759
|
+
|
|
760
|
+
// ── execFunction with return value ────────────────────────────────────────
|
|
761
|
+
|
|
762
|
+
describe('runtime — execFunction with return value', () => {
|
|
763
|
+
test('return value captured via store result', () => {
|
|
764
|
+
const rt = new MCRuntime('test')
|
|
765
|
+
rt.loadFunction('test:calc', [
|
|
766
|
+
'scoreboard players set __rs_return rs 77',
|
|
767
|
+
'return 77',
|
|
768
|
+
])
|
|
769
|
+
rt.execCommand('execute store result score result rs run function test:calc')
|
|
770
|
+
expect(rt.getScore('result', 'rs')).toBe(77)
|
|
771
|
+
})
|
|
772
|
+
|
|
773
|
+
test('function called with execute as @s sets executor', () => {
|
|
774
|
+
const rt = new MCRuntime('test')
|
|
775
|
+
const p = rt.spawnEntity(['runner'], 'player', { x: 0, y: 0, z: 0 })
|
|
776
|
+
rt.loadFunction('test:tagme', ['tag @s add tagged'])
|
|
777
|
+
rt.execCommand('execute as @e[tag=runner] run function test:tagme')
|
|
778
|
+
expect(p.tags.has('tagged')).toBe(true)
|
|
779
|
+
})
|
|
780
|
+
})
|
|
781
|
+
|
|
782
|
+
// ── kill with @s ─────────────────────────────────────────────────────────
|
|
783
|
+
|
|
784
|
+
describe('runtime — kill edge cases', () => {
|
|
785
|
+
test('kill @s does not crash without executor', () => {
|
|
786
|
+
const rt = new MCRuntime('test')
|
|
787
|
+
// kill @s without executor - should fail gracefully
|
|
788
|
+
const result = rt.execCommand('kill @s')
|
|
789
|
+
expect(typeof result).toBe('boolean')
|
|
790
|
+
})
|
|
791
|
+
})
|
|
792
|
+
|
|
793
|
+
// ── setblock / fill ────────────────────────────────────────────────────────
|
|
794
|
+
|
|
795
|
+
describe('runtime — setblock and fill', () => {
|
|
796
|
+
test('setblock places block at coordinate in world map', () => {
|
|
797
|
+
const rt = new MCRuntime('test')
|
|
798
|
+
rt.execCommand('setblock 10 64 10 minecraft:stone')
|
|
799
|
+
expect(rt.world.get('10,64,10')).toBe('minecraft:stone')
|
|
800
|
+
})
|
|
801
|
+
|
|
802
|
+
test('fill region sets multiple blocks', () => {
|
|
803
|
+
const rt = new MCRuntime('test')
|
|
804
|
+
rt.execCommand('fill 0 64 0 2 64 2 minecraft:oak_planks')
|
|
805
|
+
expect(rt.world.get('1,64,1')).toBe('minecraft:oak_planks')
|
|
806
|
+
expect(rt.world.get('0,64,0')).toBe('minecraft:oak_planks')
|
|
807
|
+
expect(rt.world.get('2,64,2')).toBe('minecraft:oak_planks')
|
|
808
|
+
})
|
|
809
|
+
|
|
810
|
+
test('setblock with invalid coordinates returns false', () => {
|
|
811
|
+
const rt = new MCRuntime('test')
|
|
812
|
+
const result = rt.execCommand('setblock notacoord notacoord notacoord minecraft:stone')
|
|
813
|
+
expect(result).toBe(false)
|
|
814
|
+
})
|
|
815
|
+
})
|
|
816
|
+
|
|
817
|
+
// ── effect with duration and amplifier ────────────────────────────────────
|
|
818
|
+
|
|
819
|
+
describe('runtime — effect with explicit duration/amplifier', () => {
|
|
820
|
+
test('effect give with duration and amplifier', () => {
|
|
821
|
+
const rt = new MCRuntime('test')
|
|
822
|
+
const p = rt.spawnEntity(['p'], 'player', { x: 0, y: 0, z: 0 })
|
|
823
|
+
rt.execCommand('effect give @e[tag=p] minecraft:strength 60 2')
|
|
824
|
+
const fx = rt.effects.get(p.id)!
|
|
825
|
+
expect(fx[0].duration).toBe(60)
|
|
826
|
+
expect(fx[0].amplifier).toBe(2)
|
|
827
|
+
})
|
|
828
|
+
|
|
829
|
+
test('multiple effect give stacks effects', () => {
|
|
830
|
+
const rt = new MCRuntime('test')
|
|
831
|
+
const p = rt.spawnEntity(['p'], 'player', { x: 0, y: 0, z: 0 })
|
|
832
|
+
rt.execCommand('effect give @e[tag=p] minecraft:speed 30 0')
|
|
833
|
+
rt.execCommand('effect give @e[tag=p] minecraft:strength 60 1')
|
|
834
|
+
const fx = rt.effects.get(p.id)!
|
|
835
|
+
expect(fx.length).toBe(2)
|
|
836
|
+
expect(fx[1].effect).toBe('minecraft:strength')
|
|
837
|
+
})
|
|
838
|
+
})
|
|
839
|
+
|
|
840
|
+
// ── compileAndLoad ─────────────────────────────────────────────────────────
|
|
841
|
+
|
|
842
|
+
describe('runtime — compileAndLoad', () => {
|
|
843
|
+
test('compileAndLoad loads multiple functions', () => {
|
|
844
|
+
const rt = new MCRuntime('test')
|
|
845
|
+
rt.compileAndLoad(`
|
|
846
|
+
fn add(a: int, b: int): int { return a + b; }
|
|
847
|
+
fn sub(a: int, b: int): int { return a - b; }
|
|
848
|
+
`)
|
|
849
|
+
expect(rt.functions.size).toBeGreaterThan(1)
|
|
850
|
+
})
|
|
851
|
+
|
|
852
|
+
test('compileAndLoad allows calling compiled functions', () => {
|
|
853
|
+
const rt = new MCRuntime('test')
|
|
854
|
+
rt.compileAndLoad(`
|
|
855
|
+
fn set_score(): void {
|
|
856
|
+
scoreboard_set("player", "rs", 99);
|
|
857
|
+
}
|
|
858
|
+
`)
|
|
859
|
+
rt.execFunction('set_score')
|
|
860
|
+
expect(rt.getScore('player', 'rs')).toBe(99)
|
|
861
|
+
})
|
|
862
|
+
})
|