[GH-ISSUE #1811] [Bug] TypeScript NodeNext imports such as ./dep.js stay not-found in analyze-javascript-application #609

Closed
opened 2026-10-15 18:26:36 +00:00 by bsakaguchi · 1 comment
Owner

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

Before submitting

  • I searched open and closed issues and pull requests for related reports.
  • This reproduction contains no credentials or private target data.

Area

Evidence, artifacts, or reconstruction: JavaScript application analysis.

Observed behavior

In a TypeScript NodeNext source tree, relative imports name the emitted file: import { dep } from "./dep.js" with only dep.ts on disk. analyze-javascript-application reports each of these as not-found, so a TypeScript project gets almost no internal module edges. The same happens for ./x.mjs -> x.mts, ./x.cjs -> x.cts and ./B.js -> B.tsx. Extensionless ./util -> util.ts resolves.

import-reference-source already resolves these through the rule added in #755 (src/application/ReferenceSourceImportEntries.ts:102-117). The application resolver (resolveCandidate, src/application/javascript/JavaScriptArtifactPathResolution.ts:552-557) has no such step. #1087 made .mts/.cts part of application analysis, but their own ./x.mjs/./x.cjs imports cannot resolve.

Reproduction

mkdir -p ts-app/src/ui && cd ts-app
printf '%s\n' '{"name":"ts-app","version":"1.0.0","type":"module","main":"src/main.ts"}' > package.json
cat > src/main.ts <<'EOF'
import { dep } from "./dep.js";
import { Button } from "./ui/Button.js";
import { cfg } from "./cfg.mjs";
import { old } from "./legacy.cjs";
import { util } from "./util";
export const all = [dep, Button, cfg, old, util];
EOF
echo 'export const dep = 1;' > src/dep.ts
echo 'export const Button = () => <button>hi</button>;' > src/ui/Button.tsx
echo 'export const cfg = 2;' > src/cfg.mts
echo 'export const old = 3;' > src/legacy.cts
echo 'export const util = 4;' > src/util.ts
rea analyze-javascript-application "$PWD" --json > out.json

Then read the module_link_kind: "import" edges in normalized_result.graph.edges.

Expected behavior

The targets TypeScript resolves. TypeScript 7.0.2 with module/moduleResolution: nodenext (tsc --traceResolution) resolves ./dep.js to src/dep.ts, ./ui/Button.js to src/ui/Button.tsx, ./cfg.mjs to src/cfg.mts and ./legacy.cjs to src/legacy.cts.

Impact and scope

Any TypeScript ESM/NodeNext source tree analyzed as an application: internal import edges are missing, so feature traces and module pages stop at the first import. Compiled JavaScript output is not affected.

REA version

rea-agents 6.4.0 and main 0153b4d9

Runtime and platform

Node 24.18.0, Linux x64

Target and artifact context

Small local TypeScript directory (above); no third-party target.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

./dep.js        not-found  (expected src/dep.ts)
./ui/Button.js  not-found  (expected src/ui/Button.tsx)
./cfg.mjs       not-found  (expected src/cfg.mts)
./legacy.cjs    not-found  (expected src/legacy.cts)
./util          resolved   src/util.ts

Additional context

A fix that copies #755's suffix table into resolveCandidate (TypeScript importers only, module specifiers only, a present runtime file keeps precedence) resolves all four above. I did not open it as a PR because it changes behaviour an existing test pins: tests/boundary/cli/javascriptSelfImportRelationships.test.ts, "discloses CommonJS and TypeScript self-imports while retaining unresolved extension rewrites" (#1130). There, util.ts imports ./util.js; with the rule it resolves to util.ts itself and becomes a third omitted self-import instead of a not-found edge. #1130 notes that "the resolver currently does not perform this extension rewrite", and #1129 listed this case as one the reporter hit.

Is the rewrite wanted in the application resolver? If so, should a rewrite that lands on the importing file count as an omitted self-import (2 -> 3 in that test), or stay unresolved? I have the change and its tests ready either way.

Originally created by @jayhemnani9910 on GitHub (Oct 11, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/1811 ### Before submitting - [x] I searched open and closed issues and pull requests for related reports. - [x] This reproduction contains no credentials or private target data. ### Area Evidence, artifacts, or reconstruction: JavaScript application analysis. ### Observed behavior In a TypeScript NodeNext source tree, relative imports name the emitted file: `import { dep } from "./dep.js"` with only `dep.ts` on disk. `analyze-javascript-application` reports each of these as `not-found`, so a TypeScript project gets almost no internal module edges. The same happens for `./x.mjs` -> `x.mts`, `./x.cjs` -> `x.cts` and `./B.js` -> `B.tsx`. Extensionless `./util` -> `util.ts` resolves. `import-reference-source` already resolves these through the rule added in #755 (`src/application/ReferenceSourceImportEntries.ts:102-117`). The application resolver (`resolveCandidate`, `src/application/javascript/JavaScriptArtifactPathResolution.ts:552-557`) has no such step. #1087 made `.mts`/`.cts` part of application analysis, but their own `./x.mjs`/`./x.cjs` imports cannot resolve. ### Reproduction ```sh mkdir -p ts-app/src/ui && cd ts-app printf '%s\n' '{"name":"ts-app","version":"1.0.0","type":"module","main":"src/main.ts"}' > package.json cat > src/main.ts <<'EOF' import { dep } from "./dep.js"; import { Button } from "./ui/Button.js"; import { cfg } from "./cfg.mjs"; import { old } from "./legacy.cjs"; import { util } from "./util"; export const all = [dep, Button, cfg, old, util]; EOF echo 'export const dep = 1;' > src/dep.ts echo 'export const Button = () => <button>hi</button>;' > src/ui/Button.tsx echo 'export const cfg = 2;' > src/cfg.mts echo 'export const old = 3;' > src/legacy.cts echo 'export const util = 4;' > src/util.ts rea analyze-javascript-application "$PWD" --json > out.json ``` Then read the `module_link_kind: "import"` edges in `normalized_result.graph.edges`. ### Expected behavior The targets TypeScript resolves. TypeScript 7.0.2 with `module`/`moduleResolution: nodenext` (`tsc --traceResolution`) resolves `./dep.js` to `src/dep.ts`, `./ui/Button.js` to `src/ui/Button.tsx`, `./cfg.mjs` to `src/cfg.mts` and `./legacy.cjs` to `src/legacy.cts`. ### Impact and scope Any TypeScript ESM/NodeNext source tree analyzed as an application: internal import edges are missing, so feature traces and module pages stop at the first import. Compiled JavaScript output is not affected. ### REA version rea-agents 6.4.0 and main 0153b4d9 ### Runtime and platform Node 24.18.0, Linux x64 ### Target and artifact context Small local TypeScript directory (above); no third-party target. ### Interface CLI ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence ``` ./dep.js not-found (expected src/dep.ts) ./ui/Button.js not-found (expected src/ui/Button.tsx) ./cfg.mjs not-found (expected src/cfg.mts) ./legacy.cjs not-found (expected src/legacy.cts) ./util resolved src/util.ts ``` ### Additional context A fix that copies #755's suffix table into `resolveCandidate` (TypeScript importers only, module specifiers only, a present runtime file keeps precedence) resolves all four above. I did not open it as a PR because it changes behaviour an existing test pins: `tests/boundary/cli/javascriptSelfImportRelationships.test.ts`, "discloses CommonJS and TypeScript self-imports while retaining unresolved extension rewrites" (#1130). There, `util.ts` imports `./util.js`; with the rule it resolves to `util.ts` itself and becomes a third omitted self-import instead of a `not-found` edge. #1130 notes that "the resolver currently does not perform this extension rewrite", and #1129 listed this case as one the reporter hit. Is the rewrite wanted in the application resolver? If so, should a rewrite that lands on the importing file count as an omitted self-import (2 -> 3 in that test), or stay unresolved? I have the change and its tests ready either way.
bsakaguchi 2026-10-15 18:26:36 +00:00
Author
Owner

@morluto commented on GitHub (Oct 11, 2026):

Fixed on main in 1dfb933e4, with f8513a42d retaining runtime resource boundaries. Application and reference imports share emitted-source candidates. Public CLI coverage verifies distinct .js/.mjs/.cjs imports to TypeScript sources, runtime-file precedence, self-import disclosure, and unresolved Electron runtime paths when their emitted files are missing.

<!-- gh-comment-id:6111845648 --> @morluto commented on GitHub (Oct 11, 2026): Fixed on main in [1dfb933e4](https://github.com/morluto/rea/commit/1dfb933e47db0156cf1cb61f28715b81e740c57b), with [f8513a42d](https://github.com/morluto/rea/commit/f8513a42dc44451a621127f06edde5d38bc93f69) retaining runtime resource boundaries. Application and reference imports share emitted-source candidates. Public CLI coverage verifies distinct .js/.mjs/.cjs imports to TypeScript sources, runtime-file precedence, self-import disclosure, and unresolved Electron runtime paths when their emitted files are missing.
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#609
No description provided.