Repository navigation
TypeScript: expand ${configDir} and compute rootDir the way tsc does - #14
Merged
Merged
Conversation
What this change does to the map
Changed, nothing to do (5)
Next to the change FactsExtractor holds most of what changed, and a flow joins it to 9 of the 16 cards, so naming them would say nothing. The committed map at |
A shared base tsconfig cannot know where the project that extends it
lives, so TypeScript lets a path option start with ${configDir}, the
folder of the top-level tsconfig.json. The reader kept the text as
written, so @sindresorhus/tsconfig left ky's outDir pointing inside
node_modules at a folder that does not exist, and a compiled package
entry could only be mapped back to its source by guessing src/ or
source/.
The rule comes from tsc --showConfig (7.0.2), not from memory: the
variable counts only at the start of a value, in every file of the
extends chain, and always means the top-level folder. A value such as
cache/${configDir}/x is left literal, and a plain relative value still
means the folder of the file that declares it.
The test states its acceptance before the fix and fails on the previous
head. bench/typescript_adapter.py gives the same counts as the run
recorded on #12 for all seven repositories.
Fixes #13.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CzLdCRXKdAP2swLysEfacu
With rootDir unset, the reader guessed src/ or the repository root. On a TypeScript 5 project with include: ["source"] that maps a compiled entry to a file tsc never produced, and a wrong answer costs more than none. The rule was measured before it was written, by where tsc emits with rootDir unset on ten layouts. 5.9.3 takes the longest common folder of the non-declaration files that files, include and exclude select, test files included. 6.0.3 and 7.0.2 take the tsconfig folder, and 6 reports TS5011 asking for an explicit rootDir. composite means the tsconfig folder on every version. So root_candidates reads the project's TypeScript major, from node_modules/typescript first and the package.json range second, and applies that version's rule. With neither, both roots are tried and a compiled target maps only when exactly one fits; two matches leave it unmapped rather than pick one. input_files follows the tsconfig glob rules, and on ky, taxonomy, zod, nest and excalidraw it returns exactly the files tsc --listFilesOnly lists: 2331 files, none missing, none extra. Counts on all seven pinned repositories are unchanged; ky's seven package entries now map through outDir and rootDir alone, where before only the src/ and source/ fallback found them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CzLdCRXKdAP2swLysEfacu
0xfauzi
force-pushed
the
claude/new-contributor-triage-141j1e
branch
from
September 26, 2026 19:50
6665a6f to
91e63d5
Compare
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.
Fixes #13, and removes the guess at
rootDirthat #13's first commit left in place.Two commits. The first expands
${configDir}. The second replaces the guessed source root with the one the project's owntscwould use. Both rules were measured with the compiler before they were written, and each has a test whose docstring states the acceptance first.Commit 1: expand
${configDir}in inherited tsconfig paths${configDir}stands for the folder of the top-leveltsconfig.json, the one the project owns, so a shared base config can point at the project that extends it. Before, the text was kept as written, so@sindresorhus/tsconfigleft ky'soutDiratnode_modules/@sindresorhus/tsconfig/${configDir}/distribution, a folder that does not exist.The rule, from
tsc --showConfigon TypeScript 7.0.2 with the variable at three levels of anextendschain:tscresolved it to${configDir}/source(rootDir)./sourceunder the top-level folder${configDir}/typings(typeRoots)./typingsunder the top-level folder./local-typings(typeRoots)./config/nested/local-typings, the declaring folder${configDir}/src/*(paths)src/*lib/*(paths)lib/*, unchanged, relative tobaseUrlcache/${configDir}/x(tsBuildInfoFile)So: in every file of the chain, a
baseUrl,pathstarget,rootDiroroutDirvalue that starts with the variable becomes the top-level folder; anywhere else it stays literal; a plain relative value still means the declaring file's folder. The same holds forfiles,includeandexclude, which commit 2 reads.Commit 2: compute
rootDirthe way the project'stscdoesWith
rootDirunset, the reader used to guesssrc/or the repository root. That is a guess, and on a TypeScript 5 project withinclude: ["source"]it mapsout/source/cli.jsto a file thattscwould never have produced. The new test shows that case failing on the old code.What
tscdoes, measured by where it emits withrootDirunset, on ten layouts:source/source/rootDirsource/andscripts/include: ["source"]withscripts/presentsource/files: ["source/index.ts"]source/exclude: ["scripts"]source/.d.tsoutsidesource/source/(declarations do not count)test/composite: trueinclude: ["${configDir}/source"]in a base configsource/Blank cells were not run; the 6 and 7 columns did not vary with the input set in any run.
The rule the reader now follows, in
root_candidates:rootDiris the answer.compositemeans the tsconfig folder, on every version.files,includeandexcludeselect, test files included. 6 and later take the tsconfig folder.node_modules/typescript/package.json, then from thetypescriptrange inpackage.json(^5.9.3names 5). When neither exists, both roots are tried, and a compiled target maps to a module only when exactly one root names one. Two matches leave the target unmapped, because which roottscused is not knowable, and a wrong answer costs more than none.The input-file selection is checked against
tscfiles,includeandexcludefollow tsconfig glob rules:**/crosses folders,*and?stay inside one, a folder entry means everything under it, andoutDiris always left out. To make sure this matches the compiler rather than my reading of the docs, I rantsc --listFilesOnly(5.9.3) on five of the pinned repositories and compared the non-declaration source files it lists withinput_files:tscinput_filestscinput_fileshono and date-fns are solution-style configs (
files: []orinclude: []withreferences), so bothtscandinput_filessee no inputs there; systemap does not followreferences, and on those two the major (6 and 7) picks the tsconfig folder anyway.Effect on the pinned repositories
bench/typescript_adapter.pygives the same counts as the run recorded on #12 for all seven, every column. ky is the one whose path changed: itsinclude: ["source"]and TypeScript^5.9.3give rootsource/, and with thesrc//source/fallback disabled its seven package entries still map, throughoutDirandrootDiralone. Before this commit they only mapped through the fallback.The extra walk
input_filesmakes costs 0.05 s on zod and 0.21 s on nest, measured in the container.Verification
uv run pytest -q: 400 passed, including the two new tests.uv run pre-commit runwith each commit staged against its parent: every hook passes, including the complexity and file-length ratchets.uv run mypy src/systemap: clean.uv run systemap refresh,extract --check,check,judgement --strict,render --check: pass;docs/map/is updated.Branch
This branch sits on #12's current head
084122e, becausetypescript_config.pyonly exists there. Until #12 merges, this PR shows #12's six commits plus two. After #12 merges, I will rebase so only these two remain.🤖 Generated with Claude Code
https://claude.ai/code/session_01CzLdCRXKdAP2swLysEfacu