On vitejs/vite @ 8492422, indexed at b9ca4b7, 157 cross-file imports edge rows resolve onto a single non-exported local variable.
Every import { defineConfig } from 'vite' across the playground and create-vite templates lands on:
playground/ssr-html/test-stacktrace.js::vite
which is this, at module scope in a file that exports nothing at all:
import { createServer } from 'vite'
// ...
const vite = await createServer({ /* ... */ })
The correct target is the workspace member packages/vite ("name": "vite", exports["."] = "./dist/node/index.js"), which is in the graph.
Counts
|
rows |
edges targeting a node named vite |
317 |
— contains (a file holding its own vite node; not at issue) |
159 |
— imports, same-file |
1 |
— imports, cross-file |
157 |
| distinct targets among those 157 |
1 |
source files importing from 'vite' |
148 / 148 |
Why the existing guards do not catch it
matchByExactName filters candidates to non-import nodes that are lexically reachable, and commits when exactly one survives. Here one does — the module-level const — so the reference resolves with resolvedBy: 'exact-match' and confidence 0.9.
The bare-import guards do not apply, and correctly so. packages/vite/package.json declares the name vite and pnpm-workspace.yaml globs packages/*, so resolveWorkspaceImport('vite', …) reports the specifier project-local and isBoundToBareImport returns false. The specifier really is project-local; the failure is that the name then matches any node called vite rather than the member's entry.
Measured, on this corpus against the same merge base:
Two places a fix could go, and I do not have a view on which
- Export visibility. A module-level binding that the file does not export is not reachable by an import from another file.
isLexicallyReachable admits it today. This looks like the general defect — it is not specific to workspace packages, and any non-exported top-level name is a candidate for any same-named import anywhere.
- Workspace package resolution. When a specifier resolves to a workspace member, the target should be that member's entry point rather than a name lookup.
entryByName already exists for the ArkTS case.
(1) is the broader fix and would subsume this; (2) is narrower and would leave the same shape wherever a package is not a workspace member.
Reproduction
git clone https://github.com/vitejs/vite && cd vite && git checkout 8492422
codegraph init && codegraph index .
Then query the graph for imports edges whose target node is named vite and whose source file differs from the target's file.
Kernel rebuilt from source per arm; index db copied out before reading. Edge rows counted with multiplicity, keyed by source, target and kind — a distinct count reads lower because one source line can carry two genuine references at different columns.
On
vitejs/vite@8492422, indexed atb9ca4b7, 157 cross-fileimportsedge rows resolve onto a single non-exported local variable.Every
import { defineConfig } from 'vite'across the playground andcreate-vitetemplates lands on:which is this, at module scope in a file that exports nothing at all:
The correct target is the workspace member
packages/vite("name": "vite",exports["."] = "./dist/node/index.js"), which is in the graph.Counts
vitecontains(a file holding its ownvitenode; not at issue)imports, same-fileimports, cross-file'vite'Why the existing guards do not catch it
matchByExactNamefilters candidates to non-importnodes that are lexically reachable, and commits when exactly one survives. Here one does — the module-levelconst— so the reference resolves withresolvedBy: 'exact-match'and confidence 0.9.The bare-import guards do not apply, and correctly so.
packages/vite/package.jsondeclares the nameviteandpnpm-workspace.yamlglobspackages/*, soresolveWorkspaceImport('vite', …)reports the specifier project-local andisBoundToBareImportreturns false. The specifier really is project-local; the failure is that the name then matches any node calledviterather than the member's entry.Measured, on this corpus against the same merge base:
eb9fddf) and indexed: 2,487 edge rows removed, none of them these. Its guard is right and simply does not reach this case.vite, the single-survivor branch stops firing for those references, and they decline. 97 still resolve wrongly afterwards.Two places a fix could go, and I do not have a view on which
isLexicallyReachableadmits it today. This looks like the general defect — it is not specific to workspace packages, and any non-exported top-level name is a candidate for any same-named import anywhere.entryByNamealready exists for the ArkTS case.(1) is the broader fix and would subsume this; (2) is narrower and would leave the same shape wherever a package is not a workspace member.
Reproduction
Then query the graph for
importsedges whose target node is namedviteand whose source file differs from the target's file.Kernel rebuilt from source per arm; index db copied out before reading. Edge rows counted with multiplicity, keyed by source, target and kind — a distinct count reads lower because one source line can carry two genuine references at different columns.