Skip to content

fix(oxlint): normalize explicit --config paths so overrides resolve from the config dir#21027

Open
niieani wants to merge 1 commit intooxc-project:mainfrom
niieani:fix/js-plugin-resolution-from-config-dir
Open

fix(oxlint): normalize explicit --config paths so overrides resolve from the config dir#21027
niieani wants to merge 1 commit intooxc-project:mainfrom
niieani:fix/js-plugin-resolution-from-config-dir

Conversation

@niieani
Copy link
Copy Markdown
Contributor

@niieani niieani commented Apr 3, 2026

Summary

This fixes a path-resolution bug in oxlint when an explicit config is passed from a nested working directory, for example:

cd files
oxlint -c ../oxlint.config.ts files

In that case, the explicit config path was made absolute but not lexically normalized, so it could still contain .. segments. That broke later override matching, because override globs are resolved relative to the config file’s parent directory. If the stored config path was something like /repo/foo/files/../oxlint.config.ts, then matching a lint target like /repo/foo/files/test.js against the config parent would fail lexically, and overrides such as files/**/*.js would not apply.

In practice, this caused rules configured through overrides to silently not fire, which can also surface as misleading unused eslint-disable diagnostics.

What This Changes

  • Normalize explicit --config paths lexically in ConfigLoader before loading them.
  • Preserve the existing behavior of resolving the config relative to cwd, but ensure the stored path no longer contains . or .. components.
  • Add a regression e2e fixture covering:
    • running oxlint from a nested cwd
    • passing -c ../oxlint.config.ts
    • relying on an override like files/**/*.js
  • Strengthen the existing unit test to assert that resolved config paths are normalized.

Why This Is Correct

The bug was not in override logic itself, but in the shape of the path data fed into it.

Override application later does path matching relative to config.path.parent(). That logic assumes the config path and lint target path are in the same normalized path form. If the config path retains .. segments while the lint target path does not, strip_prefix fails even though both paths refer to the same real location.

Lexically normalizing the explicit config path at load time fixes that mismatch at the source:

  • the config continues to resolve relative to the provided cwd
  • the config directory is stable and comparable
  • override glob matching now sees the expected relative path
  • no behavior changes for already-normalized paths

This is also the right scope for the fix: explicit config loading is where the inconsistent path form was introduced.

User-Facing Effect

This fixes cases where running oxlint from a subdirectory with an explicit config path causes override-based rules to stop applying. After this change, those overrides apply correctly, and downstream diagnostics such as unused eslint-disable are no longer produced spuriously because the intended rules now run.

Tests

  • Added an e2e regression fixture reproducing the nested-cwd + explicit-config override case.
  • Updated the config loader unit test to verify resolved config paths do not retain . / .. components.

AI Usage

Used codex to help with creating this PR.

@github-actions github-actions bot added A-linter Area - Linter A-cli Area - CLI A-linter-plugins Area - Linter JS plugins C-bug Category - Bug labels Apr 3, 2026
Copy link
Copy Markdown
Contributor

@camc314 camc314 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the use case for having your config outside of the directory your linting - surely you're going to end up with really wierd ignore patterns behaviour.

@camc314 camc314 self-assigned this Apr 5, 2026
@niieani
Copy link
Copy Markdown
Contributor Author

niieani commented Apr 5, 2026

What is the use case for having your config outside of the directory your linting

@camc314 Hi Cameron, thanks for taking a look. This is to enable partial linting from a subdirectory - a monorepo for example. You're inside of a single package, and only want to lint that package. Right now this is broken in oxlint, because the rules resolve correctly only when in the root directory of the repository. That's a pretty substantial assumption.

# from root repo:
oxlint -c oxlint.config.ts ./packages/one-package # this works

cd packages/one-package
oxlint -c ../../oxlint.config.ts . # this is broken

Both of these should be equivalent, but currently running the 2nd one applies relative paths from the current directory, rather than the directory of the config file.
This works as expected in other tools like eslint.
IMO ignore patterns should also work relative to the config file, not relative to the working directory, so that's not really a concern here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-cli Area - CLI A-linter Area - Linter A-linter-plugins Area - Linter JS plugins C-bug Category - Bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants