JS: let .gitignore decide which directories are output - #8437
Merged
Conversation
Git discovery builds its candidate set from `git ls-files` plus `git ls-files --others --exclude-standard`, so .gitignore has already removed a project's build output before any pattern matching runs. Applying the default directory globs afterwards therefore changes the outcome only when they disagree with .gitignore -- that is, only for a directory the project deliberately tracks. A committed `dist/` of hand-written source was dropped, and `**/dist/**` matches at any depth, so `src/dist/` went with it. On the git path the defaults narrow to what .gitignore cannot express: dependency trees and minified bundles are sometimes committed but are never a project's own source. The walk path keeps the full default list, including when git discovery fails and falls back to it. Caller-supplied exclusions still replace the defaults and still apply on both paths. The ParseProject handler now forwards an absent `exclusions` as absent rather than resolving it to the defaults, so the parser can pick the set that matches how it discovers files.
jkschneider
approved these changes
Aug 11, 2026
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.
Motivation
ProjectParserhas two discovery paths, and both end by filtering through the same glob list. On the git path that list is nearly redundant: candidates come fromgit ls-filesplusgit ls-files --others --exclude-standard, so.gitignorehas already removednode_modules,dist,build, andcoveragein essentially every project before a single pattern is evaluated.Which means the default directory globs change the outcome only when they disagree with
.gitignore— that is, only when the directory is tracked. And a trackeddist/is a directory the project deliberately committed as source. So on the git path those patterns did nothing except in the one case where excluding was wrong.**/dist/**also matches at any depth, sosrc/dist/was dropped along with it.The file patterns are different in kind and do real work:
*.min.jsand*.bundle.jsare frequently committed, and.gitignorewill not identify them.Summary
DEFAULT_TRACKED_EXCLUSIONS— dependency trees and minified bundles, the things that are sometimes committed but are never a project's own source. Everything else is left to.gitignore.node_modulesstays excluded unconditionally even when committed, matching the existing hardcoded guard on the walk path.DEFAULT_EXCLUSIONS, including when git discovery fails and falls back to it. Without git there is no.gitignoreevaluation to lean on, so the globs remain the only defence.handle_parse_projectforwardedrequest.exclusions ?? DEFAULT_EXCLUSIONSinto the parser, so the parser could never tell "caller specified the defaults" from "caller specified nothing". It now forwards an absent value as absent.Test plan
test/rpc/project-parser-exclusions.test.tsbuilds a real git repo whosedist/is staged source and whosebuild/is gitignored output. Four cases:.gitignoredecides directories under git discovery; committed bundles and dependency trees stay excluded; caller exclusions override git tracking; the no-git walk still applies the full defaults.npm test— 169 files passed, 1 skipped; 1931 tests passed, 24 skipped.npm run typecheckclean.Note for reviewers
handle_parse_projecthas no git discovery — it is a rawos.walk— so Python: stop ParseProject pruning build/dist below the project root #8436 anchorsbuild/distto the project root instead. Root anchoring fixes the commonsrc/build/case without a git dependency; letting.gitignoredecide is the better answer where the plumbing already exists, which on the Python side it does not.