Skip to content

Commit fdfb155

Browse files
authored
Merge pull request #198 from micromatch/issue-142
fix: handle terminal globstars in parenthesized patterns
2 parents 38c6b7a + e279bd7 commit fdfb155

2 files changed

Lines changed: 21 additions & 1 deletion

File tree

lib/parse.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1175,6 +1175,15 @@ const parse = (input, options) => {
11751175
consume('/**', 3);
11761176
}
11771177

1178+
// A globstar followed only by balanced closing parens is at the logical end of patterns like
1179+
// `test(/utils/**)` and `test?(/utils/**)`. Treat it as EOS so the trailing `/**` can match its
1180+
// parent path, except in negated extglobs where that would change the exclusion semantics.
1181+
const isEnd = eos() || (
1182+
state.parens > 0
1183+
&& rest === ')'.repeat(state.parens)
1184+
&& !extglobs.some(extglob => extglob.type === 'negate')
1185+
);
1186+
11781187
if (prior.type === 'bos' && eos()) {
11791188
prev.type = 'globstar';
11801189
prev.value += value;
@@ -1185,7 +1194,7 @@ const parse = (input, options) => {
11851194
continue;
11861195
}
11871196

1188-
if (prior.type === 'slash' && prior.prev.type !== 'bos' && !afterStar && eos()) {
1197+
if (prior.type === 'slash' && prior.prev.type !== 'bos' && !afterStar && isEnd) {
11891198
state.output = state.output.slice(0, -(prior.output + prev.output).length);
11901199
prior.output = `(?:${prior.output}`;
11911200

test/issue-related.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,15 @@ describe('issue-related tests', () => {
6161
assert(isMatch('a/foo.js', '**/foo.js', { dot: true }));
6262
assert(isMatch('foo.js', '**/foo.js', { dot: true }));
6363
});
64+
65+
it('picomatch issue#142 - should match trailing globstars in parens', () => {
66+
assert(isMatch('test/utils', 'test(/utils/**)'));
67+
assert(isMatch('test/utils', 'test?(/utils/**)'));
68+
assert(isMatch('test/utils/file', 'test(/utils/**)'));
69+
assert(isMatch('test/utils/file', 'test?(/utils/**)'));
70+
assert(!isMatch('test', 'test(/utils/**)'));
71+
assert(isMatch('test', 'test?(/utils/**)'));
72+
assert(!isMatch('test/utils', 'test(/utils/**)', { strictSlashes: true }));
73+
assert(!isMatch('test/utils', 'test(/utils/**)/file'));
74+
});
6475
});

0 commit comments

Comments
 (0)