UEA-PRODEM
This commit is contained in:
+41
-63
@@ -107,7 +107,7 @@ console.log(isMatch('a/b.js')); //=> false
|
||||
|
||||
## API
|
||||
|
||||
### [picomatch](lib/picomatch.js#L31)
|
||||
### [picomatch](lib/picomatch.js#L32)
|
||||
|
||||
Creates a matcher function from one or more glob patterns. The returned function takes a string to match as its first argument, and returns true if the string is a match. The returned matcher function also takes a boolean as the second argument that, when true, returns an object with additional information.
|
||||
|
||||
@@ -128,24 +128,7 @@ console.log(isMatch('a.a')); //=> false
|
||||
console.log(isMatch('a.b')); //=> true
|
||||
```
|
||||
|
||||
**Example without node.js**
|
||||
|
||||
For environments without `node.js`, `picomatch/posix` provides you a dependency-free matcher, without automatic OS detection.
|
||||
|
||||
```js
|
||||
const picomatch = require('picomatch/posix');
|
||||
// the same API, defaulting to posix paths
|
||||
const isMatch = picomatch('a/*');
|
||||
console.log(isMatch('a\\b')); //=> false
|
||||
console.log(isMatch('a/b')); //=> true
|
||||
|
||||
// you can still configure the matcher function to accept windows paths
|
||||
const isMatch = picomatch('a/*', { options: windows });
|
||||
console.log(isMatch('a\\b')); //=> true
|
||||
console.log(isMatch('a/b')); //=> true
|
||||
```
|
||||
|
||||
### [.test](lib/picomatch.js#L116)
|
||||
### [.test](lib/picomatch.js#L117)
|
||||
|
||||
Test `input` with the given `regex`. This is used by the main `picomatch()` function to test the input string.
|
||||
|
||||
@@ -165,7 +148,7 @@ console.log(picomatch.test('foo/bar', /^(?:([^/]*?)\/([^/]*?))$/));
|
||||
// { isMatch: true, match: [ 'foo/', 'foo', 'bar' ], output: 'foo/bar' }
|
||||
```
|
||||
|
||||
### [.matchBase](lib/picomatch.js#L160)
|
||||
### [.matchBase](lib/picomatch.js#L161)
|
||||
|
||||
Match the basename of a filepath.
|
||||
|
||||
@@ -183,7 +166,7 @@ const picomatch = require('picomatch');
|
||||
console.log(picomatch.matchBase('foo/bar.js', '*.js'); // true
|
||||
```
|
||||
|
||||
### [.isMatch](lib/picomatch.js#L182)
|
||||
### [.isMatch](lib/picomatch.js#L183)
|
||||
|
||||
Returns true if **any** of the given glob `patterns` match the specified `string`.
|
||||
|
||||
@@ -204,7 +187,7 @@ console.log(picomatch.isMatch('a.a', ['b.*', '*.a'])); //=> true
|
||||
console.log(picomatch.isMatch('a.a', 'b.*')); //=> false
|
||||
```
|
||||
|
||||
### [.parse](lib/picomatch.js#L198)
|
||||
### [.parse](lib/picomatch.js#L199)
|
||||
|
||||
Parse a glob pattern to create the source string for a regular expression.
|
||||
|
||||
@@ -221,7 +204,7 @@ const picomatch = require('picomatch');
|
||||
const result = picomatch.parse(pattern[, options]);
|
||||
```
|
||||
|
||||
### [.scan](lib/picomatch.js#L230)
|
||||
### [.scan](lib/picomatch.js#L231)
|
||||
|
||||
Scan a glob pattern to separate the pattern into segments.
|
||||
|
||||
@@ -252,7 +235,7 @@ console.log(result);
|
||||
negated: true }
|
||||
```
|
||||
|
||||
### [.compileRe](lib/picomatch.js#L244)
|
||||
### [.compileRe](lib/picomatch.js#L245)
|
||||
|
||||
Compile a regular expression from the `state` object returned by the
|
||||
[parse()](#parse) method.
|
||||
@@ -265,7 +248,7 @@ Compile a regular expression from the `state` object returned by the
|
||||
* `returnState` **{Boolean}**: Adds the state to a `state` property on the returned regex. Useful for implementors and debugging.
|
||||
* `returns` **{RegExp}**
|
||||
|
||||
### [.makeRe](lib/picomatch.js#L285)
|
||||
### [.makeRe](lib/picomatch.js#L286)
|
||||
|
||||
Create a regular expression from a parsed glob pattern.
|
||||
|
||||
@@ -288,7 +271,7 @@ console.log(picomatch.compileRe(state));
|
||||
//=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
|
||||
```
|
||||
|
||||
### [.toRegex](lib/picomatch.js#L320)
|
||||
### [.toRegex](lib/picomatch.js#L321)
|
||||
|
||||
Create a regular expression from the given regex source string.
|
||||
|
||||
@@ -336,6 +319,7 @@ The following options may be used with the main `picomatch()` function or any of
|
||||
| `literalBrackets` | `boolean` | `undefined` | When `true`, brackets in the glob pattern will be escaped so that only literal brackets will be matched. |
|
||||
| `matchBase` | `boolean` | `false` | Alias for `basename` |
|
||||
| `maxLength` | `number` | `65536` | Limit the max length of the input string. An error is thrown if the input string is longer than this value. |
|
||||
| `maxExtglobRecursion` | `number\|boolean` | `0` | Limit nested quantified extglobs and other risky repeated extglob forms. When the limit is exceeded, the extglob is treated as a literal string instead of being compiled to regex. Set to `false` to disable this safeguard. |
|
||||
| `nobrace` | `boolean` | `false` | Disable brace matching, so that `{a,b}` and `{1..3}` would be treated as literal characters. |
|
||||
| `nobracket` | `boolean` | `undefined` | Disable matching with regex brackets. |
|
||||
| `nocase` | `boolean` | `false` | Make matching case-insensitive. Equivalent to the regex `i` flag. Note that this option is overridden by the `flags` option. |
|
||||
@@ -356,7 +340,8 @@ The following options may be used with the main `picomatch()` function or any of
|
||||
| `strictSlashes` | `boolean` | `undefined` | When true, picomatch won't match trailing slashes with single stars. |
|
||||
| `unescape` | `boolean` | `undefined` | Remove backslashes preceding escaped characters in the glob pattern. By default, backslashes are retained. |
|
||||
| `unixify` | `boolean` | `undefined` | Alias for `posixSlashes`, for backwards compatibility. |
|
||||
| `windows` | `boolean` | `false` | Also accept backslashes as the path separator. |
|
||||
|
||||
picomatch has automatic detection for regex positive and negative lookbehinds. If the pattern contains a negative lookbehind, you must be using Node.js >= 8.10 or else picomatch will throw an error.
|
||||
|
||||
### Scan Options
|
||||
|
||||
@@ -500,7 +485,7 @@ isMatch('baz');
|
||||
| **Character** | **Description** |
|
||||
| --- | --- |
|
||||
| `*` | Matches any character zero or more times, excluding path separators. Does _not match_ path separators or hidden files or directories ("dotfiles"), unless explicitly enabled by setting the `dot` option to `true`. |
|
||||
| `**` | Matches any character zero or more times, including path separators. Note that `**` will only match path separators (`/`, and `\\` with the `windows` option) when they are the only characters in a path segment. Thus, `foo**/bar` is equivalent to `foo*/bar`, and `foo/a**b/bar` is equivalent to `foo/a*b/bar`, and _more than two_ consecutive stars in a glob path segment are regarded as _a single star_. Thus, `foo/***/bar` is equivalent to `foo/*/bar`. |
|
||||
| `**` | Matches any character zero or more times, including path separators. Note that `**` will only match path separators (`/`, and `\\` on Windows) when they are the only characters in a path segment. Thus, `foo**/bar` is equivalent to `foo*/bar`, and `foo/a**b/bar` is equivalent to `foo/a*b/bar`, and _more than two_ consecutive stars in a glob path segment are regarded as _a single star_. Thus, `foo/***/bar` is equivalent to `foo/*/bar`. |
|
||||
| `?` | Matches any character excluding path separators one time. Does _not match_ path separators or leading dots. |
|
||||
| `[abc]` | Matches any characters inside the brackets. For example, `[abc]` would match the characters `a`, `b` or `c`, and nothing else. |
|
||||
|
||||
@@ -540,15 +525,22 @@ console.log(pm.isMatch('az', 'a*(z)')); // true
|
||||
console.log(pm.isMatch('azzz', 'a*(z)')); // true
|
||||
|
||||
// +(pattern) matches ONE or more of "pattern"
|
||||
console.log(pm.isMatch('a', 'a+(z)')); // false
|
||||
console.log(pm.isMatch('az', 'a+(z)')); // true
|
||||
console.log(pm.isMatch('azzz', 'a+(z)')); // true
|
||||
console.log(pm.isMatch('a', 'a*(z)')); // true
|
||||
console.log(pm.isMatch('az', 'a*(z)')); // true
|
||||
console.log(pm.isMatch('azzz', 'a*(z)')); // true
|
||||
|
||||
// supports multiple extglobs
|
||||
console.log(pm.isMatch('foo.bar', '!(foo).!(bar)')); // false
|
||||
|
||||
// supports nested extglobs
|
||||
console.log(pm.isMatch('foo.bar', '!(!(foo)).!(!(bar))')); // true
|
||||
|
||||
// risky quantified extglobs are treated literally by default
|
||||
console.log(pm.makeRe('+(a|aa)'));
|
||||
//=> /^(?:\+\(a\|aa\))$/
|
||||
|
||||
// increase the limit to allow a small amount of nested quantified extglobs
|
||||
console.log(pm.isMatch('aaa', '+(+(a))', { maxExtglobRecursion: 1 })); // true
|
||||
```
|
||||
|
||||
#### POSIX brackets
|
||||
@@ -629,44 +621,30 @@ The following table shows which features are supported by [minimatch](https://gi
|
||||
|
||||
Performance comparison of picomatch and minimatch.
|
||||
|
||||
_(Pay special attention to the last three benchmarks. Minimatch freezes on long ranges.)_
|
||||
|
||||
```
|
||||
# .makeRe star (*)
|
||||
picomatch x 4,449,159 ops/sec ±0.24% (97 runs sampled)
|
||||
minimatch x 632,772 ops/sec ±0.14% (98 runs sampled)
|
||||
# .makeRe star
|
||||
picomatch x 1,993,050 ops/sec ±0.51% (91 runs sampled)
|
||||
minimatch x 627,206 ops/sec ±1.96% (87 runs sampled))
|
||||
|
||||
# .makeRe star; dot=true (*)
|
||||
picomatch x 3,500,079 ops/sec ±0.26% (99 runs sampled)
|
||||
minimatch x 564,916 ops/sec ±0.23% (96 runs sampled)
|
||||
# .makeRe star; dot=true
|
||||
picomatch x 1,436,640 ops/sec ±0.62% (91 runs sampled)
|
||||
minimatch x 525,876 ops/sec ±0.60% (88 runs sampled)
|
||||
|
||||
# .makeRe globstar (**)
|
||||
picomatch x 3,261,000 ops/sec ±0.27% (98 runs sampled)
|
||||
minimatch x 1,664,766 ops/sec ±0.20% (100 runs sampled)
|
||||
# .makeRe globstar
|
||||
picomatch x 1,592,742 ops/sec ±0.42% (90 runs sampled)
|
||||
minimatch x 962,043 ops/sec ±1.76% (91 runs sampled)d)
|
||||
|
||||
# .makeRe globstars (**/**/**)
|
||||
picomatch x 3,284,469 ops/sec ±0.18% (97 runs sampled)
|
||||
minimatch x 1,435,880 ops/sec ±0.34% (95 runs sampled)
|
||||
# .makeRe globstars
|
||||
picomatch x 1,615,199 ops/sec ±0.35% (94 runs sampled)
|
||||
minimatch x 477,179 ops/sec ±1.33% (91 runs sampled)
|
||||
|
||||
# .makeRe with leading star (*.txt)
|
||||
picomatch x 3,100,197 ops/sec ±0.35% (99 runs sampled)
|
||||
minimatch x 428,347 ops/sec ±0.42% (94 runs sampled)
|
||||
# .makeRe with leading star
|
||||
picomatch x 1,220,856 ops/sec ±0.40% (92 runs sampled)
|
||||
minimatch x 453,564 ops/sec ±1.43% (94 runs sampled)
|
||||
|
||||
# .makeRe - basic braces ({a,b,c}*.txt)
|
||||
picomatch x 443,578 ops/sec ±1.33% (89 runs sampled)
|
||||
minimatch x 107,143 ops/sec ±0.35% (94 runs sampled)
|
||||
|
||||
# .makeRe - short ranges ({a..z}*.txt)
|
||||
picomatch x 415,484 ops/sec ±0.76% (96 runs sampled)
|
||||
minimatch x 14,299 ops/sec ±0.26% (96 runs sampled)
|
||||
|
||||
# .makeRe - medium ranges ({1..100000}*.txt)
|
||||
picomatch x 395,020 ops/sec ±0.87% (89 runs sampled)
|
||||
minimatch x 2 ops/sec ±4.59% (10 runs sampled)
|
||||
|
||||
# .makeRe - long ranges ({1..10000000}*.txt)
|
||||
picomatch x 400,036 ops/sec ±0.83% (90 runs sampled)
|
||||
minimatch (FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory)
|
||||
# .makeRe - basic braces
|
||||
picomatch x 392,067 ops/sec ±0.70% (90 runs sampled)
|
||||
minimatch x 99,532 ops/sec ±2.03% (87 runs sampled))
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
+1
-15
@@ -1,17 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
const pico = require('./lib/picomatch');
|
||||
const utils = require('./lib/utils');
|
||||
|
||||
function picomatch(glob, options, returnState = false) {
|
||||
// default to os.platform()
|
||||
if (options && (options.windows === null || options.windows === undefined)) {
|
||||
// don't mutate the original options object
|
||||
options = { ...options, windows: utils.isWindows() };
|
||||
}
|
||||
|
||||
return pico(glob, options, returnState);
|
||||
}
|
||||
|
||||
Object.assign(picomatch, pico);
|
||||
module.exports = picomatch;
|
||||
module.exports = require('./lib/picomatch');
|
||||
|
||||
+9
-5
@@ -1,8 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const WIN_SLASH = '\\\\/';
|
||||
const WIN_NO_SLASH = `[^${WIN_SLASH}]`;
|
||||
|
||||
const DEFAULT_MAX_EXTGLOB_RECURSION = 0;
|
||||
|
||||
/**
|
||||
* Posix glob regex
|
||||
*/
|
||||
@@ -22,7 +25,6 @@ const NO_DOT_SLASH = `(?!${DOT_LITERAL}{0,1}${END_ANCHOR})`;
|
||||
const NO_DOTS_SLASH = `(?!${DOTS_SLASH})`;
|
||||
const QMARK_NO_DOT = `[^.${SLASH_LITERAL}]`;
|
||||
const STAR = `${QMARK}*?`;
|
||||
const SEP = '/';
|
||||
|
||||
const POSIX_CHARS = {
|
||||
DOT_LITERAL,
|
||||
@@ -39,8 +41,7 @@ const POSIX_CHARS = {
|
||||
NO_DOTS_SLASH,
|
||||
QMARK_NO_DOT,
|
||||
STAR,
|
||||
START_ANCHOR,
|
||||
SEP
|
||||
START_ANCHOR
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -60,8 +61,7 @@ const WINDOWS_CHARS = {
|
||||
NO_DOTS_SLASH: `(?!${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`,
|
||||
QMARK_NO_DOT: `[^.${WIN_SLASH}]`,
|
||||
START_ANCHOR: `(?:^|[${WIN_SLASH}])`,
|
||||
END_ANCHOR: `(?:[${WIN_SLASH}]|$)`,
|
||||
SEP: '\\'
|
||||
END_ANCHOR: `(?:[${WIN_SLASH}]|$)`
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -69,6 +69,7 @@ const WINDOWS_CHARS = {
|
||||
*/
|
||||
|
||||
const POSIX_REGEX_SOURCE = {
|
||||
__proto__: null,
|
||||
alnum: 'a-zA-Z0-9',
|
||||
alpha: 'a-zA-Z',
|
||||
ascii: '\\x00-\\x7F',
|
||||
@@ -86,6 +87,7 @@ const POSIX_REGEX_SOURCE = {
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
DEFAULT_MAX_EXTGLOB_RECURSION,
|
||||
MAX_LENGTH: 1024 * 64,
|
||||
POSIX_REGEX_SOURCE,
|
||||
|
||||
@@ -156,6 +158,8 @@ module.exports = {
|
||||
CHAR_VERTICAL_LINE: 124, /* | */
|
||||
CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279, /* \uFEFF */
|
||||
|
||||
SEP: path.sep,
|
||||
|
||||
/**
|
||||
* Create EXTGLOB_CHARS
|
||||
*/
|
||||
|
||||
+310
-3
@@ -45,6 +45,277 @@ const syntaxError = (type, char) => {
|
||||
return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`;
|
||||
};
|
||||
|
||||
const splitTopLevel = input => {
|
||||
const parts = [];
|
||||
let bracket = 0;
|
||||
let paren = 0;
|
||||
let quote = 0;
|
||||
let value = '';
|
||||
let escaped = false;
|
||||
|
||||
for (const ch of input) {
|
||||
if (escaped === true) {
|
||||
value += ch;
|
||||
escaped = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch === '\\') {
|
||||
value += ch;
|
||||
escaped = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch === '"') {
|
||||
quote = quote === 1 ? 0 : 1;
|
||||
value += ch;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (quote === 0) {
|
||||
if (ch === '[') {
|
||||
bracket++;
|
||||
} else if (ch === ']' && bracket > 0) {
|
||||
bracket--;
|
||||
} else if (bracket === 0) {
|
||||
if (ch === '(') {
|
||||
paren++;
|
||||
} else if (ch === ')' && paren > 0) {
|
||||
paren--;
|
||||
} else if (ch === '|' && paren === 0) {
|
||||
parts.push(value);
|
||||
value = '';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
value += ch;
|
||||
}
|
||||
|
||||
parts.push(value);
|
||||
return parts;
|
||||
};
|
||||
|
||||
const isPlainBranch = branch => {
|
||||
let escaped = false;
|
||||
|
||||
for (const ch of branch) {
|
||||
if (escaped === true) {
|
||||
escaped = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch === '\\') {
|
||||
escaped = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (/[?*+@!()[\]{}]/.test(ch)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const normalizeSimpleBranch = branch => {
|
||||
let value = branch.trim();
|
||||
let changed = true;
|
||||
|
||||
while (changed === true) {
|
||||
changed = false;
|
||||
|
||||
if (/^@\([^\\()[\]{}|]+\)$/.test(value)) {
|
||||
value = value.slice(2, -1);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isPlainBranch(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return value.replace(/\\(.)/g, '$1');
|
||||
};
|
||||
|
||||
const hasRepeatedCharPrefixOverlap = branches => {
|
||||
const values = branches.map(normalizeSimpleBranch).filter(Boolean);
|
||||
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
for (let j = i + 1; j < values.length; j++) {
|
||||
const a = values[i];
|
||||
const b = values[j];
|
||||
const char = a[0];
|
||||
|
||||
if (!char || a !== char.repeat(a.length) || b !== char.repeat(b.length)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (a === b || a.startsWith(b) || b.startsWith(a)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const parseRepeatedExtglob = (pattern, requireEnd = true) => {
|
||||
if ((pattern[0] !== '+' && pattern[0] !== '*') || pattern[1] !== '(') {
|
||||
return;
|
||||
}
|
||||
|
||||
let bracket = 0;
|
||||
let paren = 0;
|
||||
let quote = 0;
|
||||
let escaped = false;
|
||||
|
||||
for (let i = 1; i < pattern.length; i++) {
|
||||
const ch = pattern[i];
|
||||
|
||||
if (escaped === true) {
|
||||
escaped = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch === '\\') {
|
||||
escaped = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch === '"') {
|
||||
quote = quote === 1 ? 0 : 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (quote === 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch === '[') {
|
||||
bracket++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch === ']' && bracket > 0) {
|
||||
bracket--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bracket > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch === '(') {
|
||||
paren++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch === ')') {
|
||||
paren--;
|
||||
|
||||
if (paren === 0) {
|
||||
if (requireEnd === true && i !== pattern.length - 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
type: pattern[0],
|
||||
body: pattern.slice(2, i),
|
||||
end: i
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getStarExtglobSequenceOutput = pattern => {
|
||||
let index = 0;
|
||||
const chars = [];
|
||||
|
||||
while (index < pattern.length) {
|
||||
const match = parseRepeatedExtglob(pattern.slice(index), false);
|
||||
|
||||
if (!match || match.type !== '*') {
|
||||
return;
|
||||
}
|
||||
|
||||
const branches = splitTopLevel(match.body).map(branch => branch.trim());
|
||||
if (branches.length !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const branch = normalizeSimpleBranch(branches[0]);
|
||||
if (!branch || branch.length !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
chars.push(branch);
|
||||
index += match.end + 1;
|
||||
}
|
||||
|
||||
if (chars.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const source = chars.length === 1
|
||||
? utils.escapeRegex(chars[0])
|
||||
: `[${chars.map(ch => utils.escapeRegex(ch)).join('')}]`;
|
||||
|
||||
return `${source}*`;
|
||||
};
|
||||
|
||||
const repeatedExtglobRecursion = pattern => {
|
||||
let depth = 0;
|
||||
let value = pattern.trim();
|
||||
let match = parseRepeatedExtglob(value);
|
||||
|
||||
while (match) {
|
||||
depth++;
|
||||
value = match.body.trim();
|
||||
match = parseRepeatedExtglob(value);
|
||||
}
|
||||
|
||||
return depth;
|
||||
};
|
||||
|
||||
const analyzeRepeatedExtglob = (body, options) => {
|
||||
if (options.maxExtglobRecursion === false) {
|
||||
return { risky: false };
|
||||
}
|
||||
|
||||
const max =
|
||||
typeof options.maxExtglobRecursion === 'number'
|
||||
? options.maxExtglobRecursion
|
||||
: constants.DEFAULT_MAX_EXTGLOB_RECURSION;
|
||||
|
||||
const branches = splitTopLevel(body).map(branch => branch.trim());
|
||||
|
||||
if (branches.length > 1) {
|
||||
if (
|
||||
branches.some(branch => branch === '') ||
|
||||
branches.some(branch => /^[*?]+$/.test(branch)) ||
|
||||
hasRepeatedCharPrefixOverlap(branches)
|
||||
) {
|
||||
return { risky: true };
|
||||
}
|
||||
}
|
||||
|
||||
for (const branch of branches) {
|
||||
const safeOutput = getStarExtglobSequenceOutput(branch);
|
||||
if (safeOutput) {
|
||||
return { risky: true, safeOutput };
|
||||
}
|
||||
|
||||
if (repeatedExtglobRecursion(branch) > max) {
|
||||
return { risky: true };
|
||||
}
|
||||
}
|
||||
|
||||
return { risky: false };
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse the given input string.
|
||||
* @param {String} input
|
||||
@@ -71,9 +342,10 @@ const parse = (input, options) => {
|
||||
const tokens = [bos];
|
||||
|
||||
const capture = opts.capture ? '' : '?:';
|
||||
const win32 = utils.isWindows(options);
|
||||
|
||||
// create constants based on platform, for windows or posix
|
||||
const PLATFORM_CHARS = constants.globChars(opts.windows);
|
||||
const PLATFORM_CHARS = constants.globChars(win32);
|
||||
const EXTGLOB_CHARS = constants.extglobChars(PLATFORM_CHARS);
|
||||
|
||||
const {
|
||||
@@ -209,8 +481,8 @@ const parse = (input, options) => {
|
||||
|
||||
if (tok.value || tok.output) append(tok);
|
||||
if (prev && prev.type === 'text' && tok.type === 'text') {
|
||||
prev.output = (prev.output || prev.value) + tok.value;
|
||||
prev.value += tok.value;
|
||||
prev.output = (prev.output || '') + tok.value;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -225,6 +497,8 @@ const parse = (input, options) => {
|
||||
token.prev = prev;
|
||||
token.parens = state.parens;
|
||||
token.output = state.output;
|
||||
token.startIndex = state.index;
|
||||
token.tokensIndex = tokens.length;
|
||||
const output = (opts.capture ? '(' : '') + token.open;
|
||||
|
||||
increment('parens');
|
||||
@@ -234,6 +508,34 @@ const parse = (input, options) => {
|
||||
};
|
||||
|
||||
const extglobClose = token => {
|
||||
const literal = input.slice(token.startIndex, state.index + 1);
|
||||
const body = input.slice(token.startIndex + 2, state.index);
|
||||
const analysis = analyzeRepeatedExtglob(body, opts);
|
||||
|
||||
if ((token.type === 'plus' || token.type === 'star') && analysis.risky) {
|
||||
const safeOutput = analysis.safeOutput
|
||||
? (token.output ? '' : ONE_CHAR) + (opts.capture ? `(${analysis.safeOutput})` : analysis.safeOutput)
|
||||
: undefined;
|
||||
const open = tokens[token.tokensIndex];
|
||||
|
||||
open.type = 'text';
|
||||
open.value = literal;
|
||||
open.output = safeOutput || utils.escapeRegex(literal);
|
||||
|
||||
for (let i = token.tokensIndex + 1; i < tokens.length; i++) {
|
||||
tokens[i].value = '';
|
||||
tokens[i].output = '';
|
||||
delete tokens[i].suffix;
|
||||
}
|
||||
|
||||
state.output = token.output + open.output;
|
||||
state.backtrack = true;
|
||||
|
||||
push({ type: 'paren', extglob: true, value, output: '' });
|
||||
decrement('parens');
|
||||
return;
|
||||
}
|
||||
|
||||
let output = token.close + (opts.capture ? ')' : '');
|
||||
let rest;
|
||||
|
||||
@@ -698,6 +1000,10 @@ const parse = (input, options) => {
|
||||
const next = peek();
|
||||
let output = value;
|
||||
|
||||
if (next === '<' && !utils.supportsLookbehinds()) {
|
||||
throw new Error('Node.js v10 or higher is required for regex lookbehinds');
|
||||
}
|
||||
|
||||
if ((prev.value === '(' && !/[!=<:]/.test(next)) || (next === '<' && !/<([!=]|\w+>)/.test(remaining()))) {
|
||||
output = `\\${value}`;
|
||||
}
|
||||
@@ -1005,6 +1311,7 @@ parse.fastpaths = (input, options) => {
|
||||
}
|
||||
|
||||
input = REPLACEMENTS[input] || input;
|
||||
const win32 = utils.isWindows(options);
|
||||
|
||||
// create constants based on platform, for windows or posix
|
||||
const {
|
||||
@@ -1017,7 +1324,7 @@ parse.fastpaths = (input, options) => {
|
||||
NO_DOTS_SLASH,
|
||||
STAR,
|
||||
START_ANCHOR
|
||||
} = constants.globChars(opts.windows);
|
||||
} = constants.globChars(win32);
|
||||
|
||||
const nodot = opts.dot ? NO_DOTS : NO_DOT;
|
||||
const slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT;
|
||||
|
||||
+4
-3
@@ -1,5 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const scan = require('./scan');
|
||||
const parse = require('./parse');
|
||||
const utils = require('./utils');
|
||||
@@ -48,7 +49,7 @@ const picomatch = (glob, options, returnState = false) => {
|
||||
}
|
||||
|
||||
const opts = options || {};
|
||||
const posix = opts.windows;
|
||||
const posix = utils.isWindows(options);
|
||||
const regex = isState
|
||||
? picomatch.compileRe(glob, options)
|
||||
: picomatch.makeRe(glob, options, false, true);
|
||||
@@ -157,9 +158,9 @@ picomatch.test = (input, regex, options, { glob, posix } = {}) => {
|
||||
* @api public
|
||||
*/
|
||||
|
||||
picomatch.matchBase = (input, glob, options) => {
|
||||
picomatch.matchBase = (input, glob, options, posix = utils.isWindows(options)) => {
|
||||
const regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options);
|
||||
return regex.test(utils.basename(input));
|
||||
return regex.test(path.basename(input));
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+17
-25
@@ -1,6 +1,7 @@
|
||||
/*global navigator*/
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const win32 = process.platform === 'win32';
|
||||
const {
|
||||
REGEX_BACKSLASH,
|
||||
REGEX_REMOVE_BACKSLASH,
|
||||
@@ -14,25 +15,27 @@ exports.isRegexChar = str => str.length === 1 && exports.hasRegexChars(str);
|
||||
exports.escapeRegex = str => str.replace(REGEX_SPECIAL_CHARS_GLOBAL, '\\$1');
|
||||
exports.toPosixSlashes = str => str.replace(REGEX_BACKSLASH, '/');
|
||||
|
||||
exports.isWindows = () => {
|
||||
if (typeof navigator !== 'undefined' && navigator.platform) {
|
||||
const platform = navigator.platform.toLowerCase();
|
||||
return platform === 'win32' || platform === 'windows';
|
||||
}
|
||||
|
||||
if (typeof process !== 'undefined' && process.platform) {
|
||||
return process.platform === 'win32';
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
exports.removeBackslashes = str => {
|
||||
return str.replace(REGEX_REMOVE_BACKSLASH, match => {
|
||||
return match === '\\' ? '' : match;
|
||||
});
|
||||
};
|
||||
|
||||
exports.supportsLookbehinds = () => {
|
||||
const segs = process.version.slice(1).split('.').map(Number);
|
||||
if (segs.length === 3 && segs[0] >= 9 || (segs[0] === 8 && segs[1] >= 10)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
exports.isWindows = options => {
|
||||
if (options && typeof options.windows === 'boolean') {
|
||||
return options.windows;
|
||||
}
|
||||
return win32 === true || path.sep === '\\';
|
||||
};
|
||||
|
||||
exports.escapeLast = (input, char, lastIdx) => {
|
||||
const idx = input.lastIndexOf(char, lastIdx);
|
||||
if (idx === -1) return input;
|
||||
@@ -59,14 +62,3 @@ exports.wrapOutput = (input, state = {}, options = {}) => {
|
||||
}
|
||||
return output;
|
||||
};
|
||||
|
||||
exports.basename = (path, { windows } = {}) => {
|
||||
const segs = path.split(windows ? /[\\/]/ : '/');
|
||||
const last = segs[segs.length - 1];
|
||||
|
||||
if (last === '') {
|
||||
return segs[segs.length - 2];
|
||||
}
|
||||
|
||||
return last;
|
||||
};
|
||||
|
||||
+5
-7
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "picomatch",
|
||||
"description": "Blazing fast and accurate glob matcher written in JavaScript, with no dependencies and full support for standard and extended Bash glob features, including braces, extglobs, POSIX brackets, and regular expressions.",
|
||||
"version": "4.0.3",
|
||||
"version": "2.3.2",
|
||||
"homepage": "https://github.com/micromatch/picomatch",
|
||||
"author": "Jon Schlinkert (https://github.com/jonschlinkert)",
|
||||
"funding": "https://github.com/sponsors/jonschlinkert",
|
||||
@@ -12,13 +12,11 @@
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"index.js",
|
||||
"posix.js",
|
||||
"lib"
|
||||
],
|
||||
"sideEffects": false,
|
||||
"main": "index.js",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint --cache --cache-location node_modules/.cache/.eslintcache --report-unused-disable-directives --ignore-path .gitignore .",
|
||||
@@ -28,11 +26,11 @@
|
||||
"test:cover": "nyc npm run mocha"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.57.0",
|
||||
"eslint": "^6.8.0",
|
||||
"fill-range": "^7.0.1",
|
||||
"gulp-format-md": "^2.0.0",
|
||||
"mocha": "^10.4.0",
|
||||
"nyc": "^15.1.0",
|
||||
"mocha": "^6.2.2",
|
||||
"nyc": "^15.0.0",
|
||||
"time-require": "github:jonschlinkert/time-require"
|
||||
},
|
||||
"keywords": [
|
||||
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = require('./lib/picomatch');
|
||||
Reference in New Issue
Block a user