Honor negation patterns under default predicate quantifier#310
Open
Iron-Ham wants to merge 1 commit intodorny:masterfrom
Open
Honor negation patterns under default predicate quantifier#310Iron-Ham wants to merge 1 commit intodorny:masterfrom
Iron-Ham wants to merge 1 commit intodorny:masterfrom
Conversation
A filter rule that mixed positive and bare negation patterns under the
default ('some') predicate quantifier matched nearly every file in a PR.
Each pattern was compiled into its own picomatch matcher and combined
via Array.prototype.some, so a standalone '!**/*.md' (true for any
non-markdown file) flipped the whole rule into a near-universal match.
Group bare string patterns into a single matcher with gitignore-style
semantics: a file matches when it matches at least one positive pattern
and does not match any negation pattern. The 'every' quantifier path is
unchanged, since per-pattern matching under .every() already produces
correct subtractive semantics with negations. The '!(extglob)' single-
string form is preserved by detecting only '!' not followed by '('.
Apply the same gitignore-style grouping to status-tagged array patterns
so 'added: ["src/**", "!**/*.md"]' behaves correctly. Reject rules made
up entirely of negation patterns (no positive include) so the failure
is loud rather than a silent permanent no-match.
Closes dorny#260
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A filter rule like
matched nearly every file in a PR — including completely unrelated paths like
web/src/foo.tsx— under the defaultsomepredicate quantifier.Each YAML pattern was compiled into its own
picomatchmatcher and combined viaArray.prototype.some. A bare!**/*.mdmatcher returnstruefor any file that isn't a markdown file, so once it was OR'd with the positive patterns the whole rule collapsed into "match anything not in the negation set" — the inverse of what authors intended.This change groups bare string patterns into a single matcher with gitignore-style semantics under the default quantifier:
The
everyquantifier path is left untouched: per-pattern matching under.every()already produces correct subtractive semantics with negations and is the documented escape hatch in the README's "Detect changes in folder only for some file extensions" example.Behavior changes
['mobile/**', '!mobile/**/*.md']under default quantifiermobile/**excludingmobile/**/*.mdadded: ['src/**', '!src/**/*.md'](status-tagged array)#260bug shape under a status tagInvalid filter YAML format— users who relied on this should add an explicit**positive'!(**/*.tsx|**/*.less)'(single-string extglob)!is followed by(, so it is treated as a single picomatch pattern, not split)everyquantifier with'!**/*.md'etc.The third row is the only case where previously-broken-but-permissive behavior becomes a hard error. The previous behavior matched every non-negated file, which is almost never what the author wanted — failing loudly is better than silently flipping rule polarity.
What changed
src/filter.tsparseFilterItemYamlnow collects bare string patterns from a (possibly nested via YAML anchor) array and builds a single combined matcher viagroupedStringMatcher.compileStatusPatternroutes status-tagged string-array patterns through the same gitignore-style grouping soadded: ['src/**', '!**/*.md']behaves correctly.collectArrayItemsrecursively flattens nested arrays from YAML anchors and partitions leaves into raw string patterns vs. fully parsedFilterRuleItems.groupedStringMatcherdistinguishes leading-!gitignore-style negations from!(extglob)single-pattern strings (the latter are passed straight to picomatch).throwInvalidFormatError.__tests__/filter.test.tsadds five regression tests:added: ['src/**', '!**/*.md']).dist/index.jsregenerated to match.Closes #260