picomatch icon indicating copy to clipboard operation
picomatch copied to clipboard

Behavior of parenthesis in match

Open Superskyyy opened this issue 3 years ago • 6 comments

Hi community,

I just encountered the following

pm.isMatch("CON.md", "!(**/*.md)",{dot:true}) ? "match" : "no match" - > returns match

pm.isMatch("CON.md", "!(*.md)",{dot:true}) ? "match" : "no match" - > returns no match

without negation pm.isMatch("CON.md", "**/*.md",{dot:true}) ? "match" : "no match" - > returns match pm.isMatch("CON.md", "(**/*.md)",{dot:true}) ? "match" : "no match" - > returns no match

Why is the parenthesis matter? I appreciate some help.

Superskyyy avatar May 03 '22 21:05 Superskyyy

I realize this maybe similar to https://github.com/micromatch/picomatch/issues/104, can someone please confirm?

Superskyyy avatar May 03 '22 22:05 Superskyyy

This is correct. I believe parentheses are matched as literal characters when no preceded by an extglob charcter (!?@*+).

jonschlinkert avatar May 03 '22 22:05 jonschlinkert

This is correct. I believe parentheses are matched as literal characters when no preceded by an extglob charcter (!?@*+).

Thank you for the reply @jonschlinkert, but please take a look at the first one, even with negation, the CON.md is still matched, returning the same result when it is not with negation. Is there a correct way to do it?

I'm trying to use Picomatch to ignore files before processing other files in a repository (that is do not know what to include, we can only exclude known ones), but as you can see here in the screenshot, it is not recognizing the files at root level when I use **/*.md, is there any way that I can fix this? I've been scratching my head for hours...

image

I can confirm that problems only occur whenever a double asterisk appears at first position in an expression, so I can only avoid leading **, plus using * to help catch the missing files.

Superskyyy avatar May 03 '22 23:05 Superskyyy

It might be a bug that !(**/*.md) is matching CON.md. It looks like it ought to be considered a bug, unless I'm forgetting some rule in bash glob. (fwiw, negation extglobs are difficult to get right. But negation extglobs with nested globstars --double *-- are very difficult to get right (this is mainly due to the limitation of JavaScript's regex engine and the absence of useful features like atomic groups. Picomatch will eventually be updated to use lookbehinds, which will help with this, but the community and browsers are not quite ready for those yet. We can't rely on transpilers to properly re-create lookbehinds in a backward compatible way).

Any help from contributors would be appreciated, or I can look into this as soon as I get a chance.

Suggestions

In the meantime, a couple of suggestions for how you're doing matching:

If you're doing to use the same pattern multiple times, use the main function returned by picomatch to create a matcher function instead of calling pm.isMatch() each time.

const isMatch = pm('!(**/*.md...)', { dot: true });
// then
isMatch('abc.md');
isMatch('foo/abc.md');

Instead of using a negative extglob with multiple conditions (!(**/*.md|....)), either pass an array of globs or try using braces, or a combination:

['!**/*.md', '!**/*.txt', ...]
// or 
['!**/*.{md,txt}', ...]
// or
'!**/*.{md,txt,gitignore,licenserc.yaml,codestyle.xml}'

jonschlinkert avatar May 03 '22 23:05 jonschlinkert

also, thank you for creating the issue and for helping to figure this out!

jonschlinkert avatar May 03 '22 23:05 jonschlinkert

also, thank you for creating the issue and for helping to figure this out!

I should thank you, without Picomatch our open-source projects will be wasting a lot of CI time at non-functional file changes.

Superskyyy avatar May 03 '22 23:05 Superskyyy