[PR #1939] [MERGED] fix(javascript): preserve package and source-map boundary identity #4923

Closed
opened 2026-10-31 00:56:48 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1939
Author: @morluto
Created: 10/11/2026
Status: ✅ Merged
Merged: 10/11/2026
Merged by: @morluto

Base: main ← Head: codex/fix-javascript-package-boundaries


📝 Commits (10+)

  • f1b0ee9 fix(javascript): preserve bare package specifier suffixes
  • e081424 fix(javascript): resolve ESM package self references
  • 6277401 fix(javascript): recover retained prefixed source maps
  • 3a77c43 test(javascript): cover suffixed ESM self references
  • 5caa68f fix(javascript): retain legacy ESM package suffix behavior
  • 0d548f3 fix(javascript): reject legacy ESM directory and extension fallback
  • 6d9efff refactor(javascript): consolidate package resolution and workflow coverage
  • 9db68c0 fix(javascript): report exact ESM package subpath misses
  • 95ec1e4 fix(javascript): compare parsed names for ESM self references
  • e688467 refactor(javascript): parse bare package requests once

📊 Changes

13 files changed (+860 additions, -157 deletions)

View changed files

📝 docs/javascript-artifact-reconstruction.md (+15 -2)
📝 src/application/javascript/JavaScriptArtifactAnalysis.ts (+5 -2)
📝 src/application/javascript/JavaScriptArtifactPathResolution.ts (+114 -94)
📝 src/browser/WebSourceMapFetcher.ts (+1 -1)
📝 src/domain/sourceMapEnvelope.ts (+13 -0)
📝 src/javascript/sourceMaps/SourceMapFormat.ts (+1 -14)
📝 tests/acceptance/applications/packageImportAliasesCli.test.ts (+2 -23)
➕ tests/acceptance/applications/packageRootSuffixCli.test.ts (+109 -0)
➕ tests/acceptance/applications/packageSelfNameBoundaryCli.test.ts (+207 -0)
➕ tests/acceptance/applications/packageSpecifierSuffixCli.test.ts (+278 -0)
📝 tests/acceptance/applications/packageSubpathsCli.test.ts (+2 -21)
➕ tests/acceptance/applications/sourceMapPrefixCli.test.ts (+79 -0)
➕ tests/support/cli/javascriptApplication.ts (+34 -0)

📄 Description

Summary

Fixes #1881, fixes #1882, fixes #1883.

Bare ESM specifiers preserve query/fragment identity through exports lookup, package self-references use the correct loader rules, and retained prefixed source maps recover original-source evidence while preserving their bytes and digests.

The branch integrates @xu91102's implementation commits from #1888, #1884 and #1887, retaining their original authorship. Those PRs are superseded by this integration.

Behavior and ownership

  • Classify bare specifiers before URL suffix stripping. Exact exports keys retain their complete source spelling. Legacy ESM subpaths without exports decode only the derived filesystem path and select exact files; directory and extension/main/index fallback are refused. Exact misses explain what lookup was attempted.
  • Parse each bare package request once into its name, dependency subpath and exports eligibility. Self-resolution and ancestor lookup share that representation, replacing the separate name and eligibility helpers. ESM compares the parsed name exactly with metadata and reuses its subpath; CommonJS retains Node's raw-request equality/prefix rule and metadata-relative self subpath. A metadata name such as @scope therefore cannot steal an ESM import of the installed @scope/pkg dependency. Loader conditions and exports encapsulation remain intact.
  • After self-resolution, derive ESM dependency lookup from a package metadata URL once. Root suffixes such as legacy?x cannot select a literal suffixed directory or silently fall back to legacy. Exact suffixed self names and CommonJS literal dependency names retain their distinct behavior.
  • Reuse the existing exports-target selector directly for package imports, removing its redundant status wrapper. Self-reference and suffix cases share a Node control and CLI/MCP matrix.
  • Share the source-map parsing view across application analysis, browser fetching and point tracing. Original retained bytes, digests and source locations remain the evidence authority.

Contract and boundary impact

Artifact path resolution owns module identity and lookup; the domain source-map envelope owns the parsing view. CLI/MCP input schemas and tool catalog are unchanged. Module edges preserve original specifiers, source digests, locations and explicit unknowns. Process authority, package installation and generated metadata are unchanged.

Validation

Executed on macOS with pinned Node 24.18.0:

  • Latest resolver, package-boundary and public CLI/stdio MCP checks: 262 tests passed across nine files. Real Node controls cover malformed self names, valid scoped names, exact suffixed self names, literal root-suffix directory traps, ESM versus CommonJS, exact suffix keys, legacy directory/extension refusal, package import aliases, conditional exports, target validation and package precedence. Each test was bounded to five seconds.
  • Both the self-name and root-suffix regressions failed against their previous compiled runtimes with false resolved edges, then passed after their fixes. They verify source identity and digest as well as selected paths. The literal root-suffix filesystem fixture is explicitly skipped on Windows because it requires question-mark directory names; the self-name cases remain cross-platform.
  • The broader package integration run passed 166 tests across six files; source-map integration checks covered retained-prefix parsing and original-source nodes.
  • Runtime build, the complete static CI command, docs checks and pre-push checks pass on the branch merged with current main. Shared public CLI/MCP invocation and result validation remove repeated package-test setup. Duplication is 2.59%, below the unchanged 2.6% threshold.

No breaking input change or migration. These workflows exercise REA CLI/MCP and real Node resolution; they do not establish browser, Electron, Windows or Bun runtime behavior. Heavy resource-exhaustion tests and real Hopper/Ghidra/IDA providers were not run for this change.


🔄 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/1939 **Author:** [@morluto](https://github.com/morluto) **Created:** 10/11/2026 **Status:** ✅ Merged **Merged:** 10/11/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `codex/fix-javascript-package-boundaries` --- ### 📝 Commits (10+) - [`f1b0ee9`](https://github.com/morluto/rea/commit/f1b0ee9689c6b675152ea5fc82ba77db6e30afcd) fix(javascript): preserve bare package specifier suffixes - [`e081424`](https://github.com/morluto/rea/commit/e081424b0109cd76fb2d2b283ee41a8e98f399f9) fix(javascript): resolve ESM package self references - [`6277401`](https://github.com/morluto/rea/commit/6277401e395ae3e2d0ebb1351d1f002801cbd69b) fix(javascript): recover retained prefixed source maps - [`3a77c43`](https://github.com/morluto/rea/commit/3a77c43b5af178b34d835161d3bf44654d201d79) test(javascript): cover suffixed ESM self references - [`5caa68f`](https://github.com/morluto/rea/commit/5caa68f56fdb407d3964d8c31eba2ad47f72d4b8) fix(javascript): retain legacy ESM package suffix behavior - [`0d548f3`](https://github.com/morluto/rea/commit/0d548f3c873bcf703a29aeceb62961765c55d789) fix(javascript): reject legacy ESM directory and extension fallback - [`6d9efff`](https://github.com/morluto/rea/commit/6d9efffbd789944e0213d6ca0b0ecd9aa74f25aa) refactor(javascript): consolidate package resolution and workflow coverage - [`9db68c0`](https://github.com/morluto/rea/commit/9db68c0d81f6f9a959ab4e409431d7f41bd80c98) fix(javascript): report exact ESM package subpath misses - [`95ec1e4`](https://github.com/morluto/rea/commit/95ec1e42205a4b22d5628766a9057167fea38165) fix(javascript): compare parsed names for ESM self references - [`e688467`](https://github.com/morluto/rea/commit/e68846751cd084b319891d6c5667f81bd4acf5c9) refactor(javascript): parse bare package requests once ### 📊 Changes **13 files changed** (+860 additions, -157 deletions) <details> <summary>View changed files</summary> 📝 `docs/javascript-artifact-reconstruction.md` (+15 -2) 📝 `src/application/javascript/JavaScriptArtifactAnalysis.ts` (+5 -2) 📝 `src/application/javascript/JavaScriptArtifactPathResolution.ts` (+114 -94) 📝 `src/browser/WebSourceMapFetcher.ts` (+1 -1) 📝 `src/domain/sourceMapEnvelope.ts` (+13 -0) 📝 `src/javascript/sourceMaps/SourceMapFormat.ts` (+1 -14) 📝 `tests/acceptance/applications/packageImportAliasesCli.test.ts` (+2 -23) ➕ `tests/acceptance/applications/packageRootSuffixCli.test.ts` (+109 -0) ➕ `tests/acceptance/applications/packageSelfNameBoundaryCli.test.ts` (+207 -0) ➕ `tests/acceptance/applications/packageSpecifierSuffixCli.test.ts` (+278 -0) 📝 `tests/acceptance/applications/packageSubpathsCli.test.ts` (+2 -21) ➕ `tests/acceptance/applications/sourceMapPrefixCli.test.ts` (+79 -0) ➕ `tests/support/cli/javascriptApplication.ts` (+34 -0) </details> ### 📄 Description ## Summary Fixes #1881, fixes #1882, fixes #1883. Bare ESM specifiers preserve query/fragment identity through exports lookup, package self-references use the correct loader rules, and retained prefixed source maps recover original-source evidence while preserving their bytes and digests. The branch integrates @xu91102's implementation commits from #1888, #1884 and #1887, retaining their original authorship. Those PRs are superseded by this integration. ## Behavior and ownership - Classify bare specifiers before URL suffix stripping. Exact exports keys retain their complete source spelling. Legacy ESM subpaths without exports decode only the derived filesystem path and select exact files; directory and extension/main/index fallback are refused. Exact misses explain what lookup was attempted. - Parse each bare package request once into its name, dependency subpath and exports eligibility. Self-resolution and ancestor lookup share that representation, replacing the separate name and eligibility helpers. ESM compares the parsed name exactly with metadata and reuses its subpath; CommonJS retains Node's raw-request equality/prefix rule and metadata-relative self subpath. A metadata name such as `@scope` therefore cannot steal an ESM import of the installed `@scope/pkg` dependency. Loader conditions and exports encapsulation remain intact. - After self-resolution, derive ESM dependency lookup from a package metadata URL once. Root suffixes such as `legacy?x` cannot select a literal suffixed directory or silently fall back to `legacy`. Exact suffixed self names and CommonJS literal dependency names retain their distinct behavior. - Reuse the existing exports-target selector directly for package imports, removing its redundant status wrapper. Self-reference and suffix cases share a Node control and CLI/MCP matrix. - Share the source-map parsing view across application analysis, browser fetching and point tracing. Original retained bytes, digests and source locations remain the evidence authority. ## Contract and boundary impact Artifact path resolution owns module identity and lookup; the domain source-map envelope owns the parsing view. CLI/MCP input schemas and tool catalog are unchanged. Module edges preserve original specifiers, source digests, locations and explicit unknowns. Process authority, package installation and generated metadata are unchanged. ## Validation Executed on macOS with pinned Node 24.18.0: - Latest resolver, package-boundary and public CLI/stdio MCP checks: **262 tests passed across nine files**. Real Node controls cover malformed self names, valid scoped names, exact suffixed self names, literal root-suffix directory traps, ESM versus CommonJS, exact suffix keys, legacy directory/extension refusal, package import aliases, conditional exports, target validation and package precedence. Each test was bounded to five seconds. - Both the self-name and root-suffix regressions failed against their previous compiled runtimes with false resolved edges, then passed after their fixes. They verify source identity and digest as well as selected paths. The literal root-suffix filesystem fixture is explicitly skipped on Windows because it requires question-mark directory names; the self-name cases remain cross-platform. - The broader package integration run passed 166 tests across six files; source-map integration checks covered retained-prefix parsing and original-source nodes. - Runtime build, the complete static CI command, docs checks and pre-push checks pass on the branch merged with current main. Shared public CLI/MCP invocation and result validation remove repeated package-test setup. Duplication is 2.59%, below the unchanged 2.6% threshold. No breaking input change or migration. These workflows exercise REA CLI/MCP and real Node resolution; they do not establish browser, Electron, Windows or Bun runtime behavior. Heavy resource-exhaustion tests and real Hopper/Ghidra/IDA providers were not run for this change. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 00:56:48 +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#4923
No description provided.