Skip to content

fix: translate POSIX bracket negation by default - #196

Merged
mrmlnc merged 2 commits into
micromatch:masterfrom
rajanpanth:fix/bracket-negation-default
Aug 24, 2026
Merged

fix: translate POSIX bracket negation by default#196
mrmlnc merged 2 commits into
micromatch:masterfrom
rajanpanth:fix/bracket-negation-default

Conversation

@rajanpanth

Copy link
Copy Markdown
Contributor

Fixes #187.

[!abc] compiled to a character class containing a literal !, so it matched exactly the characters it is supposed to exclude and rejected everything else:

pm.isMatch('a', '[!abc]')  // true, should be false
pm.isMatch('d', '[!abc]')  // false, should be true
pm.makeRe('[!abc]').source // ^(?:(?:\[!abc\]|[!abc])\/?)$

bash and minimatch both treat [!...] as [^...]. The translation already existed in the tokenizer but was gated behind opts.posix === true, which controls [[:alpha:]] class support; basic bracket negation is POSIX sh glob, not a posix-class feature. This removes the gate, so [!abc] now produces byte-for-byte the same regex as [^abc] and as [!abc] under posix: true.

Behavior notes, all locked by tests:

  • [!...] inherits the [^...] slash rule (a negated class never matches /).
  • ! not in first position stays literal: [a!] matches a and !.
  • Escaped \! in first position stays literal: [\!a] matches ! and a.
  • [!] now behaves identically to [^] (both escape the lone ]).

Compatibility: this changes match results for any pattern relying on the inverted behavior. No test in the suite asserted the old behavior (1982 passing after the change, 8 in the new negation block), and the old output contradicts every reference implementation, but flagging it clearly in case you want it to ride a major.

[!abc] compiled to a class containing a literal bang, so it matched
exactly the characters it should exclude and rejected everything else.
bash and minimatch both treat [!...] as [^...]. The translation existed
but was gated behind opts.posix, which controls [[:alpha:]] classes,
not basic negation.

Fixes micromatch#187
Keep incomplete `[!]` expressions and `literalBrackets` behavior
unchanged while translating valid leading `!` expressions.

Add behavior-focused coverage for ranges, embedded patterns,
`posix: false`, disabled brackets, and literal bangs.
@mrmlnc
mrmlnc force-pushed the fix/bracket-negation-default branch from 1d96dab to 73de57b Compare August 24, 2026 22:34
@mrmlnc

mrmlnc commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

This is the correct change: both Bash and Minimatch treat a leading ! in a bracket expression as negation, so [!abc] is equivalent to [^abc]. There is a nuance with [!], but that behavior predates this PR and should be discussed separately.

@mrmlnc
mrmlnc merged commit ef533d0 into micromatch:master Aug 24, 2026
22 checks passed
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.

[!abc] matches a, b and c: POSIX-style bracket negation is inverted unless options.posix is set

2 participants