Repository navigation
Description
Summary
A JS/TS import whose specifier ends in a slash, like import('@/widgets/Chart/'), or carries a . segment, like src/widgets/./Chart, loses the edges the plain spelling gets. The lazy-loaded component is no longer linked, and App gets a calls edge to its own Chart const instead. A named import from the same specifier still resolves.
Reproduction (verified)
On main at c71a3d0, built from source, Linux (WSL2), Node 22.22.2. The project has two files, plus a package.json with react:
// src/App.tsx (SPEC is one of the three spellings below)
import { lazy } from 'react';
import { Legend } from 'SPEC';
const Chart = lazy(() => import('SPEC'));
export function App() { Legend(); return <Chart />; }// src/widgets/Chart/index.tsx
export default function ChartView() { return null; }
export function Legend() { return 1; }Edges out of src/App.tsx after CodeGraph.init(dir, { index: true }), excluding contains:
| SPEC | lazy component | file import |
|---|---|---|
@/widgets/Chart |
App -calls-> src/widgets/Chart/index.tsx::ChartView |
App.tsx -imports-> src/widgets/Chart/index.tsx |
@/widgets/Chart/ |
App -calls-> src/App.tsx::Chart |
missing |
src/widgets/./Chart |
App -calls-> src/App.tsx::Chart |
missing |
App -calls-> src/widgets/Chart/index.tsx::Legend and App.tsx -imports-> …::Legend are present in all three rows.
Likely cause (inferred from reading the code)
fileExists falls back to fs.existsSync, which accepts src/widgets/Chart//index.tsx and src/widgets/./Chart/index.tsx. The import resolver's alias and bare-path branches (for example resolveAliasedImport) join the specifier as written and return that spelling. Lookups keyed by the indexed path, such as getNodesInFile or a files row, then miss. Normalizing the path once, at resolveImportPath's return or in fileExists, would fix every caller.
Such a path also reaches synthesis_inputs, whose file_path references files(path) (#2565). #2574 normalizes on that one write, but the resolver still returns the raw spelling.
Related
- fix(resolution): a workspace package import resolves to its package.json entry (#2502) #2535 resolves a workspace package to its
package.jsonentry instead of its directory. That is the other non-file path the resolver can return. It does not cover these spellings. codegraph syncfails with "FOREIGN KEY constraint failed" after d0bb9be5 when a file lazy-loads a workspace package #2565 / fix(sync): record only indexed files as synthesis inputs (#2565) #2574.- fix(paths): preserve literal backslashes on POSIX #2009 changes path handling in the same resolver files, but for literal backslashes on POSIX, not these spellings.
Not checked
Windows, macOS (case-insensitive paths), and tsconfig paths aliases. The @/ above goes through the fallback alias, with no tsconfig in the project. From reading the code, the relative and tsconfig-paths branches normalize, but I have not tested that.
Activity
fix(resolution): an import spelled with a trailing slash or a ./ segm…
Merge upstream/main into fork main (weekly sync 2026-10-21)
Merge colbymchenry#2610 (import spellings resolve to the indexed path, …
colbymchenry commentedon Oct 22, 2026
Thanks for the precise report and for tracing it to the resolver's path handling.
#2792 is merged to
main. An import spelled with a trailing slash, a./or../segment, or a doubled slash now links like the plain spelling:That holds for the
@/fallback, directsrc/…paths and workspace packages. A trailing slash still names a folder, so@/widgets/Chart/resolves toChart/index.tsx, as Node and tsc read it. The fix ships in the next release.fix(js,ts): an import spelled with a trailing slash or a ./ segment l…
fix(rust): workspace package entries, path dependencies and import sp…