Skip to content

fix: negated patterns with slashes incorrectly use basename-only matching when matchBase is true - #190

Open
deepakganesh78 wants to merge 1 commit into
micromatch:masterfrom
deepakganesh78:fix/issue136-negation-matchbase
Open

fix: negated patterns with slashes incorrectly use basename-only matching when matchBase is true#190
deepakganesh78 wants to merge 1 commit into
micromatch:masterfrom
deepakganesh78:fix/issue136-negation-matchbase

Conversation

@deepakganesh78

Copy link
Copy Markdown

Fixes #136

Problem

When matchBase: true is set, picomatch.test() unconditionally tests the compiled regex against the basename of the input path. For negated patterns containing path separators (e.g. !**/examples/**), this produces incorrect results because the negative lookahead regex cannot detect directory structure from the basename alone.

Reproduction:

const pm = require('picomatch');
const opts = { matchBase: true, dot: true };

pm.isMatch('packages/pkg-2/examples/.eslintrc.yaml', '!**/examples/**', opts);
// Actual: true (WRONG - path IS inside examples/)
// Expected: false

Root cause

In picomatch.test(), when matchBase is true, the code calls picomatch.matchBase() which tests the regex against utils.basename(input) only. For the negated regex ^(?!^(?:...examples...)$).*$ tested against basename .eslintrc.yaml, the positive pattern doesn't match the basename, so the negative lookahead passes and the result is incorrectly true.

Fix

For negated patterns whose glob (after stripping the ! prefix) contains a path separator (/ or \), the fix now tests both the full path (regex.exec(output)) and the basename (matchBase). If either method detects that the positive pattern matches, the overall result is non-matching (null). This ensures:

  • Directory-structure negation patterns like !**/examples/** correctly reject paths inside examples/
  • Basename-oriented negation patterns like !**/*.js continue to work (the basename test catches cases where the full-path regex misses due to ./ prefix handling)

Test results

  • Baseline (clean checkout): 1977 passing, 0 failing
  • After fix: 1978 passing, 0 failing (+1 new regression test)
  • No regressions introduced

Compatibility

This change only affects negated patterns that contain path separators when matchBase is enabled. Non-negated patterns and slash-free patterns are completely unaffected.

…me only when matchBase is true

When matchBase is true, picomatch tests the compiled regex against the
basename of the input path. For negated patterns containing path
separators (e.g. '!**/examples/**'), this causes incorrect results
because the negation regex's positive lookahead cannot detect directory
structure from the basename alone.

The fix tests both the full path and the basename for negated patterns
with slashes, returning a non-match if either method detects that the
positive pattern matches. This ensures directory-based negation patterns
work correctly while preserving basename-based negation for patterns
like '!**/*.js'.

Fixes micromatch#136

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

different results picomatch vs minimatch

1 participant