wildcard-match
Advanced tools
Comparing version 4.1.1 to 5.0.0
@@ -1,8 +0,37 @@ | ||
interface Options { | ||
separator?: string; | ||
interface WildcardMatchOptions { | ||
separator?: string | boolean; | ||
} | ||
declare function wildcardMatch(pattern: string | string[], separator?: string | Options): RegExp & { | ||
pattern?: string | string[] | undefined; | ||
options: Options; | ||
}; | ||
interface isMatch { | ||
/** | ||
* Tests if a sample string matches the pattern(s) | ||
* | ||
* ```js | ||
* isMatch('foo') //=> true | ||
* ``` | ||
*/ | ||
(sample: string): boolean; | ||
/** The compiled regular expression */ | ||
regexp: RegExp; | ||
/** The original pattern or array of patterns that was used to compile the RegExp */ | ||
pattern: string | string[]; | ||
/** The options that were used to compile the RegExp */ | ||
options: WildcardMatchOptions; | ||
} | ||
declare function isMatch(regexp: RegExp, sample: string): boolean; | ||
/** | ||
* Compiles one or more glob patterns into a RegExp and returns an isMatch function. | ||
* The isMatch function takes a sample string as its only argument and returns true | ||
* if the string matches the pattern(s). | ||
* | ||
* ```js | ||
* wildcardMatch('src/*.js')('src/index.js') //=> true | ||
* ``` | ||
* | ||
* ```js | ||
* const isMatch = wildcardMatch('*.example.com', '.') | ||
* isMatch('foo.example.com') //=> true | ||
* isMatch('foo.bar.com') //=> false | ||
* ``` | ||
*/ | ||
declare function wildcardMatch(pattern: string | string[], options?: string | boolean | WildcardMatchOptions): isMatch; | ||
export = wildcardMatch; |
@@ -1,8 +0,37 @@ | ||
interface Options { | ||
separator?: string; | ||
interface WildcardMatchOptions { | ||
separator?: string | boolean; | ||
} | ||
declare function wildcardMatch(pattern: string | string[], separator?: string | Options): RegExp & { | ||
pattern?: string | string[] | undefined; | ||
options: Options; | ||
}; | ||
interface isMatch { | ||
/** | ||
* Tests if a sample string matches the pattern(s) | ||
* | ||
* ```js | ||
* isMatch('foo') //=> true | ||
* ``` | ||
*/ | ||
(sample: string): boolean; | ||
/** The compiled regular expression */ | ||
regexp: RegExp; | ||
/** The original pattern or array of patterns that was used to compile the RegExp */ | ||
pattern: string | string[]; | ||
/** The options that were used to compile the RegExp */ | ||
options: WildcardMatchOptions; | ||
} | ||
declare function isMatch(regexp: RegExp, sample: string): boolean; | ||
/** | ||
* Compiles one or more glob patterns into a RegExp and returns an isMatch function. | ||
* The isMatch function takes a sample string as its only argument and returns true | ||
* if the string matches the pattern(s). | ||
* | ||
* ```js | ||
* wildcardMatch('src/*.js')('src/index.js') //=> true | ||
* ``` | ||
* | ||
* ```js | ||
* const isMatch = wildcardMatch('*.example.com', '.') | ||
* isMatch('foo.example.com') //=> true | ||
* isMatch('foo.bar.com') //=> false | ||
* ``` | ||
*/ | ||
declare function wildcardMatch(pattern: string | string[], options?: string | boolean | WildcardMatchOptions): isMatch; | ||
export { wildcardMatch as default }; |
'use strict'; | ||
function escapeRegExpString(str) { return str.replace(/[-^$+.()|[\]{}]/g, '\\$&'); } | ||
function trimRight(str, substr) { if (str.substr(-substr.length) === substr) { | ||
return str.substr(0, str.length - substr.length); | ||
} return str; } | ||
function buildPatternWithSeparators(pattern, separator) { | ||
var segments = pattern.split(separator); | ||
return segments.reduce(function (result, segment, i) { | ||
if (segment === '**') { | ||
if (i === 0) { | ||
return "(.*" + separator + ")?"; | ||
function escapeRegExpChar(char) { if (char === '-' || | ||
char === '^' || | ||
char === '$' || | ||
char === '+' || | ||
char === '.' || | ||
char === '(' || | ||
char === ')' || | ||
char === '|' || | ||
char === '[' || | ||
char === ']' || | ||
char === '{' || | ||
char === '}' || | ||
char === '*' || | ||
char === '?' || | ||
char === '\\') { | ||
return "\\" + char; | ||
} | ||
else { | ||
return char; | ||
} } | ||
function escapeRegExpString(str) { | ||
var result = ''; | ||
for (var i = 0; i < str.length; i++) { | ||
result += escapeRegExpChar(str[i]); | ||
} | ||
return result; | ||
} | ||
function compile(pattern, options) { | ||
if (Array.isArray(pattern)) { | ||
var regExpPatterns = pattern.map(function (p) { return "^" + compile(p, options) + "$"; }); | ||
return "(?:" + regExpPatterns.join('|') + ")"; | ||
} | ||
var separator = typeof options.separator === 'undefined' ? true : options.separator; | ||
var separatorSplitter = ''; | ||
var separatorMatcher = ''; | ||
var wildcard = '.'; | ||
if (separator === true) { | ||
separatorSplitter = '/'; | ||
separatorMatcher = '[/\\\\]'; | ||
wildcard = '[^/\\\\]'; | ||
} | ||
else if (separator) { | ||
separatorSplitter = separator; | ||
separatorMatcher = escapeRegExpString(separatorSplitter); | ||
if (separatorMatcher.length > 1) { | ||
separatorMatcher = "(?:" + separatorMatcher + ")"; | ||
wildcard = "((?!" + separatorMatcher + ").)"; | ||
} | ||
else { | ||
wildcard = "[^" + separatorMatcher + "]"; | ||
} | ||
} | ||
else { | ||
wildcard = '.'; | ||
} | ||
var requiredSeparator = separator ? separatorMatcher + "+?" : ''; | ||
var optionalSeparator = separator ? separatorMatcher + "*?" : ''; | ||
var segments = separator ? pattern.split(separatorSplitter) : [pattern]; | ||
var result = ''; | ||
for (var s = 0; s < segments.length; s++) { | ||
var segment = segments[s]; | ||
var nextSegment = segments[s + 1]; | ||
var currentSeparator = ''; | ||
if (!segment && s > 0) { | ||
continue; | ||
} | ||
if (separator) { | ||
if (s === segments.length - 1) { | ||
currentSeparator = optionalSeparator; | ||
} | ||
else if (i === segments.length - 1) { | ||
return trimRight(result, separator) + "(" + separator + ".*)?"; | ||
else if (nextSegment !== '**') { | ||
currentSeparator = requiredSeparator; | ||
} | ||
return trimRight(result, separator) + "(" + separator + ".*)?" + separator; | ||
else { | ||
currentSeparator = ''; | ||
} | ||
} | ||
segment = segment | ||
.replace(/(?<!\\)\?/g, "(?!" + separator + ").") | ||
.replace(/(?<!\\)\*/g, "(((?!" + separator + ").)*|)"); | ||
if (i < segments.length - 1) { | ||
return "" + result + segment + separator; | ||
if (separator && segment === '**') { | ||
if (currentSeparator) { | ||
result += s === 0 ? '' : currentSeparator; | ||
result += "(?:" + wildcard + "*?" + currentSeparator + ")*?"; | ||
} | ||
continue; | ||
} | ||
return "" + result + segment; | ||
}, ''); | ||
for (var c = 0; c < segment.length; c++) { | ||
var char = segment[c]; | ||
if (char === '\\') { | ||
if (c < segment.length - 1) { | ||
result += escapeRegExpChar(segment[c + 1]); | ||
c++; | ||
} | ||
} | ||
else if (char === '?') { | ||
result += wildcard; | ||
} | ||
else if (char === '*') { | ||
result += wildcard + "*?"; | ||
} | ||
else { | ||
result += escapeRegExpChar(char); | ||
} | ||
} | ||
result += currentSeparator; | ||
} | ||
return result; | ||
} | ||
function buildRegExpPattern(pattern, separator) { | ||
if (Array.isArray(pattern)) { | ||
var regExpPatterns = pattern.map(function (p) { return "^" + buildRegExpPattern(p, separator) + "$"; }); | ||
return "(" + regExpPatterns.join('|') + ")"; | ||
function isMatch(regexp, sample) { if (typeof sample !== 'string') { | ||
throw new TypeError("Sample must be a string, but " + typeof sample + " given"); | ||
} return regexp.test(sample); } | ||
/** | ||
* Compiles one or more glob patterns into a RegExp and returns an isMatch function. | ||
* The isMatch function takes a sample string as its only argument and returns true | ||
* if the string matches the pattern(s). | ||
* | ||
* ```js | ||
* wildcardMatch('src/*.js')('src/index.js') //=> true | ||
* ``` | ||
* | ||
* ```js | ||
* const isMatch = wildcardMatch('*.example.com', '.') | ||
* isMatch('foo.example.com') //=> true | ||
* isMatch('foo.bar.com') //=> false | ||
* ``` | ||
*/ | ||
function wildcardMatch(pattern, options) { | ||
if (typeof pattern !== 'string' && !Array.isArray(pattern)) { | ||
throw new TypeError("The first argument must be a single pattern string or an array of patterns, but " + typeof pattern + " given"); | ||
} | ||
if (pattern === '**') { | ||
return '^.*$'; | ||
if (typeof options === 'string' || typeof options === 'boolean') { | ||
options = { separator: options }; | ||
} | ||
var regExpPattern; | ||
if (!separator) { | ||
regExpPattern = escapeRegExpString(pattern) | ||
.replace(/(?<!\\)\?/g, '.') | ||
.replace(/(?<!\\)\*/g, '.*'); | ||
if (arguments.length === 2 && | ||
!(typeof options === 'undefined' || | ||
(typeof options === 'object' && options !== null && !Array.isArray(options)))) { | ||
throw new TypeError("The second argument must be an options object or a string/boolean separator, but " + typeof options + " given"); | ||
} | ||
else if (pattern === '*') { | ||
regExpPattern = "((?!" + escapeRegExpString(separator) + ").)*"; | ||
options = options || {}; | ||
if (options.separator === '\\') { | ||
throw new Error('\\ is not a valid separator'); | ||
} | ||
else { | ||
regExpPattern = buildPatternWithSeparators(escapeRegExpString(pattern), escapeRegExpString(separator)); | ||
} | ||
return "^" + regExpPattern + "$"; | ||
var regexpPattern = compile(pattern, options); | ||
var regexp = new RegExp("^" + regexpPattern + "$"); | ||
var fn = isMatch.bind(null, regexp); | ||
fn.options = options; | ||
fn.pattern = pattern; | ||
fn.regexp = regexp; | ||
return fn; | ||
} | ||
function wildcardMatch(pattern, separator) { | ||
var options = typeof separator === 'object' ? separator : { separator: separator }; | ||
var regexpPattern = buildRegExpPattern(pattern, options.separator); | ||
var regExp = new RegExp(regexpPattern); | ||
regExp.pattern = pattern; | ||
regExp.options = options; | ||
return regExp; | ||
} | ||
module.exports = wildcardMatch; | ||
//# sourceMappingURL=index.js.map |
@@ -1,8 +0,37 @@ | ||
interface Options { | ||
separator?: string; | ||
interface WildcardMatchOptions { | ||
separator?: string | boolean; | ||
} | ||
declare function wildcardMatch(pattern: string | string[], separator?: string | Options): RegExp & { | ||
pattern?: string | string[] | undefined; | ||
options: Options; | ||
}; | ||
interface isMatch { | ||
/** | ||
* Tests if a sample string matches the pattern(s) | ||
* | ||
* ```js | ||
* isMatch('foo') //=> true | ||
* ``` | ||
*/ | ||
(sample: string): boolean; | ||
/** The compiled regular expression */ | ||
regexp: RegExp; | ||
/** The original pattern or array of patterns that was used to compile the RegExp */ | ||
pattern: string | string[]; | ||
/** The options that were used to compile the RegExp */ | ||
options: WildcardMatchOptions; | ||
} | ||
declare function isMatch(regexp: RegExp, sample: string): boolean; | ||
/** | ||
* Compiles one or more glob patterns into a RegExp and returns an isMatch function. | ||
* The isMatch function takes a sample string as its only argument and returns true | ||
* if the string matches the pattern(s). | ||
* | ||
* ```js | ||
* wildcardMatch('src/*.js')('src/index.js') //=> true | ||
* ``` | ||
* | ||
* ```js | ||
* const isMatch = wildcardMatch('*.example.com', '.') | ||
* isMatch('foo.example.com') //=> true | ||
* isMatch('foo.bar.com') //=> false | ||
* ``` | ||
*/ | ||
declare function wildcardMatch(pattern: string | string[], options?: string | boolean | WildcardMatchOptions): isMatch; | ||
export = wildcardMatch; |
@@ -1,2 +0,2 @@ | ||
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e="undefined"!=typeof globalThis?globalThis:e||self)["wildcard-match"]=n()}(this,(function(){"use strict";function e(e){return e.replace(/[-^$+.()|[\]{}]/g,"\\$&")}function n(e,n){return e.substr(-n.length)===n?e.substr(0,e.length-n.length):e}function t(r,o){return Array.isArray(r)?"("+r.map((function(e){return"^"+t(e,o)+"$"})).join("|")+")":"**"===r?"^.*$":"^"+(o?"*"===r?"((?!"+e(o)+").)*":function(e,t){var r=e.split(t);return r.reduce((function(e,o,u){return"**"===o?0===u?"(.*"+t+")?":u===r.length-1?n(e,t)+"("+t+".*)?":n(e,t)+"("+t+".*)?"+t:(o=o.replace(/(?<!\\)\?/g,"(?!"+t+").").replace(/(?<!\\)\*/g,"(((?!"+t+").)*|)"),u<r.length-1?""+e+o+t:""+e+o)}),"")}(e(r),e(o)):e(r).replace(/(?<!\\)\?/g,".").replace(/(?<!\\)\*/g,".*"))+"$"}return function(e,n){var r="object"==typeof n?n:{separator:n},o=t(e,r.separator),u=new RegExp(o);return u.pattern=e,u.options=r,u}})); | ||
!function(r,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(r="undefined"!=typeof globalThis?globalThis:r||self).wcmatch=e()}(this,(function(){"use strict";function r(r){return"-"===r||"^"===r||"$"===r||"+"===r||"."===r||"("===r||")"===r||"|"===r||"["===r||"]"===r||"{"===r||"}"===r||"*"===r||"?"===r||"\\"===r?"\\"+r:r}function e(t,n){if(Array.isArray(t))return"(?:"+t.map((function(r){return"^"+e(r,n)+"$"})).join("|")+")";var o=void 0===n.separator||n.separator,i="",a="",f=".";!0===o?(i="/",a="[/\\\\]",f="[^/\\\\]"):f=o?(a=function(e){for(var t="",n=0;n<e.length;n++)t+=r(e[n]);return t}(i=o)).length>1?"((?!"+(a="(?:"+a+")")+").)":"[^"+a+"]":".";for(var s=o?a+"+?":"",p=o?a+"*?":"",u=o?t.split(i):[t],l="",g=0;g<u.length;g++){var y=u[g],h=u[g+1],c="";if(y||!(g>0))if(o&&(c=g===u.length-1?p:"**"!==h?s:""),o&&"**"===y)c&&(l+=0===g?"":c,l+="(?:"+f+"*?"+c+")*?");else{for(var d=0;d<y.length;d++){var b=y[d];"\\"===b?d<y.length-1&&(l+=r(y[d+1]),d++):l+="?"===b?f:"*"===b?f+"*?":r(b)}l+=c}}return l}function t(r,e){if("string"!=typeof e)throw new TypeError("Sample must be a string, but "+typeof e+" given");return r.test(e)}return function(r,n){if("string"!=typeof r&&!Array.isArray(r))throw new TypeError("The first argument must be a single pattern string or an array of patterns, but "+typeof r+" given");if("string"!=typeof n&&"boolean"!=typeof n||(n={separator:n}),2===arguments.length&&void 0!==n&&("object"!=typeof n||null===n||Array.isArray(n)))throw new TypeError("The second argument must be an options object or a string/boolean separator, but "+typeof n+" given");if("\\"===(n=n||{}).separator)throw new Error("\\ is not a valid separator");var o=e(r,n),i=new RegExp("^"+o+"$"),a=t.bind(null,i);return a.options=n,a.pattern=r,a.regexp=i,a}})); | ||
//# sourceMappingURL=index.umd.js.map |
{ | ||
"name": "wildcard-match", | ||
"version": "4.1.1", | ||
"version": "5.0.0", | ||
"description": "Compile a glob-like pattern into a regular expression", | ||
@@ -29,4 +29,5 @@ "author": "Alex Schneider <me@schneider.ax>", | ||
"build": "rollup -c", | ||
"lint": "eslint {src,test}/*", | ||
"format": "eslint --cache --fix {src,test}/* && prettier --write **/*.md", | ||
"bench": "node bench/bench", | ||
"lint": "eslint {src,test,bench}/*", | ||
"format": "eslint --cache --fix {src,test,bench}/* && prettier --write **/*.md", | ||
"test": "ts-node -T -r \"core-js/modules/es.symbol.async-iterator\" -I \" \" node_modules/pta/src/cli.js --no-esm test/[!_]*.js" | ||
@@ -43,10 +44,11 @@ }, | ||
"@wessberg/rollup-plugin-ts": "^1.3.5", | ||
"benchmark": "^2.1.4", | ||
"core-js": "^3.6.5", | ||
"eslint": "^7.3.1", | ||
"eslint-config-prettier": "^6.11.0", | ||
"eslint-config-problems": "^4.0.0", | ||
"eslint-plugin-es5": "^1.5.0", | ||
"eslint-plugin-prefer-let": "^1.0.1", | ||
"eslint-plugin-prettier": "^3.1.4", | ||
"globrex": "^0.1.2", | ||
"husky": "^4.2.5", | ||
"matcher": "^3.0.0", | ||
"picomatch": "^2.2.2", | ||
"prettier": "^2.0.5", | ||
@@ -53,0 +55,0 @@ "pta": "^0.1.3", |
299
README.md
@@ -1,133 +0,284 @@ | ||
# wildcard-match | ||
<br> | ||
Compile a glob-like pattern into a regular expression. | ||
<h1 align="center">wildcard-match</h1> | ||
<p align="center"> | ||
<strong>A tiny but extremely fast JavaScript library for matching basic glob patterns</strong> | ||
</p> | ||
<p align="center"> | ||
<a href="https://www.npmjs.com/package/wildcard-match"><img src="https://img.shields.io/npm/v/wildcard-match" alt="npm package"></a> | ||
| ||
<a href="https://github.com/axtgr/wildcard-match/actions"><img src="https://img.shields.io/github/workflow/status/axtgr/wildcard-match/CI?label=CI&logo=github" alt="CI"></a> | ||
| ||
<a href="https://www.buymeacoffee.com/axtgr"><img src="https://img.shields.io/badge/%F0%9F%8D%BA-Buy%20me%20a%20beer-red?style=flat" alt="Buy me a beer"></a> | ||
</p> | ||
<br> | ||
Wildcard-match takes one or more basic glob patterns, compiles them into a RegExp and returns a function for matching strings with it. | ||
Glob patterns are strings that contain `?`, `*` and `**` wildcards. When such a pattern is compared with another string, these wildcards can replace one or more symbols. For example, `src/*` would match both `src/foo` and `src/bar`. | ||
This library's goal is to be as small and as fast as possible while supporting only the most basic wildcards. If you need character ranges, extended globs, braces and other advanced features, check out [outmatch](https://github.com/axtgr/outmatch). | ||
## Quickstart | ||
``` | ||
npm install wildcard-match | ||
``` | ||
```js | ||
import wcm from 'wildcard-match' | ||
import wcmatch from 'wildcard-match' | ||
const regExp = wcm('wildc?rd-mat*') | ||
regExp.test('wildcard-match') //=> true | ||
const isMatch = wcmatch('src/**/*.?s') | ||
isMatch('src/components/header/index.js') //=> true | ||
isMatch('src/README.md') //=> false | ||
isMatch.pattern //=> 'src/**/*.?s' | ||
isMatch.options //=> { separator: true } | ||
isMatch.regexp //=> /^src[/\\]+?(?:[^/\\]*?[/\\]+?)*?[^/\\]*?\.[^/\\]s[/\\]*?$/ | ||
``` | ||
- `?` matches a single arbitrary character | ||
- `*` matches zero or more arbitrary characters | ||
More details are available in the [Installation](#installation), [Usage](#usage) and [API](#api) sections. | ||
When a separator such as `/` is provided, the above wildcards will only match non-separator characters, and the following is activated: | ||
## Features | ||
- `**` matches any number of segments when used as a whole segment (i.e. `/**/` in the middle, `**/` at the beginning or `/**` at the end of a separated string) | ||
<table> | ||
<tr> | ||
<td align="center">🍃</td> | ||
<td><strong>Lightweight</strong><br>No dependencies. Just <strong>750</strong> bytes when minified and gzipped</td> | ||
</tr> | ||
<tr> | ||
<td align="center">🏎</td> | ||
<td><strong>Fast</strong><br>Compiles and matches patterns faster than any other known library</td> | ||
</tr> | ||
<tr> | ||
<td align="center">🌞</td> | ||
<td><strong>Simple</strong><br>The API is a single function. The number of available options is <strong>1</strong></td> | ||
</tr> | ||
<tr> | ||
<td align="center">⚒</td> | ||
<td><strong>Reliable</strong><br>Written in TypeScript. Covered by hundreds of unit tests</td> | ||
</tr> | ||
<tr> | ||
<td align="center">🔌</td> | ||
<td><strong>Compatible</strong><br>Works in any ES5 environment including older versions of Node.js, Deno, React Native and browsers</td> | ||
</tr> | ||
</table> | ||
```js | ||
wcm('src/**/*.?s', '/').test('src/lib/component/index.js') //=> true | ||
For comparison with the alternatives, see the [corresponding section](#comparison). | ||
## Installation | ||
The package is distributed via the npm package registry. It can be installed using one of the compatible package managers or included directly from a CDN. | ||
#### [npm](https://www.npmjs.com) | ||
``` | ||
npm install wildcard-match | ||
``` | ||
## Install | ||
#### [Yarn](https://yarnpkg.com) | ||
`npm install wildcard-match` | ||
``` | ||
yarn add wildcard-match | ||
``` | ||
#### [pnpm](https://pnpm.js.org) | ||
``` | ||
pnpm install wildcard-match | ||
``` | ||
#### CDN | ||
When included from a CDN, wildcard-match is available as the global function `wcmatch`. | ||
- [unpkg](https://unpkg.com/wildcard-match) | ||
- [jsDelivr](https://www.jsdelivr.com/package/npm/wildcard-match) | ||
## Usage | ||
### wildcardMatch(pattern, separator?): RegExp | ||
Wildcard-match comes built in ESM, CommonJS and UMD formats and includes TypeScript typings. The examples use ESM imports, which can be replaced with the following line for CommonJS: `const wcmatch = require('wildcard-match')`. | ||
The default export is a function that takes a string or an array of strings and an optional | ||
separator (or an options object with a _separator_ property). It compiles the pattern into | ||
a RegExp object that can be used to match strings with the pattern. | ||
The default export is a function of two arguments, first of which can be either a single glob string or an array of such patterns. The second argument is optional and can be either an [options](#options) object or a separator (which will be the value of the `separator` option). Wildcard-match compiles them into a regular expression and returns a function (usually called `isMatch` in the examples) that tests strings against the pattern. The pattern, options and the compiled RegExp object are available as properties on the returned function: | ||
```js | ||
import wcm from 'wildcard-match' | ||
import wcmatch from 'wildcard-match' | ||
const regExp = wcm('foo*/b?r', '/') | ||
const isMatch = wcmatch('src/?ar', '@') | ||
regExp.test('foo/bar') //=> true | ||
regExp.test('foobar') //=> false | ||
isMatch('src/bar') //=> true | ||
isMatch('src/car') //=> true | ||
isMatch('src/cvar') //=> false | ||
isMatch.pattern //=> 'src/?ar' | ||
isMatch.options //=> { separator: '@' } | ||
isMatch.regexp //=> /^src\/+?[^/]ar\/*?$/ | ||
``` | ||
The returned function can be invoked immediately if there is no need to match a pattern more than once: | ||
```js | ||
const regExp = wcm(['one.*', '*.two'], { separator: '.' }) | ||
regExp.test('one.two') //=> true | ||
regExp.test('one.three') //=> true | ||
regExp.test('three.two') //=> true | ||
regExp.test('one') //=> false | ||
regExp.test('two') //=> false | ||
regExp.test('one.two.three') //=> false | ||
regExp.test('three.false') //=> false | ||
wcmatch('src/**/*.js')('src/components/body/index.js') //=> true | ||
``` | ||
The returned RegExp has `pattern` and `options` properties set to the original values. | ||
Compiling a pattern is much slower than comparing a string to it, so it is recommended to always reuse the returned function when possible. | ||
### Syntax | ||
Wildcard-match supports the following glob syntax in patterns: | ||
- `?` matches exactly one arbitrary character excluding separators | ||
- `*` matches zero or more arbitrary characters excluding separators | ||
- `**` matches any number of segments when used as a whole segment in a separated pattern (e.g. <code>/\*\*/</code> if <code>/</code> is the separator) | ||
- `\` escapes the following character making it be treated literally | ||
More features are available in the [outmatch](https://github.com/axtgr/outmatch) library. | ||
### File Paths and Separators | ||
Globs are most often used to search file paths, which are, essentially, strings split into segments by slashes. While other libraries are usually restricted to this use-case, wildcard-match is able to work with _arbitrary_ strings by accepting a custom separator as the second parameter: | ||
```js | ||
const regExp = wcm('p?tt?rn', '/') | ||
const matchDomain = wcmatch('*.example.com', { separator: '.' }) | ||
matchDomain('subdomain.example.com') //=> true | ||
match.pattern //=> 'p?tt?rn' | ||
match.options //=> { separator: '/' } | ||
const matchLike = wcmatch('wh?t like**like mean', { separator: 'like' }) | ||
matchLike('what like do like you like mean') //=> true | ||
``` | ||
A pattern can have `?` and `*` escaped with a backslash so that they are treated as literal characters and not wildcards. | ||
The only limitation is that backslashes `\` cannot be used as separators in patterns because | ||
wildcard-match uses them for character escaping. However, when `separator` is `undefined` | ||
or `true`, `/` in patterns will match both `/` and `\`, so a single pattern with forward | ||
slashes can match both Unix and Windows paths: | ||
```js | ||
const regExp = wcm('foo\\*') | ||
const isMatchA = outmatch('foo\\bar') // throws an error | ||
regExp.test('foo') //=> false | ||
regExp.test('foobar') //=> false | ||
regExp.test('foo*') //=> true | ||
const isMatchB = outmatch('foo/bar') // same as passing `true` as the separator | ||
isMatchB('foo/bar') //=> true | ||
isMatchB('foo\\bar') //=> true | ||
const isMatchC = outmatch('foo/bar', '/') | ||
isMatchC('foo/bar') //=> true | ||
isMatchC('foo\\bar') //=> false | ||
``` | ||
When no separator is given, `**` acts as `*`. | ||
Matching features work with a _segment_ rather than a whole pattern: | ||
```js | ||
const regExp = wcm('foo/**bar') | ||
const isMatch = wcmatch('foo/b*') | ||
regExp.test('foo/bar') //=> true | ||
regExp.test('foo/bazbar') //=> true | ||
regExp.test('foo/baz/qux/bar') //=> true | ||
isMatch('foo/bar') //=> true | ||
isMatch('foo/b/ar') //=> false | ||
``` | ||
## Examples | ||
Segmentation can be turned off completely by passing `false` as the separator, which makes wildcard-match treat whole patterns as a single segment. Slashes become regular symbols and `*` matches _anything_: | ||
```js | ||
import wcm from 'wildcard-match' | ||
const isMatch = wcmatch('foo?ba*', false) | ||
isMatch('foo/bar/qux') //=> true | ||
``` | ||
// *? matches any non-empty substring | ||
const regExp = wcm('*?.js') | ||
A single separator in a pattern will match any number of separators in a sample string: | ||
regExp.test('index.js') //=> true | ||
regExp.test('src/index.js') //=> true | ||
regExp.test('.js') //=> false | ||
regExp.test('src') //=> false | ||
```js | ||
wcmatch('foo/bar/baz')('foo/bar///baz') //=> true | ||
``` | ||
When a pattern has an explicit separator at its end, samples also require one or more trailing separators: | ||
```js | ||
import wcm from 'wildcard-match' | ||
const isMatch = wcmatch('foo/bar/') | ||
const regExp = wcm('src/**/index.?s', '/') | ||
isMatch('foo/bar') //=> false | ||
isMatch('foo/bar/') //=> true | ||
isMatch('foo/bar///') //=> true | ||
``` | ||
regExp.test('src/index.js') //=> true | ||
regExp.test('src/lib/index.ts') //=> true | ||
regExp.test('src/lib/component/test/index.ts') //=> true | ||
regExp.test('src') //=> false | ||
regExp.test('index.js') //=> false | ||
regExp.test('src/index.js/lib') //=> false | ||
However, if there is no trailing separator in a pattern, strings will match even if they have separators at the end: | ||
```js | ||
const isMatch = wcmatch('foo/bar') | ||
isMatch('foo/bar') //=> true | ||
isMatch('foo/bar/') //=> true | ||
isMatch('foo/bar///') //=> true | ||
``` | ||
### Multiple Patterns | ||
Wildcard-match can take an array of glob patterns as the first argument instead of a single pattern. In that case a string will be considered a match if it matches _any_ of the given patterns: | ||
```js | ||
import wcm from 'wildcard-match' | ||
const isMatch = wcmatch(['src/*', 'tests/*']) | ||
const regExp = wcm('**.*.example.com', '.') | ||
isMatch('src/utils.js') //=> true | ||
isMatch('tests/utils.js') //=> true | ||
``` | ||
regExp.test('example.com') //=> false | ||
regExp.test('foo.example.com') //=> true | ||
regExp.test('foo.bar.example.com') //=> true | ||
regExp.test('foo.bar.baz.qux.example.com') //=> true | ||
regExp.test('foo.example.com.bar') //=> false | ||
### Matching Arrays of Strings | ||
The returned function can work with arrays of strings when used as the predicate of the native array methods: | ||
```js | ||
const isMatch = wcmatch('src/*.js') | ||
const paths = ['readme.md', 'src/index.js', 'src/components/body.js'] | ||
paths.map(isMatch) //=> [ false, true, false ] | ||
paths.filter(isMatch) //=> [ 'src/index.js' ] | ||
paths.some(isMatch) //=> true | ||
paths.every(isMatch) //=> false | ||
paths.find(isMatch) //=> 'src/index.js' | ||
paths.findIndex(isMatch) //=> 1 | ||
``` | ||
## Related | ||
## API | ||
- [globrex](https://github.com/terkelg/globrex) | ||
- [minimatch](https://github.com/isaacs/minimatch) | ||
- [micromatch](https://github.com/micromatch/micromatch) | ||
- [matcher](https://github.com/sindresorhus/matcher) | ||
### wcmatch(patterns, options?): isMatch<br>wcmatch(patterns, separator?): isMatch | ||
## License | ||
Takes a single pattern string or an array of patterns and compiles them into a regular expression. Returns an isMatch function that takes a sample string as its only argument and returns true if the string matches the pattern(s). | ||
[ISC](LICENSE) | ||
### isMatch(sample): boolean | ||
Tests if a sample string matches the patterns that were used to compile the regular expression and create this function. | ||
### isMatch.regexp | ||
The compiled regular expression. | ||
### isMatch.pattern | ||
The original pattern or array of patterns that was used to compile the regular expression and create the isMatch function. | ||
### isMatch.options | ||
The options object that was used to compile the regular expression and create the isMatch function. | ||
### Options | ||
| Option | Type | Default Value | Description | | ||
| ----------- | ----------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `separator` | boolean \| string | true | Defines the separator used to split patterns and samples into segments<ul><li>`true` — `/` in patterns match both `/` and `\` in samples<li>`false` — don't split<li>_any string_ — custom separator | | ||
## Comparison | ||
``` | ||
Pattern: src/test/**/*.?s | ||
Sample: src/test/foo/bar.js | ||
Compilation | ||
wildcard-match 1,046,326 ops/sec | ||
picomatch 261,589 ops/sec | ||
Matching | ||
wildcard-match 34,646,993 ops/sec | ||
picomatch 10,750,888 ops/sec | ||
``` | ||
A better comparison is in the works. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
55988
420
285
22
1