Repository navigation
fix(resolution): component and scoped-alias imports link the module file - #2528
Merged
Merged
Conversation
An import statement's own module reference linked nothing in two cases, even when its bindings resolved through the file: a Vue, Svelte or Astro component's import (`isJsPathImportRef` covered only the script languages), and a bare scoped package that a `tsconfig` path or a workspace package maps to a project file (`isJsPathSpecifier` excluded `@scope/pkg`). So a barrel or a side-effect module showed no dependency from those files, and sync's importer discovery, which follows the module edge into a changed file, never found them when a barrel they import through was deleted or added. Both now resolve through `resolveImportPath`, as a script's path import does; an outside scoped package still names no file. Component imports written with an extension, which a basename match linked before, now link through the resolver too. When a sync adds a file, it also retries the failed imports that now resolve to it but wait under no key its path gives: a scoped package parked under its last segment (`common` for `@excalidraw/common`, mapped to `packages/common/src/index.ts`, whose keys are `src` and `index`), under the module ceiling, and an import of the importer's own folder or the one above (`.`, `..`), parked under no tail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
An import statement's own module reference (the
importsref named by its specifier, which normally resolves to a file-to-fileimportsedge) linked nothing in two cases. The statement's bindings still resolved through that file:isJsPathImportRefonly covered the script languages (JS_MODULE_LANGUAGES: JS, JSX, TS, TSX, ArkTS), soimport { DropdownMenuGroup } from '../../ui'in a.vuefile failed (357 such failures in vben on main 041db10).tsconfigpath or a workspace package maps to a project file.isJsPathSpecifierexcluded@scope/pkg, soimport { debounce } from '@excalidraw/common'failed. Its bindingdebounceresolved through the very file the alias maps to (packages/common/src/index.ts); excalidraw has 381 such failures.Two things followed:
codegraph affectedand a module's dependents missed these importers wherever the module edge is the only link: a barrel, a side-effect module, or a module whose names are all re-exports.module-importers.ts, fix(sync): imports through a re-exporting module follow it when it is deleted or added #2512 and fix(ts): a re-export imports its module, and sync follows barrels of barrels #2526) follows the module edge into a changed file. So when a barrel these files import through was deleted or added, they kept stale or name-matched edges. This was all of excalidraw's residue in fix(ts): a re-export imports its module, and sync follows barrels of barrels #2526's A/B and vben's barrel residue.Fix
src/resolution/import-resolver.ts:isJsPathImportRefcoversESM_IMPORT_LANGUAGES, adding Vue, Svelte and Astro.isJsPathSpecifieraccepts a bare scoped name, which no binding can be named.resolveImportPath, as a script's path import already does since fix(js): a CommonJS require and a module path import the file they name #2263. An outside scoped package (@testing-library/react) still names no file.@/, Svelte's$lib) run first and are unchanged.Sync's failed-import retry (
src/index.ts,src/db/queries.ts,ReferenceResolver.resolveModuleFile). When a sync adds files, it also retries the failed imports that now resolve to one of them but wait under no key the file's path gives:commonfor@excalidraw/common) while the file's keys aresrcandindex. It is looked up by whole name when it resolves to an added file, under fix(sync): a Python import of a name a package re-exports links when the package appears later #2507's module ceiling, since that is no noise;.,..), parked under no tail. It is tried where it was written.Without these, the module edges a fresh index now has stayed failed after a barrel came back: excalidraw went from 44 differing lines to 6,078 in the first A/B round, before this part.
No schema change and no extraction change (so no kernel change). Fresh indexes change for projects with component imports or mapped scoped aliases; the CHANGELOG asks users to re-index.
Validation
Tests
__tests__/sfc-alias-module-imports.test.ts:../lib/utilas a module edge;tsconfig-mapped@acme/commonlinks its file, while@testing-library/reactlinks nothing.__tests__/sync-module-importers.test.ts, ES-module fixture:@app/widgetsnamed unlike its folder (as@excalidraw/commonis);.vuefile beside the barrel importing it as..Fresh-index A/B (main and this PR). Every change is one of two kinds; no edge is retargeted or lost:
import@0.9 instead offile-path@0.7./Nav.svelte), which a basename match linked before and the resolver links now.Sync A/B. Each arm's synced graph is compared with its own fresh index. Cells are differing lines, main → this PR. Barrels are every 2nd
index.{ts,tsx,js,jsx}; the rest are every 7th source file.Cost
Residues
components/button/holds bothbutton.tsandbutton.vue. Withbutton.tsheld out,'./button'resolves tobutton.vue; oncebutton.tsis back, a fresh index links it there, but sync keeps the edge, because only failed imports are retried. Script imports have had the same gap since fix(js): a CommonJS require and a module path import the file they name #2263; main hid it for components because their module refs never resolved at all."paths": { "common": [...] }) stay excluded. A bare name can't be told from an imported binding's name.package.jsonmainorexportsdon't resolve (TypeScript/pnpm: workspace member imports fail when the entry is declared via package.json "main"/"exports" (e.g. ./src/index.ts) — a same-name private function then hides real callers #2502). Their imports will link once that does.Overlap
resolveImportPathresolves. This PR then links those imports' module refs too.🤖 Generated with Claude Code