[GH-ISSUE #1881] [Bug] ESM package self-references are reported as external dependencies #635

Closed
opened 2026-10-15 18:26:49 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @xu91102 on GitHub (Oct 11, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/1881

Before submitting

  • Searched open and closed issues and recent pull requests for related reports.
  • This report uses only source-owned fixtures and contains no credentials or private target data.

Area

Evidence, artifacts, or reconstruction — JavaScript application analysis.

Observed behavior

analyze-javascript-application reports an ES module's package self-reference as external, even though the selected artifact contains the package metadata, exact exported file, and importing source. Node loads the same fixture successfully. This loses the local module/binding relationship in the application graph.

Reproduction

From a built source checkout, create a directory containing these three files:

fixture/package.json:

{"name":"rea-self-fixture","type":"module","exports":{".":"./entry.js","./feature":"./feature.js"}}

fixture/entry.js:

import { answer } from "rea-self-fixture/feature";
console.log(answer);

fixture/feature.js:

export const answer = 42;

Run:

node fixture/entry.js
# 42, exit 0
node scripts/rea.mjs analyze-javascript-application "$(pwd)/fixture" --json > observed.json
node --input-type=module -e '
import fs from "node:fs";
const graph = JSON.parse(fs.readFileSync("observed.json", "utf8")).normalized_result.graph;
console.log(graph.edges.filter(e => e.properties.module_link_kind === "import").map(e => e.properties));
'

REA exits 0 but the import has:

{"specifier":"rea-self-fixture/feature","resolved_path":null,"resolution_status":"external"}

Expected behavior

Resolve the self-reference through the nearest package's name and exports before searching node_modules, select the import condition, and retain feature.js as the internal target. Continue respecting nearest package-scope boundaries, exports encapsulation, and artifact-container identity.

Node's package documentation explicitly supports package self-reference through both import and require.

Impact and scope

Static application graphs can omit genuine internal dependencies and binding links in packages that use their own public exports internally. This does not require a native provider, browser, or execution of the analyzed artifact by REA.

Version and runtime

  • Source revision: fb94d9dde0ccda83ae520ac6fb22b1d283562cf3 (main).
  • Reproduced through the built CLI on Node 24.18.0, npm 11.16.0, macOS 27.0.1 arm64; also observed on Node 22.23.2.
  • Interface: CLI.
  • Earliest failure stage: static module target resolution.

Source-derived analysis

The existing self-reference resolver in JavaScriptArtifactPathResolution.ts runs only for moduleKind === "require"; ESM imports skip it and fall through to dependency lookup. The same exports selector and scope walk can be reused for the import loader.

Originally created by @xu91102 on GitHub (Oct 11, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/1881 ### Before submitting - [x] Searched open and closed issues and recent pull requests for related reports. - [x] This report uses only source-owned fixtures and contains no credentials or private target data. ### Area Evidence, artifacts, or reconstruction — JavaScript application analysis. ### Observed behavior `analyze-javascript-application` reports an ES module's package self-reference as external, even though the selected artifact contains the package metadata, exact exported file, and importing source. Node loads the same fixture successfully. This loses the local module/binding relationship in the application graph. ### Reproduction From a built source checkout, create a directory containing these three files: `fixture/package.json`: ```json {"name":"rea-self-fixture","type":"module","exports":{".":"./entry.js","./feature":"./feature.js"}} ``` `fixture/entry.js`: ```js import { answer } from "rea-self-fixture/feature"; console.log(answer); ``` `fixture/feature.js`: ```js export const answer = 42; ``` Run: ```sh node fixture/entry.js # 42, exit 0 node scripts/rea.mjs analyze-javascript-application "$(pwd)/fixture" --json > observed.json node --input-type=module -e ' import fs from "node:fs"; const graph = JSON.parse(fs.readFileSync("observed.json", "utf8")).normalized_result.graph; console.log(graph.edges.filter(e => e.properties.module_link_kind === "import").map(e => e.properties)); ' ``` REA exits 0 but the import has: ```json {"specifier":"rea-self-fixture/feature","resolved_path":null,"resolution_status":"external"} ``` ### Expected behavior Resolve the self-reference through the nearest package's `name` and `exports` before searching `node_modules`, select the `import` condition, and retain `feature.js` as the internal target. Continue respecting nearest package-scope boundaries, exports encapsulation, and artifact-container identity. [Node's package documentation](https://nodejs.org/docs/latest-v24.x/api/packages.html#self-referencing-a-package-using-its-name) explicitly supports package self-reference through both `import` and `require`. ### Impact and scope Static application graphs can omit genuine internal dependencies and binding links in packages that use their own public exports internally. This does not require a native provider, browser, or execution of the analyzed artifact by REA. ### Version and runtime - Source revision: `fb94d9dde0ccda83ae520ac6fb22b1d283562cf3` (`main`). - Reproduced through the built CLI on Node 24.18.0, npm 11.16.0, macOS 27.0.1 arm64; also observed on Node 22.23.2. - Interface: CLI. - Earliest failure stage: static module target resolution. ### Source-derived analysis The existing self-reference resolver in `JavaScriptArtifactPathResolution.ts` runs only for `moduleKind === "require"`; ESM imports skip it and fall through to dependency lookup. The same exports selector and scope walk can be reused for the import loader.
bsakaguchi 2026-10-15 18:26:49 +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#635
No description provided.