Skip to content

Commit

Permalink
fix(matchers): correctly handle multiple patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
mrmlnc committed Feb 8, 2020
1 parent 6474bf4 commit f043c84
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 48 deletions.
8 changes: 1 addition & 7 deletions src/providers/filters/deep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,7 @@ export default class DeepFilter {
}

private _isSkippedByPositivePatterns(entry: Entry, matcher: PartialMatcher): boolean {
const filepath = entry.path.replace(/^\.[/\\]/, '');

const parts = filepath.split('/');
const level = parts.length - 1;
const part = parts[level];

return !this._settings.baseNameMatch && !matcher.match(level, part);
return !this._settings.baseNameMatch && !matcher.match(entry.path);
}

private _isSkippedByNegativePatterns(entry: Entry, negativeRe: PatternRe[]): boolean {
Expand Down
41 changes: 21 additions & 20 deletions src/providers/matchers/partial.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,49 +7,50 @@ function getMatcher(patterns: Pattern[], options: MicromatchOptions = {}): Match
return new Matcher(patterns, options);
}

function assertMatch(patterns: Pattern[], level: number, part: string): void | never {
function assertMatch(patterns: Pattern[], filepath: string): void | never {
const matcher = getMatcher(patterns);

assert.ok(matcher.match(level, part));
assert.ok(matcher.match(filepath), `Path "${filepath}" should match: ${patterns}`);
}

function assertNotMatch(patterns: Pattern[], level: number, part: string): void | never {
function assertNotMatch(patterns: Pattern[], filepath: string): void | never {
const matcher = getMatcher(patterns);

assert.ok(!matcher.match(level, part));
assert.ok(!matcher.match(filepath), `Path "${filepath}" should do not match: ${patterns}`);
}

describe('Providers → Matchers → Partial', () => {
describe('.match', () => {
it('should handle patterns with globstar', () => {
assertMatch(['**'], 0, 'a');
assertMatch(['**'], 1, 'b');
assertMatch(['**/a'], 0, 'a');
assertMatch(['**/a'], 1, 'a');
assertNotMatch(['a/**'], 0, 'b');
assertMatch(['a/**'], 1, 'b');
assertMatch(['**'], 'a');
assertMatch(['**'], './a');
assertMatch(['**/a'], 'a');
assertMatch(['**/a'], 'b/a');
assertMatch(['a/**'], 'a/b');
assertNotMatch(['a/**'], 'b');
});

it('should do not match the latest segment', () => {
assertMatch(['b', 'b/*'], 0, 'b');
assertNotMatch(['*'], 0, 'a');
assertNotMatch(['a/*'], 1, 'b');
assertMatch(['b/*'], 'b');
assertNotMatch(['*'], 'a');
assertNotMatch(['a/*'], 'a/b');
});

it('should trying to match all patterns', () => {
assertMatch(['a/*', 'b/*'], 0, 'b');
assertMatch(['non-match', 'a/*/c'], 1, 'b');
assertMatch(['a/*', 'b/*'], 'b');
assertMatch(['non-match/b/c', 'a/*/c'], 'a/b');
assertNotMatch(['non-match/d/c', 'a/b/c'], 'a/d');
});

it('should match a static segment', () => {
assertMatch(['a/b'], 0, 'a');
assertNotMatch(['b/b'], 0, 'a');
assertMatch(['a/b'], 'a');
assertNotMatch(['b/b'], 'a');
});

it('should match a dynamic segment', () => {
assertMatch(['*/b'], 0, 'a');
assertMatch(['{a,b}/*'], 0, 'a');
assertNotMatch(['{a,b}/*'], 0, 'c');
assertMatch(['*/b'], 'a');
assertMatch(['{a,b}/*'], 'a');
assertNotMatch(['{a,b}/*'], 'c');
});
});
});
42 changes: 21 additions & 21 deletions src/providers/matchers/partial.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import Matcher from './matcher';

export default class PartialMatcher extends Matcher {
public match(level: number, part: string): boolean {
for (const info of this._storage) {
const section = info.sections[0];
public match(filepath: string): boolean {
const parts = filepath.split('/');
const levels = parts.length;

const patterns = this._storage.filter((info) => !info.complete || info.segments.length > levels);

for (const pattern of patterns) {
const section = pattern.sections[0];

/**
* In this case, the pattern has a globstar and we must read all directories unconditionally,
Expand All @@ -12,30 +17,25 @@ export default class PartialMatcher extends Matcher {
* fixtures/{a,b}/**
* ^ true/false ^ always true
*/
if (!info.complete && level >= section.length) {
if (!pattern.complete && levels > section.length) {
return true;
}

/**
* When size of the first group (minus the latest segment) greater or equals to `level`,
* we do not need reading the next directory, because in the next iteration,
* the path will have more levels than the pattern.
*
* But only if the pattern doesn't have a globstar (we must read all directories).
*
* In this cases we must trying to match other patterns.
*/
if (info.complete && level >= section.length - 1) {
continue;
}
const match = parts.every((part, index) => {
const segment = pattern.segments[index];

const segment = section[level];
if (segment.dynamic && segment.patternRe.test(part)) {
return true;
}

if (segment.dynamic && segment.patternRe.test(part)) {
return true;
}
if (!segment.dynamic && segment.pattern === part) {
return true;
}

return false;
});

if (!segment.dynamic && segment.pattern === part) {
if (match) {
return true;
}
}
Expand Down

0 comments on commit f043c84

Please sign in to comment.