Skip to content

JS: let .gitignore decide which directories are output - #8437

Merged
jkschneider merged 1 commit into
mainfrom
js-gitignore-authoritative-exclusions
Aug 11, 2026
Merged

JS: let .gitignore decide which directories are output#8437
jkschneider merged 1 commit into
mainfrom
js-gitignore-authoritative-exclusions

Conversation

@knutwannheden

@knutwannheden knutwannheden commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Motivation

ProjectParser has two discovery paths, and both end by filtering through the same glob list. On the git path that list is nearly redundant: candidates come from git ls-files plus git ls-files --others --exclude-standard, so .gitignore has already removed node_modules, dist, build, and coverage in 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 tracked dist/ 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, so src/dist/ was dropped along with it.

The file patterns are different in kind and do real work: *.min.js and *.bundle.js are frequently committed, and .gitignore will not identify them.

Summary

  • On the git discovery path the defaults narrow to 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_modules stays excluded unconditionally even when committed, matching the existing hardcoded guard on the walk path.
  • The walk path is unchanged and keeps the full DEFAULT_EXCLUSIONS, including when git discovery fails and falls back to it. Without git there is no .gitignore evaluation to lean on, so the globs remain the only defence.
  • Caller-supplied exclusions keep replacing the defaults and keep applying on both paths — an explicit list still wins over git tracking.
  • handle_parse_project forwarded request.exclusions ?? DEFAULT_EXCLUSIONS into 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

  • New test/rpc/project-parser-exclusions.test.ts builds a real git repo whose dist/ is staged source and whose build/ is gitignored output. Four cases: .gitignore decides 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.
  • Two of the four failed before the change, for the reasons they name.
  • npm test — 169 files passed, 1 skipped; 1931 tests passed, 24 skipped.
  • npm run typecheck clean.

Note for reviewers

  • This makes JavaScript and Python diverge slightly in mechanism, deliberately. Python's handle_parse_project has no git discovery — it is a raw os.walk — so Python: stop ParseProject pruning build/dist below the project root #8436 anchors build/dist to the project root instead. Root anchoring fixes the common src/build/ case without a git dependency; letting .gitignore decide is the better answer where the plumbing already exists, which on the Python side it does not.

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.
@github-project-automation github-project-automation Bot moved this from In Progress to Ready to Review in OpenRewrite Aug 11, 2026
@jkschneider
jkschneider merged commit b9d833e into main Aug 11, 2026
1 check passed
@jkschneider
jkschneider deleted the js-gitignore-authoritative-exclusions branch August 11, 2026 11:50
@github-project-automation github-project-automation Bot moved this from Ready to Review to Done in OpenRewrite Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants