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
|
@@ -31,6 +31,11 @@ function mkModule(functions: LIRFunction[]): LIRModule {
|
|
|
31
31
|
// ---------------------------------------------------------------------------
|
|
32
32
|
|
|
33
33
|
describe('estimateCommandCount', () => {
|
|
34
|
+
test('missing function returns 0', () => {
|
|
35
|
+
const mod = mkModule([mkFn('main', [])])
|
|
36
|
+
expect(estimateCommandCount('missing', mod)).toBe(0)
|
|
37
|
+
})
|
|
38
|
+
|
|
34
39
|
test('flat function — counts each instruction as 1', () => {
|
|
35
40
|
const fn = mkFn('simple', [
|
|
36
41
|
{ kind: 'score_set', dst: slot('$x'), value: 0 },
|
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cache-behavior.test.ts
|
|
3
|
+
*
|
|
4
|
+
* Focused tests for cache behavior:
|
|
5
|
+
* - Same code compiled twice → second compile uses cache
|
|
6
|
+
* - Modified code → cache invalidation
|
|
7
|
+
* - stdlib / shared module caching
|
|
8
|
+
* - Edge cases to push src/cache/ coverage > 85%
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import * as fs from 'fs'
|
|
12
|
+
import * as os from 'os'
|
|
13
|
+
import * as path from 'path'
|
|
14
|
+
import { FileCache, hashFile } from '../../cache/index'
|
|
15
|
+
import { DependencyGraph, parseImports } from '../../cache/deps'
|
|
16
|
+
import { compileIncremental, resetCompileCache } from '../../cache/incremental'
|
|
17
|
+
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Helpers
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
function makeTmpDir(): string {
|
|
23
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), 'rs-cache-behavior-'))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function writeFile(dir: string, name: string, content: string): string {
|
|
27
|
+
const filePath = path.join(dir, name)
|
|
28
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true })
|
|
29
|
+
fs.writeFileSync(filePath, content)
|
|
30
|
+
return filePath
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Bump mtime forward so hasChanged detects a modification. */
|
|
34
|
+
function touchFile(filePath: string, offsetMs = 5_000): void {
|
|
35
|
+
const now = Date.now() + offsetMs
|
|
36
|
+
fs.utimesSync(filePath, new Date(now), new Date(now))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Write new content and bump mtime. */
|
|
40
|
+
function modifyFile(filePath: string, newContent: string): void {
|
|
41
|
+
fs.writeFileSync(filePath, newContent)
|
|
42
|
+
touchFile(filePath)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// FileCache — uncovered branches
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
describe('FileCache — stat throws on cached file (branch coverage)', () => {
|
|
50
|
+
test('hasChanged returns true when stat throws after entry is cached', () => {
|
|
51
|
+
const cache = new FileCache('/tmp/test-no-file')
|
|
52
|
+
// Manually insert an entry for a path that does NOT exist on disk
|
|
53
|
+
const fakePath = '/absolutely/nonexistent/ghost.mcrs'
|
|
54
|
+
cache.set(fakePath, { hash: 'deadbeef', mtime: 12345 })
|
|
55
|
+
// stat will throw → branch at line 53 returns true
|
|
56
|
+
expect(cache.hasChanged(fakePath)).toBe(true)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('update on nonexistent file removes entry (catch branch)', () => {
|
|
60
|
+
const tmp = makeTmpDir()
|
|
61
|
+
const cache = new FileCache(tmp)
|
|
62
|
+
// First create file, cache it
|
|
63
|
+
const filePath = writeFile(tmp, 'ghost.mcrs', 'fn ghost() {}')
|
|
64
|
+
cache.update(filePath)
|
|
65
|
+
expect(cache.size).toBe(1)
|
|
66
|
+
|
|
67
|
+
// Delete the file — now update should catch the error and delete the entry
|
|
68
|
+
fs.unlinkSync(filePath)
|
|
69
|
+
// Manually wipe mtime so hasChanged considers it changed
|
|
70
|
+
cache.set(filePath, { hash: 'stale', mtime: 0 })
|
|
71
|
+
cache.update(filePath) // stat throws inside update → delete branch
|
|
72
|
+
expect(cache.get(filePath)).toBeUndefined()
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
describe('FileCache — update HIR on unchanged file', () => {
|
|
77
|
+
test('update with HIR on unchanged file stores HIR without marking changed', () => {
|
|
78
|
+
const tmp = makeTmpDir()
|
|
79
|
+
const cache = new FileCache(tmp)
|
|
80
|
+
const filePath = writeFile(tmp, 'stable.mcrs', 'fn stable() {}')
|
|
81
|
+
// Initial update — mark file as cached
|
|
82
|
+
cache.update(filePath)
|
|
83
|
+
expect(cache.hasChanged(filePath)).toBe(false)
|
|
84
|
+
|
|
85
|
+
// Call update again with a fake HIR on an unchanged file
|
|
86
|
+
const fakeHir = { functions: [] } as any
|
|
87
|
+
const changed = cache.update(filePath, fakeHir)
|
|
88
|
+
expect(changed).toBe(false) // file didn't change
|
|
89
|
+
// HIR should now be attached
|
|
90
|
+
const entry = cache.get(filePath)
|
|
91
|
+
expect(entry?.hir).toBe(fakeHir)
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
describe('FileCache — load with wrong version is ignored', () => {
|
|
96
|
+
test('load skips entries when cache version !== 1', () => {
|
|
97
|
+
const tmp = makeTmpDir()
|
|
98
|
+
const cacheDir = path.join(tmp, '.cache')
|
|
99
|
+
fs.mkdirSync(cacheDir, { recursive: true })
|
|
100
|
+
// Write a v2 cache file
|
|
101
|
+
fs.writeFileSync(
|
|
102
|
+
path.join(cacheDir, 'cache.json'),
|
|
103
|
+
JSON.stringify({ version: 99, entries: { '/some/file.mcrs': { hash: 'abc', mtime: 1 } } }),
|
|
104
|
+
)
|
|
105
|
+
const cache = new FileCache(cacheDir)
|
|
106
|
+
cache.load()
|
|
107
|
+
expect(cache.size).toBe(0) // version mismatch — ignored
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
// Behavior: same code twice → second compile is cached
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
|
|
115
|
+
describe('Cache hit: same code compiled twice', () => {
|
|
116
|
+
let tmpDir: string
|
|
117
|
+
let cacheDir: string
|
|
118
|
+
let outDir: string
|
|
119
|
+
|
|
120
|
+
beforeEach(() => {
|
|
121
|
+
tmpDir = makeTmpDir()
|
|
122
|
+
cacheDir = path.join(tmpDir, '.cache')
|
|
123
|
+
outDir = path.join(tmpDir, 'out')
|
|
124
|
+
resetCompileCache()
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
afterEach(() => {
|
|
128
|
+
fs.rmSync(tmpDir, { recursive: true, force: true })
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
test('second compile of unchanged file produces cache hit', () => {
|
|
132
|
+
const src = writeFile(tmpDir, 'hello.mcrs', 'fn hello() { let x: int = 1; }')
|
|
133
|
+
const cache = new FileCache(cacheDir)
|
|
134
|
+
const depGraph = new DependencyGraph()
|
|
135
|
+
|
|
136
|
+
// First compile — must be a miss
|
|
137
|
+
const r1 = compileIncremental([src], cache, depGraph, { output: outDir })
|
|
138
|
+
expect(r1.recompiled).toBe(1)
|
|
139
|
+
expect(r1.cached).toBe(0)
|
|
140
|
+
|
|
141
|
+
// Second compile — same file, same content → cache hit
|
|
142
|
+
const r2 = compileIncremental([src], cache, depGraph, { output: outDir })
|
|
143
|
+
expect(r2.recompiled).toBe(0)
|
|
144
|
+
expect(r2.cached).toBe(1)
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
test('cache persists across FileCache reload', () => {
|
|
148
|
+
const src = writeFile(tmpDir, 'hello.mcrs', 'fn hello() { let x: int = 1; }')
|
|
149
|
+
|
|
150
|
+
// First pass: compile and save cache to disk
|
|
151
|
+
const cache1 = new FileCache(cacheDir)
|
|
152
|
+
const depGraph1 = new DependencyGraph()
|
|
153
|
+
compileIncremental([src], cache1, depGraph1, { output: outDir })
|
|
154
|
+
cache1.save()
|
|
155
|
+
|
|
156
|
+
// Reset in-memory compile cache to simulate a fresh process
|
|
157
|
+
resetCompileCache()
|
|
158
|
+
|
|
159
|
+
// Second pass: load cache from disk — still a hit for the FileCache checks
|
|
160
|
+
const cache2 = new FileCache(cacheDir)
|
|
161
|
+
cache2.load()
|
|
162
|
+
expect(cache2.hasChanged(src)).toBe(false)
|
|
163
|
+
})
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
// Behavior: modifying code invalidates cache
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
|
|
170
|
+
describe('Cache invalidation: modified source', () => {
|
|
171
|
+
let tmpDir: string
|
|
172
|
+
let cacheDir: string
|
|
173
|
+
let outDir: string
|
|
174
|
+
|
|
175
|
+
beforeEach(() => {
|
|
176
|
+
tmpDir = makeTmpDir()
|
|
177
|
+
cacheDir = path.join(tmpDir, '.cache')
|
|
178
|
+
outDir = path.join(tmpDir, 'out')
|
|
179
|
+
resetCompileCache()
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
afterEach(() => {
|
|
183
|
+
fs.rmSync(tmpDir, { recursive: true, force: true })
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
test('modified file is recompiled after cache hit', () => {
|
|
187
|
+
const src = writeFile(tmpDir, 'counter.mcrs', 'fn counter() { let n: int = 0; }')
|
|
188
|
+
const cache = new FileCache(cacheDir)
|
|
189
|
+
const depGraph = new DependencyGraph()
|
|
190
|
+
|
|
191
|
+
// First compile
|
|
192
|
+
compileIncremental([src], cache, depGraph, { output: outDir })
|
|
193
|
+
|
|
194
|
+
// Modify the file
|
|
195
|
+
modifyFile(src, 'fn counter() { let n: int = 99; }')
|
|
196
|
+
|
|
197
|
+
// hasChanged should now return true
|
|
198
|
+
expect(cache.hasChanged(src)).toBe(true)
|
|
199
|
+
|
|
200
|
+
// Second compile — should recompile
|
|
201
|
+
const r2 = compileIncremental([src], cache, depGraph, { output: outDir })
|
|
202
|
+
expect(r2.recompiled).toBe(1)
|
|
203
|
+
expect(r2.cached).toBe(0)
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
test('mtime change with same content still returns cached (hash match)', () => {
|
|
207
|
+
const tmp2 = makeTmpDir()
|
|
208
|
+
const cache = new FileCache(tmp2)
|
|
209
|
+
const filePath = writeFile(tmp2, 'stable.mcrs', 'fn stable() {}')
|
|
210
|
+
cache.update(filePath)
|
|
211
|
+
|
|
212
|
+
// Touch mtime without changing content
|
|
213
|
+
touchFile(filePath)
|
|
214
|
+
|
|
215
|
+
// mtime changed but hash should match → hasChanged returns false
|
|
216
|
+
expect(cache.hasChanged(filePath)).toBe(false)
|
|
217
|
+
|
|
218
|
+
fs.rmSync(tmp2, { recursive: true, force: true })
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
test('delete file from cache then recompile triggers miss', () => {
|
|
222
|
+
const src = writeFile(tmpDir, 'foo.mcrs', 'fn foo() { let x: int = 5; }')
|
|
223
|
+
const cache = new FileCache(cacheDir)
|
|
224
|
+
const depGraph = new DependencyGraph()
|
|
225
|
+
|
|
226
|
+
// Compile once
|
|
227
|
+
compileIncremental([src], cache, depGraph, { output: outDir })
|
|
228
|
+
expect(cache.hasChanged(src)).toBe(false)
|
|
229
|
+
|
|
230
|
+
// Evict from FileCache
|
|
231
|
+
cache.delete(src)
|
|
232
|
+
expect(cache.hasChanged(src)).toBe(true)
|
|
233
|
+
})
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
// ---------------------------------------------------------------------------
|
|
237
|
+
// Behavior: stdlib / shared module caching
|
|
238
|
+
// ---------------------------------------------------------------------------
|
|
239
|
+
|
|
240
|
+
describe('Stdlib / shared module caching', () => {
|
|
241
|
+
let tmpDir: string
|
|
242
|
+
let cacheDir: string
|
|
243
|
+
let outDir: string
|
|
244
|
+
|
|
245
|
+
beforeEach(() => {
|
|
246
|
+
tmpDir = makeTmpDir()
|
|
247
|
+
cacheDir = path.join(tmpDir, '.cache')
|
|
248
|
+
outDir = path.join(tmpDir, 'out')
|
|
249
|
+
resetCompileCache()
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
afterEach(() => {
|
|
253
|
+
fs.rmSync(tmpDir, { recursive: true, force: true })
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
test('unchanged stdlib module cached across multiple entry files', () => {
|
|
257
|
+
// Simulate a stdlib module shared by many files
|
|
258
|
+
const stdlib = writeFile(tmpDir, 'stdlib/math.mcrs', 'fn math_add(a: int, b: int): int { return a + b; }')
|
|
259
|
+
const file1 = writeFile(tmpDir, 'prog1.mcrs', `import "stdlib/math.mcrs";\nfn prog1() { math_add(1, 2); }`)
|
|
260
|
+
const file2 = writeFile(tmpDir, 'prog2.mcrs', `import "stdlib/math.mcrs";\nfn prog2() { math_add(3, 4); }`)
|
|
261
|
+
|
|
262
|
+
const cache = new FileCache(cacheDir)
|
|
263
|
+
const depGraph = new DependencyGraph()
|
|
264
|
+
|
|
265
|
+
// First compile — all miss
|
|
266
|
+
const r1 = compileIncremental([file1, file2], cache, depGraph, { output: outDir })
|
|
267
|
+
expect(r1.recompiled).toBe(2)
|
|
268
|
+
expect(r1.cached).toBe(0)
|
|
269
|
+
|
|
270
|
+
// Second compile — stdlib unchanged, both files cached
|
|
271
|
+
const r2 = compileIncremental([file1, file2], cache, depGraph, { output: outDir })
|
|
272
|
+
expect(r2.recompiled).toBe(0)
|
|
273
|
+
expect(r2.cached).toBe(2)
|
|
274
|
+
|
|
275
|
+
// Verify stdlib itself is tracked in cache
|
|
276
|
+
expect(cache.hasChanged(stdlib)).toBe(false)
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
test('stdlib change invalidates all dependents', () => {
|
|
280
|
+
const stdlib = writeFile(tmpDir, 'stdlib/core.mcrs', 'fn core_fn() { let v: int = 1; }')
|
|
281
|
+
const file1 = writeFile(tmpDir, 'a.mcrs', `import "stdlib/core.mcrs";\nfn a() { core_fn(); }`)
|
|
282
|
+
const file2 = writeFile(tmpDir, 'b.mcrs', `import "stdlib/core.mcrs";\nfn b() { core_fn(); }`)
|
|
283
|
+
const isolated = writeFile(tmpDir, 'isolated.mcrs', 'fn isolated() { let x: int = 42; }')
|
|
284
|
+
|
|
285
|
+
const cache = new FileCache(cacheDir)
|
|
286
|
+
const depGraph = new DependencyGraph()
|
|
287
|
+
|
|
288
|
+
// Compile all three
|
|
289
|
+
compileIncremental([file1, file2, isolated], cache, depGraph, { output: outDir })
|
|
290
|
+
|
|
291
|
+
// Modify stdlib
|
|
292
|
+
modifyFile(stdlib, 'fn core_fn() { let v: int = 999; }')
|
|
293
|
+
|
|
294
|
+
// Both file1 and file2 depend on stdlib → recompile; isolated is unaffected
|
|
295
|
+
const r2 = compileIncremental([file1, file2, isolated], cache, depGraph, { output: outDir })
|
|
296
|
+
expect(r2.recompiled).toBe(2) // file1 + file2
|
|
297
|
+
expect(r2.cached).toBe(1) // isolated
|
|
298
|
+
expect(r2.errors.size).toBe(0)
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
test('stdlib module hash stays stable when content unchanged', () => {
|
|
302
|
+
const stdlib = writeFile(tmpDir, 'stdlib/stable.mcrs', 'fn stable_fn() { let s: int = 0; }')
|
|
303
|
+
const cache = new FileCache(tmpDir)
|
|
304
|
+
|
|
305
|
+
const h1 = hashFile(stdlib)
|
|
306
|
+
cache.update(stdlib)
|
|
307
|
+
// Reload from entry
|
|
308
|
+
const entry = cache.get(stdlib)
|
|
309
|
+
expect(entry?.hash).toBe(h1)
|
|
310
|
+
|
|
311
|
+
// No modification — hash should remain identical
|
|
312
|
+
const h2 = hashFile(stdlib)
|
|
313
|
+
expect(h1).toBe(h2)
|
|
314
|
+
expect(cache.hasChanged(stdlib)).toBe(false)
|
|
315
|
+
})
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
// ---------------------------------------------------------------------------
|
|
319
|
+
// DependencyGraph — uncovered branches (line 52, 125-130)
|
|
320
|
+
// ---------------------------------------------------------------------------
|
|
321
|
+
|
|
322
|
+
describe('DependencyGraph — edge cases', () => {
|
|
323
|
+
let tmpDir: string
|
|
324
|
+
|
|
325
|
+
beforeEach(() => {
|
|
326
|
+
tmpDir = makeTmpDir()
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
afterEach(() => {
|
|
330
|
+
fs.rmSync(tmpDir, { recursive: true, force: true })
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
test('removeFile removes the file from the graph', () => {
|
|
334
|
+
const a = writeFile(tmpDir, 'a.mcrs', 'fn a() {}')
|
|
335
|
+
const graph = new DependencyGraph()
|
|
336
|
+
graph.addFile(a)
|
|
337
|
+
expect(graph.getAllFiles()).toContain(path.resolve(a))
|
|
338
|
+
graph.removeFile(a)
|
|
339
|
+
expect(graph.getAllFiles()).not.toContain(path.resolve(a))
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
test('getAllFiles returns all tracked files', () => {
|
|
343
|
+
const a = writeFile(tmpDir, 'a.mcrs', 'fn a() {}')
|
|
344
|
+
const b = writeFile(tmpDir, 'b.mcrs', 'fn b() {}')
|
|
345
|
+
const graph = new DependencyGraph()
|
|
346
|
+
graph.addFile(a)
|
|
347
|
+
graph.addFile(b)
|
|
348
|
+
const files = graph.getAllFiles()
|
|
349
|
+
expect(files).toHaveLength(2)
|
|
350
|
+
expect(files).toContain(path.resolve(a))
|
|
351
|
+
expect(files).toContain(path.resolve(b))
|
|
352
|
+
})
|
|
353
|
+
|
|
354
|
+
test('clear empties the graph', () => {
|
|
355
|
+
const a = writeFile(tmpDir, 'a.mcrs', 'fn a() {}')
|
|
356
|
+
const graph = new DependencyGraph()
|
|
357
|
+
graph.addFile(a)
|
|
358
|
+
expect(graph.getAllFiles()).toHaveLength(1)
|
|
359
|
+
graph.clear()
|
|
360
|
+
expect(graph.getAllFiles()).toHaveLength(0)
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
test('getDirectDeps returns empty set for unknown file', () => {
|
|
364
|
+
const graph = new DependencyGraph()
|
|
365
|
+
const deps = graph.getDirectDeps('/nonexistent.mcrs')
|
|
366
|
+
expect(deps.size).toBe(0)
|
|
367
|
+
})
|
|
368
|
+
|
|
369
|
+
test('parseImports with inline source string (no disk read)', () => {
|
|
370
|
+
const source = `import "util.mcrs";\nimport "math.mcrs";\nfn main() {}`
|
|
371
|
+
const fakePath = path.join(tmpDir, 'main.mcrs')
|
|
372
|
+
const imports = parseImports(fakePath, source)
|
|
373
|
+
expect(imports).toHaveLength(2)
|
|
374
|
+
expect(imports[0]).toBe(path.resolve(tmpDir, 'util.mcrs'))
|
|
375
|
+
expect(imports[1]).toBe(path.resolve(tmpDir, 'math.mcrs'))
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
test('cyclic dependency does not cause infinite loop in getTransitiveDeps', () => {
|
|
379
|
+
// Simulate a cycle: a → b → a (shouldn't happen in practice but must be safe)
|
|
380
|
+
const a = path.resolve(tmpDir, 'a.mcrs')
|
|
381
|
+
const b = path.resolve(tmpDir, 'b.mcrs')
|
|
382
|
+
writeFile(tmpDir, 'a.mcrs', 'fn a() {}')
|
|
383
|
+
writeFile(tmpDir, 'b.mcrs', 'fn b() {}')
|
|
384
|
+
|
|
385
|
+
const graph = new DependencyGraph()
|
|
386
|
+
// Manually force a cycle via addFile with inline source
|
|
387
|
+
graph.addFile(a, `import "b.mcrs";\nfn a() {}`)
|
|
388
|
+
graph.addFile(b, `import "a.mcrs";\nfn b() {}`)
|
|
389
|
+
|
|
390
|
+
// Should not throw or loop forever
|
|
391
|
+
expect(() => graph.getTransitiveDeps(a)).not.toThrow()
|
|
392
|
+
const deps = graph.getTransitiveDeps(a)
|
|
393
|
+
expect(deps.has(b)).toBe(true)
|
|
394
|
+
})
|
|
395
|
+
})
|
|
396
|
+
|
|
397
|
+
// ---------------------------------------------------------------------------
|
|
398
|
+
// compileIncremental — uncovered branches (lines 67, 113)
|
|
399
|
+
// ---------------------------------------------------------------------------
|
|
400
|
+
|
|
401
|
+
describe('compileIncremental — edge cases', () => {
|
|
402
|
+
let tmpDir: string
|
|
403
|
+
let cacheDir: string
|
|
404
|
+
let outDir: string
|
|
405
|
+
|
|
406
|
+
beforeEach(() => {
|
|
407
|
+
tmpDir = makeTmpDir()
|
|
408
|
+
cacheDir = path.join(tmpDir, '.cache')
|
|
409
|
+
outDir = path.join(tmpDir, 'out')
|
|
410
|
+
resetCompileCache()
|
|
411
|
+
})
|
|
412
|
+
|
|
413
|
+
afterEach(() => {
|
|
414
|
+
fs.rmSync(tmpDir, { recursive: true, force: true })
|
|
415
|
+
})
|
|
416
|
+
|
|
417
|
+
test('deleted entry file is removed from dep graph gracefully', () => {
|
|
418
|
+
// Write a file, then delete it before compileIncremental runs
|
|
419
|
+
const ghost = path.join(tmpDir, 'ghost.mcrs')
|
|
420
|
+
fs.writeFileSync(ghost, 'fn ghost() {}')
|
|
421
|
+
fs.unlinkSync(ghost)
|
|
422
|
+
|
|
423
|
+
const cache = new FileCache(cacheDir)
|
|
424
|
+
const depGraph = new DependencyGraph()
|
|
425
|
+
|
|
426
|
+
// Should not throw; error captured in result
|
|
427
|
+
const r = compileIncremental([ghost], cache, depGraph, { output: outDir })
|
|
428
|
+
// Either an error is captured or the file is skipped
|
|
429
|
+
expect(r.recompiled + r.errors.size).toBeGreaterThanOrEqual(0)
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
test('dep count change triggers recompile (depHashes.size mismatch branch)', () => {
|
|
433
|
+
// Compile 'a' with no deps first
|
|
434
|
+
const a = writeFile(tmpDir, 'a.mcrs', 'fn a_func() { let x: int = 1; }')
|
|
435
|
+
const cache = new FileCache(cacheDir)
|
|
436
|
+
const depGraph = new DependencyGraph()
|
|
437
|
+
|
|
438
|
+
// First compile: a has no deps
|
|
439
|
+
const r1 = compileIncremental([a], cache, depGraph, { output: outDir })
|
|
440
|
+
expect(r1.recompiled).toBe(1)
|
|
441
|
+
|
|
442
|
+
// Now add a new dep to a — simulate by modifying a to import lib, then compile
|
|
443
|
+
const lib = writeFile(tmpDir, 'lib.mcrs', 'fn lib_fn() { let l: int = 0; }')
|
|
444
|
+
modifyFile(a, `import "lib.mcrs";\nfn a_func() { lib_fn(); }`)
|
|
445
|
+
|
|
446
|
+
// Second compile: a now has one dep → depHashes.size mismatch triggers recompile
|
|
447
|
+
const r2 = compileIncremental([a], cache, depGraph, { output: outDir })
|
|
448
|
+
expect(r2.recompiled).toBe(1)
|
|
449
|
+
expect(r2.errors.size).toBe(0)
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
test('multiple files: partial recompile on single change', () => {
|
|
453
|
+
const files = ['fn1', 'fn2', 'fn3'].map(name =>
|
|
454
|
+
writeFile(tmpDir, `${name}.mcrs`, `fn ${name}() { let x: int = 1; }`)
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
const cache = new FileCache(cacheDir)
|
|
458
|
+
const depGraph = new DependencyGraph()
|
|
459
|
+
|
|
460
|
+
// First compile — all miss
|
|
461
|
+
const r1 = compileIncremental(files, cache, depGraph, { output: outDir })
|
|
462
|
+
expect(r1.recompiled).toBe(3)
|
|
463
|
+
|
|
464
|
+
// Modify only fn2
|
|
465
|
+
modifyFile(files[1], 'fn fn2() { let x: int = 999; }')
|
|
466
|
+
|
|
467
|
+
const r2 = compileIncremental(files, cache, depGraph, { output: outDir })
|
|
468
|
+
expect(r2.recompiled).toBe(1)
|
|
469
|
+
expect(r2.cached).toBe(2)
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
test('empty file list returns zero counts', () => {
|
|
473
|
+
const cache = new FileCache(cacheDir)
|
|
474
|
+
const depGraph = new DependencyGraph()
|
|
475
|
+
const r = compileIncremental([], cache, depGraph, { output: outDir })
|
|
476
|
+
expect(r.recompiled).toBe(0)
|
|
477
|
+
expect(r.cached).toBe(0)
|
|
478
|
+
expect(r.errors.size).toBe(0)
|
|
479
|
+
})
|
|
480
|
+
})
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extra coverage for src/cache/index.ts
|
|
3
|
+
* Targets: save/load, hasChanged with mtime, update branches, delete, clear.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as fs from 'fs'
|
|
7
|
+
import * as os from 'os'
|
|
8
|
+
import * as path from 'path'
|
|
9
|
+
import { FileCache, hashFile } from '../cache'
|
|
10
|
+
|
|
11
|
+
function makeTmpDir(): string {
|
|
12
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), 'rs-cache-test-'))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function writeTmpFile(dir: string, name: string, content: string): string {
|
|
16
|
+
const p = path.join(dir, name)
|
|
17
|
+
fs.writeFileSync(p, content)
|
|
18
|
+
return p
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('FileCache — basic get/set', () => {
|
|
22
|
+
test('get returns undefined for unknown file', () => {
|
|
23
|
+
const cache = new FileCache('/tmp/test-cache-nonexistent')
|
|
24
|
+
expect(cache.get('/nonexistent/file.mcrs')).toBeUndefined()
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('set then get returns entry', () => {
|
|
28
|
+
const cache = new FileCache('/tmp/test-cache')
|
|
29
|
+
const filePath = '/tmp/fake.mcrs'
|
|
30
|
+
cache.set(filePath, { hash: 'abc123', mtime: 1000 })
|
|
31
|
+
const entry = cache.get(filePath)
|
|
32
|
+
expect(entry).toBeDefined()
|
|
33
|
+
expect(entry!.hash).toBe('abc123')
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('size reflects number of entries', () => {
|
|
37
|
+
const cache = new FileCache('/tmp/test-cache')
|
|
38
|
+
expect(cache.size).toBe(0)
|
|
39
|
+
cache.set('/tmp/a.mcrs', { hash: 'h1', mtime: 1 })
|
|
40
|
+
cache.set('/tmp/b.mcrs', { hash: 'h2', mtime: 2 })
|
|
41
|
+
expect(cache.size).toBe(2)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('delete removes an entry', () => {
|
|
45
|
+
const cache = new FileCache('/tmp/test-cache')
|
|
46
|
+
cache.set('/tmp/a.mcrs', { hash: 'h1', mtime: 1 })
|
|
47
|
+
expect(cache.size).toBe(1)
|
|
48
|
+
cache.delete('/tmp/a.mcrs')
|
|
49
|
+
expect(cache.size).toBe(0)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
test('clear removes all entries', () => {
|
|
53
|
+
const cache = new FileCache('/tmp/test-cache')
|
|
54
|
+
cache.set('/tmp/a.mcrs', { hash: 'h1', mtime: 1 })
|
|
55
|
+
cache.set('/tmp/b.mcrs', { hash: 'h2', mtime: 2 })
|
|
56
|
+
cache.clear()
|
|
57
|
+
expect(cache.size).toBe(0)
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
describe('FileCache — hasChanged', () => {
|
|
62
|
+
test('returns true for uncached file', () => {
|
|
63
|
+
const tmp = makeTmpDir()
|
|
64
|
+
const cache = new FileCache(tmp)
|
|
65
|
+
const filePath = writeTmpFile(tmp, 'test.mcrs', 'hello')
|
|
66
|
+
expect(cache.hasChanged(filePath)).toBe(true)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test('returns false when mtime matches', () => {
|
|
70
|
+
const tmp = makeTmpDir()
|
|
71
|
+
const cache = new FileCache(tmp)
|
|
72
|
+
const filePath = writeTmpFile(tmp, 'test.mcrs', 'hello')
|
|
73
|
+
const stat = fs.statSync(filePath)
|
|
74
|
+
cache.set(filePath, { hash: 'irrelevant', mtime: stat.mtimeMs })
|
|
75
|
+
expect(cache.hasChanged(filePath)).toBe(false)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test('returns true when content hash differs (mtime changed)', () => {
|
|
79
|
+
const tmp = makeTmpDir()
|
|
80
|
+
const cache = new FileCache(tmp)
|
|
81
|
+
const filePath = writeTmpFile(tmp, 'test.mcrs', 'hello')
|
|
82
|
+
// Cache with old mtime (0) and wrong hash
|
|
83
|
+
cache.set(filePath, { hash: 'wronghash', mtime: 0 })
|
|
84
|
+
// mtime is different → compare hash
|
|
85
|
+
expect(cache.hasChanged(filePath)).toBe(true)
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
test('returns true for nonexistent file', () => {
|
|
89
|
+
const cache = new FileCache('/tmp/nonexistent-cache')
|
|
90
|
+
expect(cache.hasChanged('/tmp/definitelynotafile.mcrs')).toBe(true)
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
describe('FileCache — update', () => {
|
|
95
|
+
test('update on changed file returns true and caches entry', () => {
|
|
96
|
+
const tmp = makeTmpDir()
|
|
97
|
+
const cache = new FileCache(tmp)
|
|
98
|
+
const filePath = writeTmpFile(tmp, 'test.mcrs', 'content')
|
|
99
|
+
const changed = cache.update(filePath)
|
|
100
|
+
expect(changed).toBe(true)
|
|
101
|
+
expect(cache.get(filePath)).toBeDefined()
|
|
102
|
+
expect(cache.get(filePath)!.hash).toBeTruthy()
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
test('update on unchanged file returns false', () => {
|
|
106
|
+
const tmp = makeTmpDir()
|
|
107
|
+
const cache = new FileCache(tmp)
|
|
108
|
+
const filePath = writeTmpFile(tmp, 'test.mcrs', 'content')
|
|
109
|
+
cache.update(filePath) // first call: changed
|
|
110
|
+
const changed2 = cache.update(filePath) // second call: not changed
|
|
111
|
+
expect(changed2).toBe(false)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
test('update stores HIR when provided and content changed', () => {
|
|
115
|
+
const tmp = makeTmpDir()
|
|
116
|
+
const cache = new FileCache(tmp)
|
|
117
|
+
const filePath = writeTmpFile(tmp, 'test.mcrs', 'content')
|
|
118
|
+
const fakeHir = { namespace: 'test', functions: [], structs: [], enums: [], implBlocks: [], imports: [] } as any
|
|
119
|
+
cache.update(filePath, fakeHir)
|
|
120
|
+
expect(cache.get(filePath)!.hir).toBe(fakeHir)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
test('update stores HIR when content unchanged but HIR provided', () => {
|
|
124
|
+
const tmp = makeTmpDir()
|
|
125
|
+
const cache = new FileCache(tmp)
|
|
126
|
+
const filePath = writeTmpFile(tmp, 'test.mcrs', 'content')
|
|
127
|
+
cache.update(filePath) // mark as cached
|
|
128
|
+
// Second update with HIR but no content change
|
|
129
|
+
const fakeHir = { namespace: 'test2', functions: [], structs: [], enums: [], implBlocks: [], imports: [] } as any
|
|
130
|
+
cache.update(filePath, fakeHir)
|
|
131
|
+
expect(cache.get(filePath)!.hir).toBe(fakeHir)
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
describe('FileCache — save/load', () => {
|
|
136
|
+
test('save and load round-trip persists entries', () => {
|
|
137
|
+
const tmp = makeTmpDir()
|
|
138
|
+
const cache = new FileCache(tmp)
|
|
139
|
+
const filePath = writeTmpFile(tmp, 'test.mcrs', 'hello world')
|
|
140
|
+
cache.update(filePath)
|
|
141
|
+
cache.save()
|
|
142
|
+
|
|
143
|
+
// Load into a new cache instance
|
|
144
|
+
const cache2 = new FileCache(tmp)
|
|
145
|
+
cache2.load()
|
|
146
|
+
const entry = cache2.get(filePath)
|
|
147
|
+
expect(entry).toBeDefined()
|
|
148
|
+
expect(entry!.hash).toBe(cache.get(filePath)!.hash)
|
|
149
|
+
expect(entry!.mtime).toBe(cache.get(filePath)!.mtime)
|
|
150
|
+
// HIR is NOT persisted
|
|
151
|
+
expect(entry!.hir).toBeUndefined()
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
test('load silently ignores missing cache file', () => {
|
|
155
|
+
const tmp = makeTmpDir()
|
|
156
|
+
const cache = new FileCache(tmp)
|
|
157
|
+
expect(() => cache.load()).not.toThrow()
|
|
158
|
+
expect(cache.size).toBe(0)
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
test('load silently ignores corrupt cache file', () => {
|
|
162
|
+
const tmp = makeTmpDir()
|
|
163
|
+
fs.writeFileSync(path.join(tmp, 'cache.json'), 'not valid json{{{')
|
|
164
|
+
const cache = new FileCache(tmp)
|
|
165
|
+
expect(() => cache.load()).not.toThrow()
|
|
166
|
+
expect(cache.size).toBe(0)
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
test('load ignores wrong version', () => {
|
|
170
|
+
const tmp = makeTmpDir()
|
|
171
|
+
fs.writeFileSync(path.join(tmp, 'cache.json'), JSON.stringify({ version: 99, entries: {} }))
|
|
172
|
+
const cache = new FileCache(tmp)
|
|
173
|
+
cache.load()
|
|
174
|
+
expect(cache.size).toBe(0)
|
|
175
|
+
})
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
describe('hashFile', () => {
|
|
179
|
+
test('returns a hex string', () => {
|
|
180
|
+
const tmp = makeTmpDir()
|
|
181
|
+
const filePath = writeTmpFile(tmp, 'test.mcrs', 'hello')
|
|
182
|
+
const hash = hashFile(filePath)
|
|
183
|
+
expect(hash).toMatch(/^[0-9a-f]{64}$/)
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
test('same content gives same hash', () => {
|
|
187
|
+
const tmp = makeTmpDir()
|
|
188
|
+
const f1 = writeTmpFile(tmp, 'a.mcrs', 'same content')
|
|
189
|
+
const f2 = writeTmpFile(tmp, 'b.mcrs', 'same content')
|
|
190
|
+
expect(hashFile(f1)).toBe(hashFile(f2))
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
test('different content gives different hash', () => {
|
|
194
|
+
const tmp = makeTmpDir()
|
|
195
|
+
const f1 = writeTmpFile(tmp, 'a.mcrs', 'hello')
|
|
196
|
+
const f2 = writeTmpFile(tmp, 'b.mcrs', 'world')
|
|
197
|
+
expect(hashFile(f1)).not.toBe(hashFile(f2))
|
|
198
|
+
})
|
|
199
|
+
})
|