Possibly fixes#25259, and partial revert of #25133.
---
- `.gitignore` applies only to discovery (walking directory targets, cwd, globs)
- An explicitly named file target is linted / formatted even when gitignored
- = Restoring the pre-[#25133]() behavior for files, while fully keeping the [#25107]() fix for walk roots
| Target | Current | This PR |
| --- | --- | --- |
| Explicit file (`oxlint dist/a.js`) | skipped | linted |
| Explicit directory (`oxlint dist`) | skipped | skipped |
| cwd inside ignored tree | skipped | skipped |
The underlying principle:
> `.gitignore` is a message addressed to git, not to tools.
> Borrowing it to scope discovery is a useful heuristic, and a heuristic may narrow what the walk finds, but never refuse what the user names.
> Only tool's own ignore config can refuse. (which remain hard for the husky staged-file case).
This also re-aligns the CLI with stdin and LSP, which deliberately do not consult `.gitignore` (#19206).
👉🏻 This is the main motivation.
### Why not full revert
A directory target names where to search, not what to process.
The files under it are still discovered by the walk, so discovery rules apply.
Reverting that would bring back [#25107](), whose old behavior was not even a statable spec: whether running inside an ignored tree processed anything depended on the ignore pattern's form (bare `generated` did, `generated/**` didn't), an artifact of walker pruning, not a design.
### Regarding to `--no-ignore`
This flag remains orthogonal as a walk-level opt-out (`--no-ignore=vcs dist`) and for filling gap between existing tools.
However, with explicit files working again, I'm inclined to close those PRs and revisit if demand shows up.
For [#25259]()'s use case: name the files, e.g. `oxlint dist/foo.js` (or shell-expanded glob).
Fixes#25107.
The `ignore` crate walker enforces gitignore's "everything under an ignored directory is ignored" rule only by pruning ignored directories during traversal.
And it never filters its walk roots.
So when a walk target (based on cwd or an explicit CLI target path) is already inside a gitignored tree, pruning never happens and a bare directory pattern like `generated` matches nothing file-level. (even though `git check-ignore` says they are ignored)
See also BurntSushi/ripgrep#2595
### Changes
- oxc_config: added `GitignoreChecker`
- a pre-walk check that replays git's resolution order over the ancestor chain
- Matchers and `.git`/`.jj` probes are cached per directory
- oxlint / oxfmt: filter all CLI targets through this check before walking
### Behavior changes
- Explicitly passed gitignored files are now skipped (previously always linted/formatted)
- `oxlint --no-ignore` no longer force-lints gitignored targets
- The same behavior as `--no-ignore` does not disable during walk `.gitignore`
<details>
<summary>FYI: Current our ignore model overview</summary>
Two independent families, AND-ed (a path excluded by any layer is skipped):
| Layer | Source | oxlint | oxfmt |
| -------------------------------------------- | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| git-derived (always on, not user-disablable) | nested `.gitignore`, `.git/info/exclude` (during walk) | walker via shared `configure_walk_builder` | same (shared) |
| | walk roots / explicit CLI targets | `GitignoreChecker` (this PR) | `GitignoreChecker` (this PR) |
| tool-owned | ignore file | `.eslintignore` / `--ignore-path`; disabled by `--no-ignore` | `.prettierignore` / `--ignore-path`; no disable flag |
| | CLI patterns | `--ignore-pattern`; disabled by `--no-ignore` | `!pattern` path args |
| | config `ignorePatterns` | `LintIgnoreMatcher` (already containment-correct via `matched_path_or_any_parents`); always on | scope-local `is_path_ignored` (same); always on |
NOTE: `ignorePatterns` never had this bug, only the walker-backed gitignore layer did; this PR brings it to the same level.
A `!` negation in `ignorePatterns` cannot re-include gitignored paths (unchanged; the layers are independent).
</details>
Fixes#24612
- Update `fast-glob` to `1.1.0` which exposes `validate()` api
- Use it in `oxc_config`, apps will be validated through `deserialize`
- Oxfmt supports globs for CLI paths, also validated
## Summary
- auto-discover `oxfmt.config.mts` and `oxlint.config.mts`
- watch `.mts` configs in the language server and reject `.ts`/`.mts` conflicts
- add focused CLI and LSP coverage
Also removed unused functions from `oxc_config`.
As a bonus of sharing the code, the number of syscalls should decrease, resulting in a slight improvement in perf.
uses oxlint's `GlobSet` for overrides over `Vec<String>`.
This helpe move out some shared normalization code from oxlint and oxfmt to the shared config crate.
Hopefully this change is ok for you @leaysgur - I was originally hoping to share somethign else, but it seems trickier than I expected, so I just moved this out instead, which feels to me a good change