Skip to content

fix(lint): correct glob-to-regex translation for oxlint excludes#603

Open
John-David Dalton (jdalton) wants to merge 1 commit intomainfrom
fix/lint-runner-exclude-glob
Open

fix(lint): correct glob-to-regex translation for oxlint excludes#603
John-David Dalton (jdalton) wants to merge 1 commit intomainfrom
fix/lint-runner-exclude-glob

Conversation

@jdalton
Copy link
Copy Markdown
Contributor

Summary

isExcludedByOxlint in scripts/lint.mts had two defects that caused the lint runner to exit non-zero whenever the only changed files were inside an oxlint-excluded directory like .claude/. Symptom: pnpm run check (and the pre-commit hook) emits Linting failed / Expected at least one target file.

The bugs

  1. Replacement order corrupted the regex. The old code did **/ → .*, then * → [^/]*, then . → \.. The last step escaped the dots in the just-introduced .* and [^/]* patterns; and the * replacement also consumed the * in the .* produced by the **/ step. **/.claude ended up as \.[^/]*\.claude — wrong.
  2. Exact-match anchoring. Even after fixing (1), the regex used $ at the end so **/dist only matched the bare path dist, never files inside like dist/foo.js.

The fix

  • Escape regex metacharacters on the original pattern first.
  • Translate **/ and * in a single callback-based pass so later substitutions can't corrupt earlier ones.
  • Anchor with (?:/|$) so directory patterns also match descendants.

Test plan

  • pnpm run check passes on this branch
  • 21-case harness against all 13 patterns in .oxlintrc.json — directories (**/dist), descendants (dist/foo.js), nested patterns (**/test/fixtures), file globs (**/*.d.ts, **/*.tsbuildinfo), lookalike siblings that must NOT match (coverage-other vs **/coverage, distributed vs **/dist, .cachewhatever vs **/.cache), and deep paths (a/b/tsconfig.tsbuildinfo)
  • Confirm pnpm run check on a future PR that only touches .claude/ files no longer reports spurious lint failure

`isExcludedByOxlint` had two defects that caused the pre-commit lint
runner to exit non-zero whenever the only changed files were inside
oxlint-excluded directories like `.claude/`:

1. `.replace(/\./g, '\\.')` ran *after* the glob substitutions, so it
   escaped the dots in the just-introduced `.*` and `[^/]*` patterns,
   corrupting them. The first `*` replacement also consumed the `*`
   inside the `.*` produced by the `**/` replacement.
2. The resulting regex used `$` anchoring, so a pattern like `**/dist`
   only matched the bare path `dist`, never files *inside* it like
   `dist/foo.js`.

Fix: escape regex metacharacters on the original pattern first, then
translate `**/` and `*` in a single callback-based pass so later
substitutions can't corrupt earlier ones. Anchor with `(?:/|$)` so
directory patterns also match descendants.

Verified against all 13 patterns in `.oxlintrc.json` with a 21-case
harness covering directories, descendants, file globs, lookalike
siblings (e.g. `coverage-other` must not match `**/coverage`), and
nested path prefixes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants