new major change
This commit is contained in:
+1
-1
@@ -1,2 +1,2 @@
|
||||
export declare const assertValidPattern: (pattern: any) => void;
|
||||
export declare const assertValidPattern: (pattern: unknown) => void;
|
||||
//# sourceMappingURL=assert-valid-pattern.d.ts.map
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"version":3,"file":"assert-valid-pattern.d.ts","sourceRoot":"","sources":["../../src/assert-valid-pattern.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,kBAAkB,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAUlD,CAAA"}
|
||||
{"version":3,"file":"assert-valid-pattern.d.ts","sourceRoot":"","sources":["../../src/assert-valid-pattern.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,kBAAkB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAUtD,CAAA"}
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"version":3,"file":"assert-valid-pattern.js","sourceRoot":"","sources":["../../src/assert-valid-pattern.ts"],"names":[],"mappings":";;;AAAA,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAE,CAAA;AAC7B,MAAM,kBAAkB,GAA2B,CACxD,OAAY,EACe,EAAE;IAC7B,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,MAAM,IAAI,SAAS,CAAC,iBAAiB,CAAC,CAAA;IACxC,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,kBAAkB,EAAE,CAAC;QACxC,MAAM,IAAI,SAAS,CAAC,qBAAqB,CAAC,CAAA;IAC5C,CAAC;AACH,CAAC,CAAA;AAVY,QAAA,kBAAkB,sBAU9B","sourcesContent":["const MAX_PATTERN_LENGTH = 1024 * 64\nexport const assertValidPattern: (pattern: any) => void = (\n pattern: any,\n): asserts pattern is string => {\n if (typeof pattern !== 'string') {\n throw new TypeError('invalid pattern')\n }\n\n if (pattern.length > MAX_PATTERN_LENGTH) {\n throw new TypeError('pattern is too long')\n }\n}\n"]}
|
||||
{"version":3,"file":"assert-valid-pattern.js","sourceRoot":"","sources":["../../src/assert-valid-pattern.ts"],"names":[],"mappings":";;;AAAA,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAE,CAAA;AAC7B,MAAM,kBAAkB,GAA+B,CAC5D,OAAgB,EACW,EAAE;IAC7B,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,MAAM,IAAI,SAAS,CAAC,iBAAiB,CAAC,CAAA;IACxC,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,kBAAkB,EAAE,CAAC;QACxC,MAAM,IAAI,SAAS,CAAC,qBAAqB,CAAC,CAAA;IAC5C,CAAC;AACH,CAAC,CAAA;AAVY,QAAA,kBAAkB,sBAU9B","sourcesContent":["const MAX_PATTERN_LENGTH = 1024 * 64\nexport const assertValidPattern: (pattern: unknown) => void = (\n pattern: unknown,\n): asserts pattern is string => {\n if (typeof pattern !== 'string') {\n throw new TypeError('invalid pattern')\n }\n\n if (pattern.length > MAX_PATTERN_LENGTH) {\n throw new TypeError('pattern is too long')\n }\n}\n"]}
|
||||
+2
@@ -3,6 +3,8 @@ export type ExtglobType = '!' | '?' | '+' | '*' | '@';
|
||||
export declare class AST {
|
||||
#private;
|
||||
type: ExtglobType | null;
|
||||
id: number;
|
||||
get depth(): number;
|
||||
constructor(type: ExtglobType | null, parent?: AST, options?: MinimatchOptions);
|
||||
get hasMagic(): boolean | undefined;
|
||||
toString(): string;
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/ast.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAwCvD,MAAM,MAAM,WAAW,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;AAkCrD,qBAAa,GAAG;;IACd,IAAI,EAAE,WAAW,GAAG,IAAI,CAAA;gBAiBtB,IAAI,EAAE,WAAW,GAAG,IAAI,EACxB,MAAM,CAAC,EAAE,GAAG,EACZ,OAAO,GAAE,gBAAqB;IAahC,IAAI,QAAQ,IAAI,OAAO,GAAG,SAAS,CAUlC;IAGD,QAAQ,IAAI,MAAM;IA+ClB,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,MAAM,GAAG,GAAG,CAAC,EAAE;IAe/B,MAAM;IAkBN,OAAO,IAAI,OAAO;IAgBlB,KAAK,IAAI,OAAO;IAYhB,MAAM,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM;IAKzB,KAAK,CAAC,MAAM,EAAE,GAAG;IAsIjB,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB;IAQ/D,WAAW,IAAI,QAAQ,GAAG,MAAM;IA2BhC,IAAI,OAAO,qBAEV;IAuED,cAAc,CACZ,QAAQ,CAAC,EAAE,OAAO,GACjB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC;CAwMjE"}
|
||||
{"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/ast.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAwCvD,MAAM,MAAM,WAAW,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;AA6IrD,qBAAa,GAAG;;IACd,IAAI,EAAE,WAAW,GAAG,IAAI,CAAA;IAexB,EAAE,SAAO;IAET,IAAI,KAAK,IAAI,MAAM,CAElB;gBAgBC,IAAI,EAAE,WAAW,GAAG,IAAI,EACxB,MAAM,CAAC,EAAE,GAAG,EACZ,OAAO,GAAE,gBAAqB;IAahC,IAAI,QAAQ,IAAI,OAAO,GAAG,SAAS,CAUlC;IAGD,QAAQ,IAAI,MAAM;IA+ClB,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,MAAM,GAAG,GAAG,CAAC,EAAE;IAe/B,MAAM;IAkBN,OAAO,IAAI,OAAO;IAgBlB,KAAK,IAAI,OAAO;IAYhB,MAAM,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM;IAKzB,KAAK,CAAC,MAAM,EAAE,GAAG;IAwQjB,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB;IAQ/D,WAAW,IAAI,QAAQ,GAAG,MAAM;IA2BhC,IAAI,OAAO,qBAEV;IAuED,cAAc,CACZ,QAAQ,CAAC,EAAE,OAAO,GACjB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC;CA6OjE"}
|
||||
+266
-21
@@ -1,11 +1,113 @@
|
||||
"use strict";
|
||||
// parse a single path portion
|
||||
var _a;
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AST = void 0;
|
||||
const brace_expressions_js_1 = require("./brace-expressions.js");
|
||||
const unescape_js_1 = require("./unescape.js");
|
||||
const types = new Set(['!', '?', '+', '*', '@']);
|
||||
const isExtglobType = (c) => types.has(c);
|
||||
const isExtglobAST = (c) => isExtglobType(c.type);
|
||||
// Map of which extglob types can adopt the children of a nested extglob
|
||||
//
|
||||
// anything but ! can adopt a matching type:
|
||||
// +(a|+(b|c)|d) => +(a|b|c|d)
|
||||
// *(a|*(b|c)|d) => *(a|b|c|d)
|
||||
// @(a|@(b|c)|d) => @(a|b|c|d)
|
||||
// ?(a|?(b|c)|d) => ?(a|b|c|d)
|
||||
//
|
||||
// * can adopt anything, because 0 or repetition is allowed
|
||||
// *(a|?(b|c)|d) => *(a|b|c|d)
|
||||
// *(a|+(b|c)|d) => *(a|b|c|d)
|
||||
// *(a|@(b|c)|d) => *(a|b|c|d)
|
||||
//
|
||||
// + can adopt @, because 1 or repetition is allowed
|
||||
// +(a|@(b|c)|d) => +(a|b|c|d)
|
||||
//
|
||||
// + and @ CANNOT adopt *, because 0 would be allowed
|
||||
// +(a|*(b|c)|d) => would match "", on *(b|c)
|
||||
// @(a|*(b|c)|d) => would match "", on *(b|c)
|
||||
//
|
||||
// + and @ CANNOT adopt ?, because 0 would be allowed
|
||||
// +(a|?(b|c)|d) => would match "", on ?(b|c)
|
||||
// @(a|?(b|c)|d) => would match "", on ?(b|c)
|
||||
//
|
||||
// ? can adopt @, because 0 or 1 is allowed
|
||||
// ?(a|@(b|c)|d) => ?(a|b|c|d)
|
||||
//
|
||||
// ? and @ CANNOT adopt * or +, because >1 would be allowed
|
||||
// ?(a|*(b|c)|d) => would match bbb on *(b|c)
|
||||
// @(a|*(b|c)|d) => would match bbb on *(b|c)
|
||||
// ?(a|+(b|c)|d) => would match bbb on +(b|c)
|
||||
// @(a|+(b|c)|d) => would match bbb on +(b|c)
|
||||
//
|
||||
// ! CANNOT adopt ! (nothing else can either)
|
||||
// !(a|!(b|c)|d) => !(a|b|c|d) would fail to match on b (not not b|c)
|
||||
//
|
||||
// ! can adopt @
|
||||
// !(a|@(b|c)|d) => !(a|b|c|d)
|
||||
//
|
||||
// ! CANNOT adopt *
|
||||
// !(a|*(b|c)|d) => !(a|b|c|d) would match on bbb, not allowed
|
||||
//
|
||||
// ! CANNOT adopt +
|
||||
// !(a|+(b|c)|d) => !(a|b|c|d) would match on bbb, not allowed
|
||||
//
|
||||
// ! CANNOT adopt ?
|
||||
// x!(a|?(b|c)|d) => x!(a|b|c|d) would fail to match "x"
|
||||
const adoptionMap = new Map([
|
||||
['!', ['@']],
|
||||
['?', ['?', '@']],
|
||||
['@', ['@']],
|
||||
['*', ['*', '+', '?', '@']],
|
||||
['+', ['+', '@']],
|
||||
]);
|
||||
// nested extglobs that can be adopted in, but with the addition of
|
||||
// a blank '' element.
|
||||
const adoptionWithSpaceMap = new Map([
|
||||
['!', ['?']],
|
||||
['@', ['?']],
|
||||
['+', ['?', '*']],
|
||||
]);
|
||||
// union of the previous two maps
|
||||
const adoptionAnyMap = new Map([
|
||||
['!', ['?', '@']],
|
||||
['?', ['?', '@']],
|
||||
['@', ['?', '@']],
|
||||
['*', ['*', '+', '?', '@']],
|
||||
['+', ['+', '@', '?', '*']],
|
||||
]);
|
||||
// Extglobs that can take over their parent if they are the only child
|
||||
// the key is parent, value maps child to resulting extglob parent type
|
||||
// '@' is omitted because it's a special case. An `@` extglob with a single
|
||||
// member can always be usurped by that subpattern.
|
||||
const usurpMap = new Map([
|
||||
['!', new Map([['!', '@']])],
|
||||
[
|
||||
'?',
|
||||
new Map([
|
||||
['*', '*'],
|
||||
['+', '*'],
|
||||
]),
|
||||
],
|
||||
[
|
||||
'@',
|
||||
new Map([
|
||||
['!', '!'],
|
||||
['?', '?'],
|
||||
['@', '@'],
|
||||
['*', '*'],
|
||||
['+', '+'],
|
||||
]),
|
||||
],
|
||||
[
|
||||
'+',
|
||||
new Map([
|
||||
['?', '*'],
|
||||
['*', '*'],
|
||||
]),
|
||||
],
|
||||
]);
|
||||
// Patterns that get prepended to bind to the start of either the
|
||||
// entire string, or just a single path portion, to prevent dots
|
||||
// and/or traversal patterns, when needed.
|
||||
@@ -29,6 +131,7 @@ const star = qmark + '*?';
|
||||
const starNoEmpty = qmark + '+?';
|
||||
// remove the \ chars that we added if we end up doing a nonmagic compare
|
||||
// const deslash = (s: string) => s.replace(/\\(.)/g, '$1')
|
||||
let ID = 0;
|
||||
class AST {
|
||||
type;
|
||||
#root;
|
||||
@@ -44,6 +147,22 @@ class AST {
|
||||
// set to true if it's an extglob with no children
|
||||
// (which really means one child of '')
|
||||
#emptyExt = false;
|
||||
id = ++ID;
|
||||
get depth() {
|
||||
return (this.#parent?.depth ?? -1) + 1;
|
||||
}
|
||||
[Symbol.for('nodejs.util.inspect.custom')]() {
|
||||
return {
|
||||
'@@type': 'AST',
|
||||
id: this.id,
|
||||
type: this.type,
|
||||
root: this.#root.id,
|
||||
parent: this.#parent?.id,
|
||||
depth: this.depth,
|
||||
partsLength: this.#parts.length,
|
||||
parts: this.#parts,
|
||||
};
|
||||
}
|
||||
constructor(type, parent, options = {}) {
|
||||
this.type = type;
|
||||
// extglobs are inherently magical
|
||||
@@ -123,7 +242,7 @@ class AST {
|
||||
continue;
|
||||
/* c8 ignore start */
|
||||
if (typeof p !== 'string' &&
|
||||
!(p instanceof AST && p.#parent === this)) {
|
||||
!(p instanceof _a && p.#parent === this)) {
|
||||
throw new Error('invalid part: ' + p);
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
@@ -157,7 +276,7 @@ class AST {
|
||||
const p = this.#parent;
|
||||
for (let i = 0; i < this.#parentIndex; i++) {
|
||||
const pp = p.#parts[i];
|
||||
if (!(pp instanceof AST && pp.type === '!')) {
|
||||
if (!(pp instanceof _a && pp.type === '!')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -185,13 +304,14 @@ class AST {
|
||||
this.push(part.clone(this));
|
||||
}
|
||||
clone(parent) {
|
||||
const c = new AST(this.type, parent);
|
||||
const c = new _a(this.type, parent);
|
||||
for (const p of this.#parts) {
|
||||
c.copyIn(p);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
static #parseAST(str, ast, pos, opt) {
|
||||
static #parseAST(str, ast, pos, opt, extDepth) {
|
||||
const maxDepth = opt.maxExtglobRecursion ?? 2;
|
||||
let escaping = false;
|
||||
let inBrace = false;
|
||||
let braceStart = -1;
|
||||
@@ -228,11 +348,17 @@ class AST {
|
||||
acc += c;
|
||||
continue;
|
||||
}
|
||||
if (!opt.noext && isExtglobType(c) && str.charAt(i) === '(') {
|
||||
// we don't have to check for adoption here, because that's
|
||||
// done at the other recursion point.
|
||||
const doRecurse = !opt.noext &&
|
||||
isExtglobType(c) &&
|
||||
str.charAt(i) === '(' &&
|
||||
extDepth <= maxDepth;
|
||||
if (doRecurse) {
|
||||
ast.push(acc);
|
||||
acc = '';
|
||||
const ext = new AST(c, ast);
|
||||
i = AST.#parseAST(str, ext, i, opt);
|
||||
const ext = new _a(c, ast);
|
||||
i = _a.#parseAST(str, ext, i, opt, extDepth + 1);
|
||||
ast.push(ext);
|
||||
continue;
|
||||
}
|
||||
@@ -244,7 +370,7 @@ class AST {
|
||||
// some kind of extglob, pos is at the (
|
||||
// find the next | or )
|
||||
let i = pos + 1;
|
||||
let part = new AST(null, ast);
|
||||
let part = new _a(null, ast);
|
||||
const parts = [];
|
||||
let acc = '';
|
||||
while (i < str.length) {
|
||||
@@ -275,19 +401,26 @@ class AST {
|
||||
acc += c;
|
||||
continue;
|
||||
}
|
||||
if (isExtglobType(c) && str.charAt(i) === '(') {
|
||||
const doRecurse = !opt.noext &&
|
||||
isExtglobType(c) &&
|
||||
str.charAt(i) === '(' &&
|
||||
/* c8 ignore start - the maxDepth is sufficient here */
|
||||
(extDepth <= maxDepth || (ast && ast.#canAdoptType(c)));
|
||||
/* c8 ignore stop */
|
||||
if (doRecurse) {
|
||||
const depthAdd = ast && ast.#canAdoptType(c) ? 0 : 1;
|
||||
part.push(acc);
|
||||
acc = '';
|
||||
const ext = new AST(c, part);
|
||||
const ext = new _a(c, part);
|
||||
part.push(ext);
|
||||
i = AST.#parseAST(str, ext, i, opt);
|
||||
i = _a.#parseAST(str, ext, i, opt, extDepth + depthAdd);
|
||||
continue;
|
||||
}
|
||||
if (c === '|') {
|
||||
part.push(acc);
|
||||
acc = '';
|
||||
parts.push(part);
|
||||
part = new AST(null, ast);
|
||||
part = new _a(null, ast);
|
||||
continue;
|
||||
}
|
||||
if (c === ')') {
|
||||
@@ -309,9 +442,82 @@ class AST {
|
||||
ast.#parts = [str.substring(pos - 1)];
|
||||
return i;
|
||||
}
|
||||
#canAdoptWithSpace(child) {
|
||||
return this.#canAdopt(child, adoptionWithSpaceMap);
|
||||
}
|
||||
#canAdopt(child, map = adoptionMap) {
|
||||
if (!child ||
|
||||
typeof child !== 'object' ||
|
||||
child.type !== null ||
|
||||
child.#parts.length !== 1 ||
|
||||
this.type === null) {
|
||||
return false;
|
||||
}
|
||||
const gc = child.#parts[0];
|
||||
if (!gc || typeof gc !== 'object' || gc.type === null) {
|
||||
return false;
|
||||
}
|
||||
return this.#canAdoptType(gc.type, map);
|
||||
}
|
||||
#canAdoptType(c, map = adoptionAnyMap) {
|
||||
return !!map.get(this.type)?.includes(c);
|
||||
}
|
||||
#adoptWithSpace(child, index) {
|
||||
const gc = child.#parts[0];
|
||||
const blank = new _a(null, gc, this.options);
|
||||
blank.#parts.push('');
|
||||
gc.push(blank);
|
||||
this.#adopt(child, index);
|
||||
}
|
||||
#adopt(child, index) {
|
||||
const gc = child.#parts[0];
|
||||
this.#parts.splice(index, 1, ...gc.#parts);
|
||||
for (const p of gc.#parts) {
|
||||
if (typeof p === 'object')
|
||||
p.#parent = this;
|
||||
}
|
||||
this.#toString = undefined;
|
||||
}
|
||||
#canUsurpType(c) {
|
||||
const m = usurpMap.get(this.type);
|
||||
return !!(m?.has(c));
|
||||
}
|
||||
#canUsurp(child) {
|
||||
if (!child ||
|
||||
typeof child !== 'object' ||
|
||||
child.type !== null ||
|
||||
child.#parts.length !== 1 ||
|
||||
this.type === null ||
|
||||
this.#parts.length !== 1) {
|
||||
return false;
|
||||
}
|
||||
const gc = child.#parts[0];
|
||||
if (!gc || typeof gc !== 'object' || gc.type === null) {
|
||||
return false;
|
||||
}
|
||||
return this.#canUsurpType(gc.type);
|
||||
}
|
||||
#usurp(child) {
|
||||
const m = usurpMap.get(this.type);
|
||||
const gc = child.#parts[0];
|
||||
const nt = m?.get(gc.type);
|
||||
/* c8 ignore start - impossible */
|
||||
if (!nt)
|
||||
return false;
|
||||
/* c8 ignore stop */
|
||||
this.#parts = gc.#parts;
|
||||
for (const p of this.#parts) {
|
||||
if (typeof p === 'object') {
|
||||
p.#parent = this;
|
||||
}
|
||||
}
|
||||
this.type = nt;
|
||||
this.#toString = undefined;
|
||||
this.#emptyExt = false;
|
||||
}
|
||||
static fromGlob(pattern, options = {}) {
|
||||
const ast = new AST(null, undefined, options);
|
||||
AST.#parseAST(pattern, ast, 0, options);
|
||||
const ast = new _a(null, undefined, options);
|
||||
_a.#parseAST(pattern, ast, 0, options, 0);
|
||||
return ast;
|
||||
}
|
||||
// returns the regular expression if there's magic, or the unescaped
|
||||
@@ -415,16 +621,18 @@ class AST {
|
||||
// or start or whatever) and prepend ^ or / at the Regexp construction.
|
||||
toRegExpSource(allowDot) {
|
||||
const dot = allowDot ?? !!this.#options.dot;
|
||||
if (this.#root === this)
|
||||
if (this.#root === this) {
|
||||
this.#flatten();
|
||||
this.#fillNegs();
|
||||
if (!this.type) {
|
||||
}
|
||||
if (!isExtglobAST(this)) {
|
||||
const noEmpty = this.isStart() &&
|
||||
this.isEnd() &&
|
||||
!this.#parts.some(s => typeof s !== 'string');
|
||||
const src = this.#parts
|
||||
.map(p => {
|
||||
const [re, _, hasMagic, uflag] = typeof p === 'string' ?
|
||||
AST.#parseGlob(p, this.#hasMagic, noEmpty)
|
||||
_a.#parseGlob(p, this.#hasMagic, noEmpty)
|
||||
: p.toRegExpSource(allowDot);
|
||||
this.#hasMagic = this.#hasMagic || hasMagic;
|
||||
this.#uflag = this.#uflag || uflag;
|
||||
@@ -486,12 +694,12 @@ class AST {
|
||||
// invalid extglob, has to at least be *something* present, if it's
|
||||
// the entire path portion.
|
||||
const s = this.toString();
|
||||
this.#parts = [s];
|
||||
this.type = null;
|
||||
this.#hasMagic = undefined;
|
||||
const me = this;
|
||||
me.#parts = [s];
|
||||
me.type = null;
|
||||
me.#hasMagic = undefined;
|
||||
return [s, (0, unescape_js_1.unescape)(this.toString()), false, false];
|
||||
}
|
||||
// XXX abstract out this map method
|
||||
let bodyDotAllowed = !repeated || allowDot || dot || !startNoDot ?
|
||||
''
|
||||
: this.#partsToRegExp(true);
|
||||
@@ -527,6 +735,42 @@ class AST {
|
||||
this.#uflag,
|
||||
];
|
||||
}
|
||||
#flatten() {
|
||||
if (!isExtglobAST(this)) {
|
||||
for (const p of this.#parts) {
|
||||
if (typeof p === 'object') {
|
||||
p.#flatten();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// do up to 10 passes to flatten as much as possible
|
||||
let iterations = 0;
|
||||
let done = false;
|
||||
do {
|
||||
done = true;
|
||||
for (let i = 0; i < this.#parts.length; i++) {
|
||||
const c = this.#parts[i];
|
||||
if (typeof c === 'object') {
|
||||
c.#flatten();
|
||||
if (this.#canAdopt(c)) {
|
||||
done = false;
|
||||
this.#adopt(c, i);
|
||||
}
|
||||
else if (this.#canAdoptWithSpace(c)) {
|
||||
done = false;
|
||||
this.#adoptWithSpace(c, i);
|
||||
}
|
||||
else if (this.#canUsurp(c)) {
|
||||
done = false;
|
||||
this.#usurp(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!done && ++iterations < 10);
|
||||
}
|
||||
this.#toString = undefined;
|
||||
}
|
||||
#partsToRegExp(dot) {
|
||||
return this.#parts
|
||||
.map(p => {
|
||||
@@ -598,4 +842,5 @@ class AST {
|
||||
}
|
||||
}
|
||||
exports.AST = AST;
|
||||
_a = AST;
|
||||
//# sourceMappingURL=ast.js.map
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+30
@@ -71,6 +71,34 @@ export interface MinimatchOptions {
|
||||
* max number of `{...}` patterns to expand. Default 100_000.
|
||||
*/
|
||||
braceExpandMax?: number;
|
||||
/**
|
||||
* Max number of non-adjacent `**` patterns to recursively walk down.
|
||||
*
|
||||
* The default of 200 is almost certainly high enough for most purposes,
|
||||
* and can handle absurdly excessive patterns.
|
||||
*/
|
||||
maxGlobstarRecursion?: number;
|
||||
/**
|
||||
* Max depth to traverse for nested extglobs like `*(a|b|c)`
|
||||
*
|
||||
* Default is 2, which is quite low, but any higher value
|
||||
* swiftly results in punishing performance impacts. Note
|
||||
* that this is *not* relevant when the globstar types can
|
||||
* be safely coalesced into a single set.
|
||||
*
|
||||
* For example, `*(a|@(b|c)|d)` would be flattened into
|
||||
* `*(a|b|c|d)`. Thus, many common extglobs will retain good
|
||||
* performance and never hit this limit, even if they are
|
||||
* excessively deep and complicated.
|
||||
*
|
||||
* If the limit is hit, then the extglob characters are simply
|
||||
* not parsed, and the pattern effectively switches into
|
||||
* `noextglob: true` mode for the contents of that nested
|
||||
* sub-pattern. This will typically _not_ result in a match,
|
||||
* but is considered a valid trade-off for security and
|
||||
* performance.
|
||||
*/
|
||||
maxExtglobRecursion?: number;
|
||||
}
|
||||
export declare const minimatch: {
|
||||
(p: string, pattern: string, options?: MinimatchOptions): boolean;
|
||||
@@ -101,6 +129,7 @@ export type MMRegExp = RegExp & {
|
||||
export type ParseReturnFiltered = string | MMRegExp | typeof GLOBSTAR;
|
||||
export type ParseReturn = ParseReturnFiltered | false;
|
||||
export declare class Minimatch {
|
||||
#private;
|
||||
options: MinimatchOptions;
|
||||
set: ParseReturnFiltered[][];
|
||||
pattern: string;
|
||||
@@ -117,6 +146,7 @@ export declare class Minimatch {
|
||||
isWindows: boolean;
|
||||
platform: Platform;
|
||||
windowsNoMagicRoot: boolean;
|
||||
maxGlobstarRecursion: number;
|
||||
regexp: false | null | MMRegExp;
|
||||
constructor(pattern: string, options?: MinimatchOptions);
|
||||
hasMagic(): boolean;
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
||||
+178
-92
@@ -202,11 +202,13 @@ class Minimatch {
|
||||
isWindows;
|
||||
platform;
|
||||
windowsNoMagicRoot;
|
||||
maxGlobstarRecursion;
|
||||
regexp;
|
||||
constructor(pattern, options = {}) {
|
||||
(0, assert_valid_pattern_js_1.assertValidPattern)(pattern);
|
||||
options = options || {};
|
||||
this.options = options;
|
||||
this.maxGlobstarRecursion = options.maxGlobstarRecursion ?? 200;
|
||||
this.pattern = pattern;
|
||||
this.platform = options.platform || defaultPlatform;
|
||||
this.isWindows = this.platform === 'win32';
|
||||
@@ -611,7 +613,8 @@ class Minimatch {
|
||||
// out of pattern, then that's fine, as long as all
|
||||
// the parts match.
|
||||
matchOne(file, pattern, partial = false) {
|
||||
const options = this.options;
|
||||
let fileStartIndex = 0;
|
||||
let patternStartIndex = 0;
|
||||
// UNC paths like //?/X:/... can match X:/... and vice versa
|
||||
// Drive letters in absolute drive or unc paths are always compared
|
||||
// case-insensitively.
|
||||
@@ -640,14 +643,11 @@ class Minimatch {
|
||||
file[fdi],
|
||||
pattern[pdi],
|
||||
];
|
||||
// start matching at the drive letter index of each
|
||||
if (fd.toLowerCase() === pd.toLowerCase()) {
|
||||
pattern[pdi] = fd;
|
||||
if (pdi > fdi) {
|
||||
pattern = pattern.slice(pdi);
|
||||
}
|
||||
else if (fdi > pdi) {
|
||||
file = file.slice(fdi);
|
||||
}
|
||||
patternStartIndex = pdi;
|
||||
fileStartIndex = fdi;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -657,99 +657,185 @@ class Minimatch {
|
||||
if (optimizationLevel >= 2) {
|
||||
file = this.levelTwoFileOptimize(file);
|
||||
}
|
||||
this.debug('matchOne', this, { file, pattern });
|
||||
this.debug('matchOne', file.length, pattern.length);
|
||||
for (var fi = 0, pi = 0, fl = file.length, pl = pattern.length; fi < fl && pi < pl; fi++, pi++) {
|
||||
if (pattern.includes(exports.GLOBSTAR)) {
|
||||
return this.#matchGlobstar(file, pattern, partial, fileStartIndex, patternStartIndex);
|
||||
}
|
||||
return this.#matchOne(file, pattern, partial, fileStartIndex, patternStartIndex);
|
||||
}
|
||||
#matchGlobstar(file, pattern, partial, fileIndex, patternIndex) {
|
||||
// split the pattern into head, tail, and middle of ** delimited parts
|
||||
const firstgs = pattern.indexOf(exports.GLOBSTAR, patternIndex);
|
||||
const lastgs = pattern.lastIndexOf(exports.GLOBSTAR);
|
||||
// split the pattern up into globstar-delimited sections
|
||||
// the tail has to be at the end, and the others just have
|
||||
// to be found in order from the head.
|
||||
const [head, body, tail] = partial ? [
|
||||
pattern.slice(patternIndex, firstgs),
|
||||
pattern.slice(firstgs + 1),
|
||||
[],
|
||||
] : [
|
||||
pattern.slice(patternIndex, firstgs),
|
||||
pattern.slice(firstgs + 1, lastgs),
|
||||
pattern.slice(lastgs + 1),
|
||||
];
|
||||
// check the head, from the current file/pattern index.
|
||||
if (head.length) {
|
||||
const fileHead = file.slice(fileIndex, fileIndex + head.length);
|
||||
if (!this.#matchOne(fileHead, head, partial, 0, 0)) {
|
||||
return false;
|
||||
}
|
||||
fileIndex += head.length;
|
||||
patternIndex += head.length;
|
||||
}
|
||||
// now we know the head matches!
|
||||
// if the last portion is not empty, it MUST match the end
|
||||
// check the tail
|
||||
let fileTailMatch = 0;
|
||||
if (tail.length) {
|
||||
// if head + tail > file, then we cannot possibly match
|
||||
if (tail.length + fileIndex > file.length)
|
||||
return false;
|
||||
// try to match the tail
|
||||
let tailStart = file.length - tail.length;
|
||||
if (this.#matchOne(file, tail, partial, tailStart, 0)) {
|
||||
fileTailMatch = tail.length;
|
||||
}
|
||||
else {
|
||||
// affordance for stuff like a/**/* matching a/b/
|
||||
// if the last file portion is '', and there's more to the pattern
|
||||
// then try without the '' bit.
|
||||
if (file[file.length - 1] !== '' ||
|
||||
fileIndex + tail.length === file.length) {
|
||||
return false;
|
||||
}
|
||||
tailStart--;
|
||||
if (!this.#matchOne(file, tail, partial, tailStart, 0)) {
|
||||
return false;
|
||||
}
|
||||
fileTailMatch = tail.length + 1;
|
||||
}
|
||||
}
|
||||
// now we know the tail matches!
|
||||
// the middle is zero or more portions wrapped in **, possibly
|
||||
// containing more ** sections.
|
||||
// so a/**/b/**/c/**/d has become **/b/**/c/**
|
||||
// if it's empty, it means a/**/b, just verify we have no bad dots
|
||||
// if there's no tail, so it ends on /**, then we must have *something*
|
||||
// after the head, or it's not a matc
|
||||
if (!body.length) {
|
||||
let sawSome = !!fileTailMatch;
|
||||
for (let i = fileIndex; i < file.length - fileTailMatch; i++) {
|
||||
const f = String(file[i]);
|
||||
sawSome = true;
|
||||
if (f === '.' ||
|
||||
f === '..' ||
|
||||
(!this.options.dot && f.startsWith('.'))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// in partial mode, we just need to get past all file parts
|
||||
return partial || sawSome;
|
||||
}
|
||||
// now we know that there's one or more body sections, which can
|
||||
// be matched anywhere from the 0 index (because the head was pruned)
|
||||
// through to the length-fileTailMatch index.
|
||||
// split the body up into sections, and note the minimum index it can
|
||||
// be found at (start with the length of all previous segments)
|
||||
// [section, before, after]
|
||||
const bodySegments = [[[], 0]];
|
||||
let currentBody = bodySegments[0];
|
||||
let nonGsParts = 0;
|
||||
const nonGsPartsSums = [0];
|
||||
for (const b of body) {
|
||||
if (b === exports.GLOBSTAR) {
|
||||
nonGsPartsSums.push(nonGsParts);
|
||||
currentBody = [[], 0];
|
||||
bodySegments.push(currentBody);
|
||||
}
|
||||
else {
|
||||
currentBody[0].push(b);
|
||||
nonGsParts++;
|
||||
}
|
||||
}
|
||||
let i = bodySegments.length - 1;
|
||||
const fileLength = file.length - fileTailMatch;
|
||||
for (const b of bodySegments) {
|
||||
b[1] = fileLength - (nonGsPartsSums[i--] + b[0].length);
|
||||
}
|
||||
return !!this.#matchGlobStarBodySections(file, bodySegments, fileIndex, 0, partial, 0, !!fileTailMatch);
|
||||
}
|
||||
// return false for "nope, not matching"
|
||||
// return null for "not matching, cannot keep trying"
|
||||
#matchGlobStarBodySections(file,
|
||||
// pattern section, last possible position for it
|
||||
bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail) {
|
||||
// take the first body segment, and walk from fileIndex to its "after"
|
||||
// value at the end
|
||||
// If it doesn't match at that position, we increment, until we hit
|
||||
// that final possible position, and give up.
|
||||
// If it does match, then advance and try to rest.
|
||||
// If any of them fail we keep walking forward.
|
||||
// this is still a bit recursively painful, but it's more constrained
|
||||
// than previous implementations, because we never test something that
|
||||
// can't possibly be a valid matching condition.
|
||||
const bs = bodySegments[bodyIndex];
|
||||
if (!bs) {
|
||||
// just make sure that there's no bad dots
|
||||
for (let i = fileIndex; i < file.length; i++) {
|
||||
sawTail = true;
|
||||
const f = file[i];
|
||||
if (f === '.' ||
|
||||
f === '..' ||
|
||||
(!this.options.dot && f.startsWith('.'))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return sawTail;
|
||||
}
|
||||
// have a non-globstar body section to test
|
||||
const [body, after] = bs;
|
||||
while (fileIndex <= after) {
|
||||
const m = this.#matchOne(file.slice(0, fileIndex + body.length), body, partial, fileIndex, 0);
|
||||
// if limit exceeded, no match. intentional false negative,
|
||||
// acceptable break in correctness for security.
|
||||
if (m && globStarDepth < this.maxGlobstarRecursion) {
|
||||
// match! see if the rest match. if so, we're done!
|
||||
const sub = this.#matchGlobStarBodySections(file, bodySegments, fileIndex + body.length, bodyIndex + 1, partial, globStarDepth + 1, sawTail);
|
||||
if (sub !== false) {
|
||||
return sub;
|
||||
}
|
||||
}
|
||||
const f = file[fileIndex];
|
||||
if (f === '.' ||
|
||||
f === '..' ||
|
||||
(!this.options.dot && f.startsWith('.'))) {
|
||||
return false;
|
||||
}
|
||||
fileIndex++;
|
||||
}
|
||||
// walked off. no point continuing
|
||||
return partial || null;
|
||||
}
|
||||
#matchOne(file, pattern, partial, fileIndex, patternIndex) {
|
||||
let fi;
|
||||
let pi;
|
||||
let pl;
|
||||
let fl;
|
||||
for (fi = fileIndex,
|
||||
pi = patternIndex,
|
||||
fl = file.length,
|
||||
pl = pattern.length; fi < fl && pi < pl; fi++, pi++) {
|
||||
this.debug('matchOne loop');
|
||||
var p = pattern[pi];
|
||||
var f = file[fi];
|
||||
let p = pattern[pi];
|
||||
let f = file[fi];
|
||||
this.debug(pattern, p, f);
|
||||
// should be impossible.
|
||||
// some invalid regexp stuff in the set.
|
||||
/* c8 ignore start */
|
||||
if (p === false) {
|
||||
if (p === false || p === exports.GLOBSTAR) {
|
||||
return false;
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
if (p === exports.GLOBSTAR) {
|
||||
this.debug('GLOBSTAR', [pattern, p, f]);
|
||||
// "**"
|
||||
// a/**/b/**/c would match the following:
|
||||
// a/b/x/y/z/c
|
||||
// a/x/y/z/b/c
|
||||
// a/b/x/b/x/c
|
||||
// a/b/c
|
||||
// To do this, take the rest of the pattern after
|
||||
// the **, and see if it would match the file remainder.
|
||||
// If so, return success.
|
||||
// If not, the ** "swallows" a segment, and try again.
|
||||
// This is recursively awful.
|
||||
//
|
||||
// a/**/b/**/c matching a/b/x/y/z/c
|
||||
// - a matches a
|
||||
// - doublestar
|
||||
// - matchOne(b/x/y/z/c, b/**/c)
|
||||
// - b matches b
|
||||
// - doublestar
|
||||
// - matchOne(x/y/z/c, c) -> no
|
||||
// - matchOne(y/z/c, c) -> no
|
||||
// - matchOne(z/c, c) -> no
|
||||
// - matchOne(c, c) yes, hit
|
||||
var fr = fi;
|
||||
var pr = pi + 1;
|
||||
if (pr === pl) {
|
||||
this.debug('** at the end');
|
||||
// a ** at the end will just swallow the rest.
|
||||
// We have found a match.
|
||||
// however, it will not swallow /.x, unless
|
||||
// options.dot is set.
|
||||
// . and .. are *never* matched by **, for explosively
|
||||
// exponential reasons.
|
||||
for (; fi < fl; fi++) {
|
||||
if (file[fi] === '.' ||
|
||||
file[fi] === '..' ||
|
||||
(!options.dot && file[fi].charAt(0) === '.'))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// ok, let's see if we can swallow whatever we can.
|
||||
while (fr < fl) {
|
||||
var swallowee = file[fr];
|
||||
this.debug('\nglobstar while', file, fr, pattern, pr, swallowee);
|
||||
// XXX remove this slice. Just pass the start index.
|
||||
if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
|
||||
this.debug('globstar found match!', fr, fl, swallowee);
|
||||
// found a match.
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// can't swallow "." or ".." ever.
|
||||
// can only swallow ".foo" when explicitly asked.
|
||||
if (swallowee === '.' ||
|
||||
swallowee === '..' ||
|
||||
(!options.dot && swallowee.charAt(0) === '.')) {
|
||||
this.debug('dot detected!', file, fr, pattern, pr);
|
||||
break;
|
||||
}
|
||||
// ** swallows a segment, and continue.
|
||||
this.debug('globstar swallow a segment, and continue');
|
||||
fr++;
|
||||
}
|
||||
}
|
||||
// no match was found.
|
||||
// However, in partial mode, we can't say this is necessarily over.
|
||||
/* c8 ignore start */
|
||||
if (partial) {
|
||||
// ran out of file
|
||||
this.debug('\n>>> no match, partial?', file, fr, pattern, pr);
|
||||
if (fr === fl) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
return false;
|
||||
}
|
||||
// something other than **
|
||||
// non-magic patterns just have to match exactly
|
||||
// patterns with magic have been turned into regexps.
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user