[PR #4165] [MERGED] fix(browser): omit erased type-only import-equals from source-map dependencies #6104

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

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/4165
Author: @kaoru0822-kitauji
Created: 10/15/2026
Status: ✅ Merged
Merged: 10/15/2026
Merged by: @kaoru0822-kitauji

Base: main ← Head: fix/3932-sourcemap-type-import-equals


📝 Commits (1)

  • ff6d33a fix(browser): omit erased type-only import-equals from source-map dependencies

📊 Changes

6 files changed (+31 additions, -24 deletions)

View changed files

📝 src/browser/WebSourceMapFetcher.ts (+7 -11)
📝 src/domain/javascript/javascriptModuleDeclaration.ts (+13 -0)
📝 src/domain/javascript/javascriptSemanticAnalysis.ts (+4 -2)
📝 src/domain/javascript/javascriptSemanticProjection.ts (+1 -10)
📝 src/domain/javascript/javascriptStaticAnalysis.ts (+1 -1)
📝 tests/boundary/browser/webSourceMapFetcher.test.ts (+5 -0)

📄 Description

Summary

Fixes #3932. analyze_web_bundle and analyze-web-bundle --fetch-source-maps reported a require dependency for import type X = require("m") in a source map's original source. TypeScript erases that declaration. Source-map dependency recovery now uses the same value-only import-equals rule as the JavaScript static and semantic analyzers. The value form import Y = require("n") is still reported.

Problem and expected behavior

originalDependency in src/browser/WebSourceMapFetcher.ts re-derived import-equals targets and accepted any external module reference, so it never checked importKind === "type". The rule already existed as semanticImportEqualsSpecifier in the JavaScript semantic projection, used by the static and semantic analyzers. The fetcher did not use it.

The issue's fixture, run through the registered MCP tool and the built CLI against the repository's fake CDP browser. The original source has import type X = require("m"), import Y = require("n"), and whole-statement import type / export type controls:

adapter main this PR
MCP require:m, require:n; 5,016 bytes; 31 ms require:n; 4,911 bytes; 32–41 ms
CLI require:m, require:n; 5,016 bytes; 381 ms require:n; 4,911 bytes; 405–434 ms

In both builds the map is included, the original source text is retained exactly, and the whole-statement type-only controls produce no edge. Timings are single runs; CLI time is process startup.

Change and scope

  • semanticImportEqualsSpecifier moves to src/domain/javascript/javascriptModuleDeclaration.ts, next to the other TypeScript erasure predicates (isTypeOnlyImportDeclaration and the others). Static analysis, semantic analysis, semantic projection, and the source-map fetcher import it from there. Its behavior is unchanged.
  • The fetcher returns a require edge only for a value import-equals. Its separate external-module check is removed.
  • The reference-source importer is intentionally unchanged: its dependency graph records type imports as source dependencies, including import type { T } from.

Contract and boundary impact

  • Semantic owner and earliest changed stage: the module-declaration erasure predicates own the import-equals rule; source-map dependency recovery consumes it.

  • Contribution scope fit and linked maintainer decision: a bug fix within existing static source-map analysis; not applicable.

  • CLI and MCP/tool-catalog contract: schemas unchanged.

  • Provider, bridge, target-format, or platform compatibility: provider-independent; no browser behavior changes.

  • Evidence, artifact, provenance, or reconstruction contract: no false runtime dependency candidate for an erased declaration. Original source bytes are retained.

  • Target selection, authority, upstream behavior, and cleanup details: not applicable.

  • Generated metadata, package, or installation impact: none.

  • Read existing files or captured data.

Evidence and regression coverage

  • tests/boundary/browser/webSourceMapFetcher.test.ts adds a "type-only import equals" case: import type Types = require("./types.js") together with import lib = require("./lib.js") yields only ./lib.js. It fails with main's fetcher and passes with the fix. The existing cases for value import-equals, local aliases, and whole-statement type-only imports and exports still pass.
  • Real data: the three largest installed source maps with embedded TypeScript sources, run through fetchWebSourceMaps with an in-process fetch host (median of 3):
source map status sources edges edge digest (main = PR) result bytes main this PR
openpgp/dist/openpgp.min.js.map included 124 431 57a8e7b0579df4a8 19,163,284 133 ms 143–148 ms
@babel/parser/lib/index.js.map partial 43 129 681f4cea034f0e46 20,209,227 152 ms 154–162 ms
@babel/parser (@vue/compiler-core copy) partial 42 127 9e254929abcaaf9f 21,667,679 162 ms 164–169 ms

The results are byte-identical and the timing differences are within run-to-run noise. None of the 287 installed TypeScript source maps contains an import-equals declaration, so the changed branch is exercised only by the fixtures.

  • Remaining proof gaps: a real browser and real served bundles were not used. The MCP and CLI evidence above uses the repository's fake CDP browser at the production protocol boundary.

Validation performed

  • npx vitest run tests/boundary/browser/webSourceMapFetcher.test.ts — 82 passed; with main's fetcher, the new case failed.
  • npx vitest run src/domain/javascript tests/boundary/browser src/browser — 158 files passed, 1 skipped; 2,802 tests passed, 6 skipped.
  • npm run check:fast — passed.
  • MCP and CLI runs on the issue fixture and the real-map runs above, on both builds. Both were temporary tests and are not committed.

Compatibility, safety, and release

  • Breaking changes or migration steps: none.
  • Real Hopper/Ghidra, browser, or OS coverage: no real browser; macOS arm64, Node 26.5.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: static parsing only.

Author readiness

Human owner:

  • 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.

🤖 Generated with Claude Code


🔄 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/4165 **Author:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Created:** 10/15/2026 **Status:** ✅ Merged **Merged:** 10/15/2026 **Merged by:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Base:** `main` ← **Head:** `fix/3932-sourcemap-type-import-equals` --- ### 📝 Commits (1) - [`ff6d33a`](https://github.com/morluto/rea/commit/ff6d33adfbc6c1e9c2209089a726f043515dfdfc) fix(browser): omit erased type-only import-equals from source-map dependencies ### 📊 Changes **6 files changed** (+31 additions, -24 deletions) <details> <summary>View changed files</summary> 📝 `src/browser/WebSourceMapFetcher.ts` (+7 -11) 📝 `src/domain/javascript/javascriptModuleDeclaration.ts` (+13 -0) 📝 `src/domain/javascript/javascriptSemanticAnalysis.ts` (+4 -2) 📝 `src/domain/javascript/javascriptSemanticProjection.ts` (+1 -10) 📝 `src/domain/javascript/javascriptStaticAnalysis.ts` (+1 -1) 📝 `tests/boundary/browser/webSourceMapFetcher.test.ts` (+5 -0) </details> ### 📄 Description ## Summary Fixes #3932. `analyze_web_bundle` and `analyze-web-bundle --fetch-source-maps` reported a `require` dependency for `import type X = require("m")` in a source map's original source. TypeScript erases that declaration. Source-map dependency recovery now uses the same value-only import-equals rule as the JavaScript static and semantic analyzers. The value form `import Y = require("n")` is still reported. ## Problem and expected behavior `originalDependency` in `src/browser/WebSourceMapFetcher.ts` re-derived import-equals targets and accepted any external module reference, so it never checked `importKind === "type"`. The rule already existed as `semanticImportEqualsSpecifier` in the JavaScript semantic projection, used by the static and semantic analyzers. The fetcher did not use it. The issue's fixture, run through the registered MCP tool and the built CLI against the repository's fake CDP browser. The original source has `import type X = require("m")`, `import Y = require("n")`, and whole-statement `import type` / `export type` controls: | adapter | main | this PR | |---|---|---| | MCP | `require:m`, `require:n`; 5,016 bytes; 31 ms | `require:n`; 4,911 bytes; 32–41 ms | | CLI | `require:m`, `require:n`; 5,016 bytes; 381 ms | `require:n`; 4,911 bytes; 405–434 ms | In both builds the map is `included`, the original source text is retained exactly, and the whole-statement type-only controls produce no edge. Timings are single runs; CLI time is process startup. ## Change and scope - `semanticImportEqualsSpecifier` moves to `src/domain/javascript/javascriptModuleDeclaration.ts`, next to the other TypeScript erasure predicates (`isTypeOnlyImportDeclaration` and the others). Static analysis, semantic analysis, semantic projection, and the source-map fetcher import it from there. Its behavior is unchanged. - The fetcher returns a `require` edge only for a value import-equals. Its separate external-module check is removed. - The reference-source importer is intentionally unchanged: its dependency graph records type imports as source dependencies, including `import type { T } from`. ## Contract and boundary impact - Semantic owner and earliest changed stage: the module-declaration erasure predicates own the import-equals rule; source-map dependency recovery consumes it. - Contribution scope fit and linked maintainer decision: a bug fix within existing static source-map analysis; not applicable. - CLI and MCP/tool-catalog contract: schemas unchanged. - Provider, bridge, target-format, or platform compatibility: provider-independent; no browser behavior changes. - Evidence, artifact, provenance, or reconstruction contract: no false runtime dependency candidate for an erased declaration. Original source bytes are retained. - Target selection, authority, upstream behavior, and cleanup details: not applicable. - Generated metadata, package, or installation impact: none. - [x] Read existing files or captured data. ## Evidence and regression coverage - `tests/boundary/browser/webSourceMapFetcher.test.ts` adds a "type-only import equals" case: `import type Types = require("./types.js")` together with `import lib = require("./lib.js")` yields only `./lib.js`. It fails with main's fetcher and passes with the fix. The existing cases for value import-equals, local aliases, and whole-statement type-only imports and exports still pass. - Real data: the three largest installed source maps with embedded TypeScript sources, run through `fetchWebSourceMaps` with an in-process fetch host (median of 3): | source map | status | sources | edges | edge digest (main = PR) | result bytes | main | this PR | |---|---|---|---|---|---|---|---| | `openpgp/dist/openpgp.min.js.map` | included | 124 | 431 | `57a8e7b0579df4a8` | 19,163,284 | 133 ms | 143–148 ms | | `@babel/parser/lib/index.js.map` | partial | 43 | 129 | `681f4cea034f0e46` | 20,209,227 | 152 ms | 154–162 ms | | `@babel/parser` (`@vue/compiler-core` copy) | partial | 42 | 127 | `9e254929abcaaf9f` | 21,667,679 | 162 ms | 164–169 ms | The results are byte-identical and the timing differences are within run-to-run noise. None of the 287 installed TypeScript source maps contains an import-equals declaration, so the changed branch is exercised only by the fixtures. - Remaining proof gaps: a real browser and real served bundles were not used. The MCP and CLI evidence above uses the repository's fake CDP browser at the production protocol boundary. ## Validation performed - `npx vitest run tests/boundary/browser/webSourceMapFetcher.test.ts` — 82 passed; with main's fetcher, the new case failed. - `npx vitest run src/domain/javascript tests/boundary/browser src/browser` — 158 files passed, 1 skipped; 2,802 tests passed, 6 skipped. - `npm run check:fast` — passed. - MCP and CLI runs on the issue fixture and the real-map runs above, on both builds. Both were temporary tests and are not committed. ## Compatibility, safety, and release - Breaking changes or migration steps: none. - Real Hopper/Ghidra, browser, or OS coverage: no real browser; macOS arm64, Node 26.5. - Package or release metadata impact: none. - Security, privacy, process, or containment review: static parsing only. ## Author readiness Human owner: <!-- @GitHub-handle --> - [ ] 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. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <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:53 +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#6104
No description provided.