fix(resolution): honor jsconfig.json and compilerOptions.baseUrl (#2153) - #2176
Closed
Rishet11 wants to merge 2 commits into
Closed
fix(resolution): honor jsconfig.json and compilerOptions.baseUrl (#2153)#2176Rishet11 wants to merge 2 commits into
Rishet11 wants to merge 2 commits into
Conversation
…phify-Labs#2153) Non-relative imports produced no edge in a Rails/webpacker project, so every module under `baseUrl` was orphaned and `affected` answered nothing. Two defects. First, only `tsconfig.json` was probed, never `jsconfig.json` — the plain-JS spelling of the same file, which json_config.py already indexes, so the config's nodes appeared in the graph while resolution ignored it entirely. Second, `baseUrl` was consumed only as the base that `paths` targets resolve against, so a config declaring `baseUrl` and NO `paths` produced an empty alias map and every bare specifier died. `_find_js_config` now probes both names, tsconfig winning within a directory as tsc and editors do. `baseUrl` is exposed separately and used as a resolution root of LAST RESORT, tried only when no declared alias matches, so `paths` precedence (Graphify-Labs#1269, Graphify-Labs#927, Graphify-Labs#1531) is untouched. It is deliberately not modelled as a synthesized `*` alias: that would score (1, 0) in _match_tsconfig_alias and beat a declared non-wildcard directory-prefix alias at (2, -len), silently shadowing it. The fallback also returns a candidate only when it is a real file, so an external package import is not fabricated into a <baseUrl>/<pkg> edge. Threaded through the three regex-rescue dynamic-import paths (Svelte, Astro, TS/TSX) as well as static resolution, since the issue reports both.
…Labs#2153) Eleven cases: the webpacker repro (jsconfig + baseUrl, no paths) for static, dynamic and extensionless specifiers; the same for tsconfig; tsconfig winning over jsconfig in one directory; and four preservation guards that pass before and after — declared paths and directory-prefix aliases are not shadowed, relative imports are untouched, an absent baseUrl changes nothing, and an external package is not fabricated.
Collaborator
|
Thanks @Rishet11. Shipped in v0.9.27 (cherry-picked to v8 to keep your authorship). Closed-unmerged here, but it's in the release: https://github.com/Graphify-Labs/graphify/releases/tag/v0.9.27 |
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.
Closes #2153
Problem
Non-relative imports produced no edge in a Rails/webpacker project, so every module under
baseUrlwas orphaned andaffectedanswered nothing.There are two defects, and the first is not quite the one the issue describes.
baseUrlis read today, atresolution.py:146-147:but only as the base that
pathstargets resolve against._read_tsconfig_aliasesreturns onlypathsentries, so a config declaringbaseUrland nopaths— exactly the webpacker layout — yields an empty alias map and every bare specifier dies.The second is as reported:
_load_tsconfig_aliasesprobed onlytsconfig.json, neverjsconfig.json, even thoughjson_config.pyalready indexesjsconfig.json. That is why the config's own nodes appear in the graph while resolution ignores the file.Fix
_find_js_configwalks up probingtsconfig.jsonthenjsconfig.json, tsconfig winning within a directory — matching tsc and editors, which consultjsconfig.jsononly when there is notsconfig.json._load_tsconfig_base_urlexposes the resolved baseUrl directory, cached per config path._resolve_tsconfig_aliasgainsbase_url=None, used as a resolution root of last resort: only when no declared alias matches. Threaded through static resolution and the three regex-rescue dynamic-import paths (Svelte, Astro, TS/TSX), since the issue reports both.Two deliberate design choices worth flagging for review:
baseUrl is not modelled as a synthesized
"*"alias. That was the tempting one-line version, and it is wrong:"*"scores(1, 0)in_match_tsconfig_alias, while a declared non-wildcard directory-prefix alias scores(2, -len(prefix)). Since_resolve_tsconfig_aliaspicks the smallest tuple,(1, 0) < (2, -4)means an implicit"*"would silently shadow a declared alias like"@lib": ["src/lib"]and regress #1269. Keeping baseUrl out of the specificity contest entirely is what makes existing precedence provably untouched.test_declared_directory_prefix_alias_still_winspins this.The fallback returns a candidate only when it is a real file on disk. The declared-alias path deliberately returns a non-resolving first candidate to preserve phantom/external-edge behavior; doing that for baseUrl would turn
import React from 'react'into a fabricated<baseUrl>/reactedge.test_external_package_not_fabricated_under_baseurlpins this.Verification
End-to-end on the reported layout (
jsconfig.jsonwith"baseUrl": "app/javascript",packs/dashboard.jsimporting'mods/Widget.js').Before —
dashboard.jshas no outbound edges at all:After:
66d8110ruff checkpython -m tools.skillgen --checkThe 15 pre-existing failures are unrelated (
test_ollama.pybackend detection and similar), identical before and after, measured with-p no:randomlyin the same env.Four of the eleven tests pass both before and after by design — they are preservation guards: declared
pathsand directory-prefix aliases are not shadowed, relative imports are untouched, an absentbaseUrlchanges nothing, and an external package is not fabricated.Known gap
baseUrlinherited through anextendschain is not followed —_load_tsconfig_base_urlreads it only from the directly-found config, whereas alias loading does followextends. In that case the fallback simply does not apply, degrading to today's behavior (unresolved import) rather than producing a wrong edge. I left it out to keep this diff focused on the reported case, but it is an asymmetry and I'm happy to follow theextendschain forbaseUrlhere if you'd prefer it in one PR.