[PR #4023] [MERGED] fix(javascript): keep Vite dependency slots after a spread unknown #5997

Closed
opened 2026-10-31 01:11:03 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/4023
Author: @Sriram-PR
Created: 10/15/2026
Status: ✅ Merged
Merged: 10/21/2026
Merged by: @morluto

Base: main ← Head: fix/vite-deps-spread-unknown


📝 Commits (1)

  • e3e3b00 fix(javascript): keep Vite dependency slots after a spread unknown

📊 Changes

2 files changed (+23 additions, -1 deletions)

View changed files

📝 src/domain/javascript/javascriptStaticAnalysisCalls.ts (+8 -1)
📝 src/domain/javascript/javascriptVitePreloadDependencies.test.ts (+15 -0)

📄 Description

Summary

indexVitePreloadDependencyTable maps each element of the __vite__mapDeps cache initializer to one table slot. A spread element became a single undefined slot, so every entry after it kept a definite index even though the spread can contribute any number of elements. With ["./first.js", ...["./middle-a.js", "./middle-b.js"], "./last.js"], __vite__mapDeps([0, 2]) selects middle-b.js at runtime, but static analysis published a resolved dynamic-import edge to last.js.

Fixes #3907

Problem and expected behavior

Smallest trigger: the fixture from the issue (a directory with main.mjs holding the helper above plus first.js, middle-a.js, middle-b.js, last.js). analyze-javascript-application returned dynamic-import edges for first.js and last.js, both resolved. Expected (from the issue): index 0 stays first.js, and index 2 must not resolve to last.js; it either expands the spread or stays unknown.

Change and scope

  • src/domain/javascript/javascriptStaticAnalysisCalls.ts: the table keeps only the entries before the first spread. Indexes from the spread onward fall outside the table and are reported as unknown, the same way an out-of-range or dynamic index already is.
  • Entries before the spread, holes, non-string entries, and tables without a spread are unchanged.
  • Not included: expanding literal spreads. Getting the length right would mean handling holes in the spread array, string spreads, nested spreads and so on, and a wrong length would publish another wrong resolved edge. Unknown is the existing fallback for slots the indexer cannot place.

Contribution scope: ordinary fix within existing boundaries; no scope decision needed.

Contract and boundary impact

  • Semantic owner and earliest changed stage: indexVitePreloadDependencyTable in src/domain/javascript/javascriptStaticAnalysisCalls.ts, when static analysis indexes the helper's cache table.
  • Contribution scope fit and linked maintainer decision: not applicable (bug fix, #3907).
  • CLI and MCP/tool-catalog contract: no schema change. For a table with a spread, slots from the spread onward produce an unknown dynamic-import reference (specifier: null) instead of a resolved edge to a later entry.
  • Provider, bridge, target-format, or platform compatibility: none.
  • Evidence, artifact, provenance, or reconstruction contract: fewer resolved dynamic-import edges for spread tables; the unknown edge stays visible with its __vite__mapDeps(...) expression.
  • Target selection, authority, upstream behavior, and cleanup details: not applicable.
  • Generated metadata, package, or installation impact: none.

Expected effects (check known effects; use documentation-only on its own).
Unchecked items do not establish absence; leave uncertainties visible.

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

  • Tests added or updated: src/domain/javascript/javascriptVitePreloadDependencies.test.ts adds "keeps table slots from a spread onward unknown", using the issue's table and __vite__mapDeps([0, 2]), and expects ["./first.js", null].
  • Base reproduction: on the base revision the new test fails with expected [ './first.js', './last.js' ] to deeply equal [ './first.js', null ].
  • User-visible CLI output (analyze-javascript-application <dir> --artifact-format directory --json, dynamic-import edges as specifier -> resolved_path (resolution_status)):
    fixture  base                                                    PR
    spread   ./first.js -> first.js (resolved)                       ./first.js -> first.js (resolved)
             ./last.js -> last.js (resolved)                         null -> null (null), expression __vite__mapDeps([0, 2])
    flat     ./first.js -> first.js, ./middle-b.js -> middle-b.js    unchanged
    
  • Real Vite output: built a small code-split app with Vite 8.3.4 (vite build --minify false; the helper's table is a flat array, __vite__mapDeps([0,1,2,3]) and ([4,1,2,5])). analyze-javascript-application on dist/ gives an identical normalized_result on base and on this branch, so real builds without a spread are unaffected.
  • Remaining proof gaps: Vite does not emit a spread in the table itself, so the spread case is covered by the issue's fixture and the unit test.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

  • npm run test:local -- src/domain/javascript/*.test.ts (74 files): 1734 passed (the new test fails on the base revision)
  • npm run test:focused -- tests/boundary/filesystem/javascript-applications/javascriptBundlerAdapters.test.ts tests/boundary/process/sourceMapUncHosts.test.ts: 13 passed
  • npm run check:fast: typecheck and lint passed
  • CLI comparison above, built with npm run build:cached on base and on this branch

Compatibility, safety, and release

  • Breaking changes or migration steps: none.
  • Real Hopper/Ghidra, browser, or OS coverage: Linux x64, Node 24.18.0; no provider or browser involved.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: none.

Author readiness

Human owner: @Sriram-PR

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/4023 **Author:** [@Sriram-PR](https://github.com/Sriram-PR) **Created:** 10/15/2026 **Status:** ✅ Merged **Merged:** 10/21/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `fix/vite-deps-spread-unknown` --- ### 📝 Commits (1) - [`e3e3b00`](https://github.com/morluto/rea/commit/e3e3b00fa3e9b468b4da5b76f084ab426971d1df) fix(javascript): keep Vite dependency slots after a spread unknown ### 📊 Changes **2 files changed** (+23 additions, -1 deletions) <details> <summary>View changed files</summary> 📝 `src/domain/javascript/javascriptStaticAnalysisCalls.ts` (+8 -1) 📝 `src/domain/javascript/javascriptVitePreloadDependencies.test.ts` (+15 -0) </details> ### 📄 Description ## Summary `indexVitePreloadDependencyTable` maps each element of the `__vite__mapDeps` cache initializer to one table slot. A spread element became a single `undefined` slot, so every entry after it kept a definite index even though the spread can contribute any number of elements. With `["./first.js", ...["./middle-a.js", "./middle-b.js"], "./last.js"]`, `__vite__mapDeps([0, 2])` selects `middle-b.js` at runtime, but static analysis published a resolved dynamic-import edge to `last.js`. Fixes #3907 ## Problem and expected behavior Smallest trigger: the fixture from the issue (a directory with `main.mjs` holding the helper above plus `first.js`, `middle-a.js`, `middle-b.js`, `last.js`). `analyze-javascript-application` returned dynamic-import edges for `first.js` and `last.js`, both `resolved`. Expected (from the issue): index 0 stays `first.js`, and index 2 must not resolve to `last.js`; it either expands the spread or stays unknown. ## Change and scope - `src/domain/javascript/javascriptStaticAnalysisCalls.ts`: the table keeps only the entries before the first spread. Indexes from the spread onward fall outside the table and are reported as unknown, the same way an out-of-range or dynamic index already is. - Entries before the spread, holes, non-string entries, and tables without a spread are unchanged. - Not included: expanding literal spreads. Getting the length right would mean handling holes in the spread array, string spreads, nested spreads and so on, and a wrong length would publish another wrong resolved edge. Unknown is the existing fallback for slots the indexer cannot place. Contribution scope: ordinary fix within existing boundaries; no scope decision needed. ## Contract and boundary impact - Semantic owner and earliest changed stage: `indexVitePreloadDependencyTable` in `src/domain/javascript/javascriptStaticAnalysisCalls.ts`, when static analysis indexes the helper's cache table. - Contribution scope fit and linked maintainer decision: not applicable (bug fix, #3907). - CLI and MCP/tool-catalog contract: no schema change. For a table with a spread, slots from the spread onward produce an unknown dynamic-import reference (`specifier: null`) instead of a resolved edge to a later entry. - Provider, bridge, target-format, or platform compatibility: none. - Evidence, artifact, provenance, or reconstruction contract: fewer resolved dynamic-import edges for spread tables; the unknown edge stays visible with its `__vite__mapDeps(...)` expression. - Target selection, authority, upstream behavior, and cleanup details: not applicable. - Generated metadata, package, or installation impact: none. Expected effects (check known effects; use documentation-only on its own). Unchecked items do not establish absence; leave uncertainties visible. - [x] Read existing files or captured data. - [ ] Launch or attach to a process. - [ ] Inject instrumentation or run scripts/code. - [ ] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage - Tests added or updated: `src/domain/javascript/javascriptVitePreloadDependencies.test.ts` adds "keeps table slots from a spread onward unknown", using the issue's table and `__vite__mapDeps([0, 2])`, and expects `["./first.js", null]`. - Base reproduction: on the base revision the new test fails with `expected [ './first.js', './last.js' ] to deeply equal [ './first.js', null ]`. - User-visible CLI output (`analyze-javascript-application <dir> --artifact-format directory --json`, dynamic-import edges as `specifier -> resolved_path (resolution_status)`): ``` fixture base PR spread ./first.js -> first.js (resolved) ./first.js -> first.js (resolved) ./last.js -> last.js (resolved) null -> null (null), expression __vite__mapDeps([0, 2]) flat ./first.js -> first.js, ./middle-b.js -> middle-b.js unchanged ``` - Real Vite output: built a small code-split app with Vite 8.3.4 (`vite build --minify false`; the helper's table is a flat array, `__vite__mapDeps([0,1,2,3])` and `([4,1,2,5])`). `analyze-javascript-application` on `dist/` gives an identical `normalized_result` on base and on this branch, so real builds without a spread are unaffected. - Remaining proof gaps: Vite does not emit a spread in the table itself, so the spread case is covered by the issue's fixture and the unit test. For evidence-bearing changes: - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed - `npm run test:local -- src/domain/javascript/*.test.ts` (74 files): 1734 passed (the new test fails on the base revision) - `npm run test:focused -- tests/boundary/filesystem/javascript-applications/javascriptBundlerAdapters.test.ts tests/boundary/process/sourceMapUncHosts.test.ts`: 13 passed - `npm run check:fast`: typecheck and lint passed - CLI comparison above, built with `npm run build:cached` on base and on this branch ## Compatibility, safety, and release - Breaking changes or migration steps: none. - Real Hopper/Ghidra, browser, or OS coverage: Linux x64, Node 24.18.0; no provider or browser involved. - Package or release metadata impact: none. - Security, privacy, process, or containment review: none. ## Author readiness Human owner: @Sriram-PR - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:11:03 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#5997
No description provided.