@vue/compiler-sfc 3.5.43 → 3.5.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compiler-sfc.cjs.js +1872 -1370
- package/dist/compiler-sfc.esm-browser.js +6652 -6202
- package/package.json +12 -12
package/dist/compiler-sfc.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @vue/compiler-sfc v3.5.
|
|
2
|
+
* @vue/compiler-sfc v3.5.45
|
|
3
3
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
4
4
|
* @license MIT
|
|
5
5
|
**/
|
|
@@ -4542,13 +4542,11 @@ function requireUnesc$1 () {
|
|
|
4542
4542
|
function gobbleHex(str) {
|
|
4543
4543
|
var lower = str.toLowerCase();
|
|
4544
4544
|
var hex = "";
|
|
4545
|
-
var spaceTerminated = false;
|
|
4546
4545
|
for (var i = 0; i < 6 && lower[i] !== undefined; i++) {
|
|
4547
4546
|
var code = lower.charCodeAt(i);
|
|
4548
4547
|
// check to see if we are dealing with a valid hex char [a-f|0-9]
|
|
4549
4548
|
var valid = (code >= 97 && code <= 102) || (code >= 48 && code <= 57);
|
|
4550
4549
|
// https://drafts.csswg.org/css-syntax/#consume-escaped-code-point
|
|
4551
|
-
spaceTerminated = code === 32;
|
|
4552
4550
|
if (!valid) {
|
|
4553
4551
|
break;
|
|
4554
4552
|
}
|
|
@@ -4557,15 +4555,21 @@ function requireUnesc$1 () {
|
|
|
4557
4555
|
if (hex.length === 0) {
|
|
4558
4556
|
return undefined;
|
|
4559
4557
|
}
|
|
4558
|
+
var consumed = hex.length;
|
|
4559
|
+
var next = str[consumed];
|
|
4560
|
+
if (next === " " || next === "\t" || next === "\n" || next === "\r" || next === "\f") {
|
|
4561
|
+
// CSS preprocessing treats CRLF as a single newline.
|
|
4562
|
+
consumed += next === "\r" && str[consumed + 1] === "\n" ? 2 : 1;
|
|
4563
|
+
}
|
|
4560
4564
|
var codePoint = parseInt(hex, 16);
|
|
4561
4565
|
var isSurrogate = codePoint >= 0xd800 && codePoint <= 0xdfff;
|
|
4562
4566
|
// Add special case for
|
|
4563
4567
|
// "If this number is zero, or is for a surrogate, or is greater than the maximum allowed code point"
|
|
4564
4568
|
// https://drafts.csswg.org/css-syntax/#maximum-allowed-code-point
|
|
4565
4569
|
if (isSurrogate || codePoint === 0x0000 || codePoint > 0x10ffff) {
|
|
4566
|
-
return ["\uFFFD",
|
|
4570
|
+
return ["\uFFFD", consumed];
|
|
4567
4571
|
}
|
|
4568
|
-
return [String.fromCodePoint(codePoint),
|
|
4572
|
+
return [String.fromCodePoint(codePoint), consumed];
|
|
4569
4573
|
}
|
|
4570
4574
|
var CONTAINS_ESCAPE = /\\/;
|
|
4571
4575
|
function unesc(str) {
|
|
@@ -4576,7 +4580,7 @@ function requireUnesc$1 () {
|
|
|
4576
4580
|
var ret = "";
|
|
4577
4581
|
for (var i = 0; i < str.length; i++) {
|
|
4578
4582
|
if (str[i] === "\\") {
|
|
4579
|
-
var gobbled = gobbleHex(str.slice(i + 1, i +
|
|
4583
|
+
var gobbled = gobbleHex(str.slice(i + 1, i + 9));
|
|
4580
4584
|
if (gobbled !== undefined) {
|
|
4581
4585
|
ret += gobbled[0];
|
|
4582
4586
|
i += gobbled[1];
|
|
@@ -4953,29 +4957,29 @@ function requireNode$2 () {
|
|
|
4953
4957
|
return node$2;
|
|
4954
4958
|
}
|
|
4955
4959
|
|
|
4956
|
-
var types$
|
|
4960
|
+
var types$1 = {};
|
|
4957
4961
|
|
|
4958
4962
|
var hasRequiredTypes$1;
|
|
4959
4963
|
|
|
4960
4964
|
function requireTypes$1 () {
|
|
4961
|
-
if (hasRequiredTypes$1) return types$
|
|
4965
|
+
if (hasRequiredTypes$1) return types$1;
|
|
4962
4966
|
hasRequiredTypes$1 = 1;
|
|
4963
|
-
Object.defineProperty(types$
|
|
4964
|
-
types$
|
|
4965
|
-
types$
|
|
4966
|
-
types$
|
|
4967
|
-
types$
|
|
4968
|
-
types$
|
|
4969
|
-
types$
|
|
4970
|
-
types$
|
|
4971
|
-
types$
|
|
4972
|
-
types$
|
|
4973
|
-
types$
|
|
4974
|
-
types$
|
|
4975
|
-
types$
|
|
4976
|
-
types$
|
|
4967
|
+
Object.defineProperty(types$1, "__esModule", { value: true });
|
|
4968
|
+
types$1.UNIVERSAL = types$1.ATTRIBUTE = types$1.CLASS = types$1.COMBINATOR = types$1.COMMENT = types$1.ID = types$1.NESTING = types$1.PSEUDO = types$1.ROOT = types$1.SELECTOR = types$1.STRING = types$1.TAG = void 0;
|
|
4969
|
+
types$1.TAG = "tag";
|
|
4970
|
+
types$1.STRING = "string";
|
|
4971
|
+
types$1.SELECTOR = "selector";
|
|
4972
|
+
types$1.ROOT = "root";
|
|
4973
|
+
types$1.PSEUDO = "pseudo";
|
|
4974
|
+
types$1.NESTING = "nesting";
|
|
4975
|
+
types$1.ID = "id";
|
|
4976
|
+
types$1.COMMENT = "comment";
|
|
4977
|
+
types$1.COMBINATOR = "combinator";
|
|
4978
|
+
types$1.CLASS = "class";
|
|
4979
|
+
types$1.ATTRIBUTE = "attribute";
|
|
4980
|
+
types$1.UNIVERSAL = "universal";
|
|
4977
4981
|
|
|
4978
|
-
return types$
|
|
4982
|
+
return types$1;
|
|
4979
4983
|
}
|
|
4980
4984
|
|
|
4981
4985
|
var hasRequiredContainer$1;
|
|
@@ -5166,6 +5170,7 @@ function requireContainer$1 () {
|
|
|
5166
5170
|
var oldIndex = this.index(oldNode);
|
|
5167
5171
|
var resetNode = [];
|
|
5168
5172
|
for (var i = 2; i < arguments.length; i++) {
|
|
5173
|
+
arguments[i].parent = this;
|
|
5169
5174
|
resetNode.push(arguments[i]);
|
|
5170
5175
|
}
|
|
5171
5176
|
(_a = this.nodes).splice.apply(_a, __spreadArray([oldIndex + 1, 0, newNode], __read(resetNode), false));
|
|
@@ -5185,6 +5190,7 @@ function requireContainer$1 () {
|
|
|
5185
5190
|
var oldIndex = this.index(oldNode);
|
|
5186
5191
|
var resetNode = [];
|
|
5187
5192
|
for (var i = 2; i < arguments.length; i++) {
|
|
5193
|
+
arguments[i].parent = this;
|
|
5188
5194
|
resetNode.push(arguments[i]);
|
|
5189
5195
|
}
|
|
5190
5196
|
(_a = this.nodes).splice.apply(_a, __spreadArray([oldIndex, 0, newNode], __read(resetNode), false));
|
|
@@ -6578,8 +6584,22 @@ function requireCombinator$1 () {
|
|
|
6578
6584
|
function Combinator(opts) {
|
|
6579
6585
|
var _this = _super.call(this, opts) || this;
|
|
6580
6586
|
_this.type = types_1.COMBINATOR;
|
|
6587
|
+
_this._constructed = true;
|
|
6581
6588
|
return _this;
|
|
6582
6589
|
}
|
|
6590
|
+
Object.defineProperty(Combinator.prototype, "value", {
|
|
6591
|
+
get: function () {
|
|
6592
|
+
return this._value;
|
|
6593
|
+
},
|
|
6594
|
+
set: function (value) {
|
|
6595
|
+
if (this._constructed && this.raws) {
|
|
6596
|
+
delete this.raws.value;
|
|
6597
|
+
}
|
|
6598
|
+
this._value = value;
|
|
6599
|
+
},
|
|
6600
|
+
enumerable: false,
|
|
6601
|
+
configurable: true
|
|
6602
|
+
});
|
|
6583
6603
|
return Combinator;
|
|
6584
6604
|
}(node_1.default));
|
|
6585
6605
|
combinator$1.default = Combinator;
|
|
@@ -6646,7 +6666,7 @@ function requireSortAscending$1 () {
|
|
|
6646
6666
|
return sortAscending$1;
|
|
6647
6667
|
}
|
|
6648
6668
|
|
|
6649
|
-
var tokenize$
|
|
6669
|
+
var tokenize$2 = {};
|
|
6650
6670
|
|
|
6651
6671
|
var tokenTypes$1 = {};
|
|
6652
6672
|
|
|
@@ -6699,9 +6719,9 @@ function requireTokenTypes$1 () {
|
|
|
6699
6719
|
var hasRequiredTokenize$1;
|
|
6700
6720
|
|
|
6701
6721
|
function requireTokenize$1 () {
|
|
6702
|
-
if (hasRequiredTokenize$1) return tokenize$
|
|
6722
|
+
if (hasRequiredTokenize$1) return tokenize$2;
|
|
6703
6723
|
hasRequiredTokenize$1 = 1;
|
|
6704
|
-
var __createBinding = (tokenize$
|
|
6724
|
+
var __createBinding = (tokenize$2 && tokenize$2.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6705
6725
|
if (k2 === undefined) k2 = k;
|
|
6706
6726
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6707
6727
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
@@ -6712,12 +6732,12 @@ function requireTokenize$1 () {
|
|
|
6712
6732
|
if (k2 === undefined) k2 = k;
|
|
6713
6733
|
o[k2] = m[k];
|
|
6714
6734
|
}));
|
|
6715
|
-
var __setModuleDefault = (tokenize$
|
|
6735
|
+
var __setModuleDefault = (tokenize$2 && tokenize$2.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
6716
6736
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
6717
6737
|
}) : function(o, v) {
|
|
6718
6738
|
o["default"] = v;
|
|
6719
6739
|
});
|
|
6720
|
-
var __importStar = (tokenize$
|
|
6740
|
+
var __importStar = (tokenize$2 && tokenize$2.__importStar) || (function () {
|
|
6721
6741
|
var ownKeys = function(o) {
|
|
6722
6742
|
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
6723
6743
|
var ar = [];
|
|
@@ -6735,9 +6755,9 @@ function requireTokenize$1 () {
|
|
|
6735
6755
|
};
|
|
6736
6756
|
})();
|
|
6737
6757
|
var _a, _b;
|
|
6738
|
-
Object.defineProperty(tokenize$
|
|
6739
|
-
tokenize$
|
|
6740
|
-
tokenize$
|
|
6758
|
+
Object.defineProperty(tokenize$2, "__esModule", { value: true });
|
|
6759
|
+
tokenize$2.FIELDS = void 0;
|
|
6760
|
+
tokenize$2.default = tokenize;
|
|
6741
6761
|
var t = __importStar(/*@__PURE__*/ requireTokenTypes$1());
|
|
6742
6762
|
var unescapable = (_a = {},
|
|
6743
6763
|
_a[t.tab] = true,
|
|
@@ -6828,7 +6848,7 @@ function requireTokenize$1 () {
|
|
|
6828
6848
|
}
|
|
6829
6849
|
return next;
|
|
6830
6850
|
}
|
|
6831
|
-
tokenize$
|
|
6851
|
+
tokenize$2.FIELDS = {
|
|
6832
6852
|
TYPE: 0,
|
|
6833
6853
|
START_LINE: 1,
|
|
6834
6854
|
START_COL: 2,
|
|
@@ -6999,7 +7019,7 @@ function requireTokenize$1 () {
|
|
|
6999
7019
|
return tokens;
|
|
7000
7020
|
}
|
|
7001
7021
|
|
|
7002
|
-
return tokenize$
|
|
7022
|
+
return tokenize$2;
|
|
7003
7023
|
}
|
|
7004
7024
|
|
|
7005
7025
|
var hasRequiredParser$2;
|
|
@@ -7200,6 +7220,23 @@ function requireParser$2 () {
|
|
|
7200
7220
|
return _this.rule.error(message, errorOptions);
|
|
7201
7221
|
};
|
|
7202
7222
|
};
|
|
7223
|
+
Parser.prototype.namespaceSeparatorFollows = function (attr, pos) {
|
|
7224
|
+
var next = pos;
|
|
7225
|
+
while (attr[next] && attr[next][tokenize_1.FIELDS.TYPE] === tokens.space) {
|
|
7226
|
+
next++;
|
|
7227
|
+
}
|
|
7228
|
+
if (!attr[next] || this.content(attr[next]) !== "|") {
|
|
7229
|
+
return false;
|
|
7230
|
+
}
|
|
7231
|
+
next++;
|
|
7232
|
+
if (attr[next] && attr[next][tokenize_1.FIELDS.TYPE] === tokens.equals) {
|
|
7233
|
+
return false;
|
|
7234
|
+
}
|
|
7235
|
+
while (attr[next] && attr[next][tokenize_1.FIELDS.TYPE] === tokens.space) {
|
|
7236
|
+
next++;
|
|
7237
|
+
}
|
|
7238
|
+
return Boolean(attr[next]);
|
|
7239
|
+
};
|
|
7203
7240
|
Parser.prototype.attribute = function () {
|
|
7204
7241
|
var attr = [];
|
|
7205
7242
|
var startingToken = this.currToken;
|
|
@@ -7230,6 +7267,7 @@ function requireParser$2 () {
|
|
|
7230
7267
|
var commentBefore = "";
|
|
7231
7268
|
var lastAdded = null;
|
|
7232
7269
|
var spaceAfterMeaningfulToken = false;
|
|
7270
|
+
var namespaceSpaces = null;
|
|
7233
7271
|
while (pos < len) {
|
|
7234
7272
|
var token = attr[pos];
|
|
7235
7273
|
var content = this.content(token);
|
|
@@ -7246,6 +7284,15 @@ function requireParser$2 () {
|
|
|
7246
7284
|
if (this.options.lossy) {
|
|
7247
7285
|
break;
|
|
7248
7286
|
}
|
|
7287
|
+
if (namespaceSpaces !== null) {
|
|
7288
|
+
namespaceSpaces += content;
|
|
7289
|
+
break;
|
|
7290
|
+
}
|
|
7291
|
+
if (lastAdded === "namespace") {
|
|
7292
|
+
(0, util_1.ensureObject)(node, "raws");
|
|
7293
|
+
node.raws.namespace = (node.raws.namespace || node.namespace) + content;
|
|
7294
|
+
break;
|
|
7295
|
+
}
|
|
7249
7296
|
if (lastAdded) {
|
|
7250
7297
|
(0, util_1.ensureObject)(node, "spaces", lastAdded);
|
|
7251
7298
|
var prevContent = node.spaces[lastAdded].after || "";
|
|
@@ -7267,6 +7314,11 @@ function requireParser$2 () {
|
|
|
7267
7314
|
}
|
|
7268
7315
|
else if ((!node.namespace || (lastAdded === "namespace" && !spaceAfterMeaningfulToken)) &&
|
|
7269
7316
|
next) {
|
|
7317
|
+
node.namespace = (node.namespace || "") + content;
|
|
7318
|
+
var rawValue = (0, util_1.getProp)(node, "raws", "namespace") || null;
|
|
7319
|
+
if (rawValue) {
|
|
7320
|
+
node.raws.namespace += content;
|
|
7321
|
+
}
|
|
7270
7322
|
if (spaceBefore) {
|
|
7271
7323
|
(0, util_1.ensureObject)(node, "spaces", "attribute");
|
|
7272
7324
|
node.spaces.attribute.before = spaceBefore;
|
|
@@ -7277,11 +7329,6 @@ function requireParser$2 () {
|
|
|
7277
7329
|
node.raws.spaces.attribute.before = commentBefore;
|
|
7278
7330
|
commentBefore = "";
|
|
7279
7331
|
}
|
|
7280
|
-
node.namespace = (node.namespace || "") + content;
|
|
7281
|
-
var rawValue = (0, util_1.getProp)(node, "raws", "namespace") || null;
|
|
7282
|
-
if (rawValue) {
|
|
7283
|
-
node.raws.namespace += content;
|
|
7284
|
-
}
|
|
7285
7332
|
lastAdded = "namespace";
|
|
7286
7333
|
}
|
|
7287
7334
|
spaceAfterMeaningfulToken = false;
|
|
@@ -7316,18 +7363,16 @@ function requireParser$2 () {
|
|
|
7316
7363
|
node.operator = content;
|
|
7317
7364
|
lastAdded = "operator";
|
|
7318
7365
|
}
|
|
7319
|
-
else if (!node.
|
|
7320
|
-
node.namespace
|
|
7366
|
+
else if (!node.operator) {
|
|
7367
|
+
if (!node.namespace && !node.attribute) {
|
|
7368
|
+
node.namespace = true;
|
|
7369
|
+
}
|
|
7370
|
+
namespaceSpaces = "";
|
|
7321
7371
|
}
|
|
7322
7372
|
spaceAfterMeaningfulToken = false;
|
|
7323
7373
|
break;
|
|
7324
7374
|
case tokens.word:
|
|
7325
|
-
if (
|
|
7326
|
-
this.content(next) === "|" &&
|
|
7327
|
-
attr[pos + 2] &&
|
|
7328
|
-
attr[pos + 2][tokenize_1.FIELDS.TYPE] !== tokens.equals && // this look-ahead probably fails with comment nodes involved.
|
|
7329
|
-
!node.operator &&
|
|
7330
|
-
!node.namespace) {
|
|
7375
|
+
if (this.namespaceSeparatorFollows(attr, pos + 1) && !node.operator && !node.namespace) {
|
|
7331
7376
|
node.namespace = content;
|
|
7332
7377
|
lastAdded = "namespace";
|
|
7333
7378
|
}
|
|
@@ -7342,6 +7387,11 @@ function requireParser$2 () {
|
|
|
7342
7387
|
node.raws.spaces.attribute.before = commentBefore;
|
|
7343
7388
|
commentBefore = "";
|
|
7344
7389
|
}
|
|
7390
|
+
if (namespaceSpaces) {
|
|
7391
|
+
(0, util_1.ensureObject)(node, "raws");
|
|
7392
|
+
node.raws.attribute = namespaceSpaces + (node.raws.attribute || node.attribute || "");
|
|
7393
|
+
}
|
|
7394
|
+
namespaceSpaces = null;
|
|
7345
7395
|
node.attribute = (node.attribute || "") + content;
|
|
7346
7396
|
var rawValue = (0, util_1.getProp)(node, "raws", "attribute") || null;
|
|
7347
7397
|
if (rawValue) {
|
|
@@ -7651,7 +7701,34 @@ function requireParser$2 () {
|
|
|
7651
7701
|
}
|
|
7652
7702
|
return this.newNode(node);
|
|
7653
7703
|
};
|
|
7704
|
+
// Whitespace is only ever stored on a node, as `spaces.before` or
|
|
7705
|
+
// `spaces.after`. `space()` parks leading whitespace on `this.spaces` for the
|
|
7706
|
+
// next node to claim, so a selector that ends before any node is created --
|
|
7707
|
+
// `:not(a, )`, `:not( )`, a trailing `a, ` -- drops it. Park it on an empty
|
|
7708
|
+
// string node instead, which is what `parseWhitespaceEquivalentTokens`
|
|
7709
|
+
// already does for the comment-adjacent case.
|
|
7710
|
+
Parser.prototype.flushPendingSpaces = function () {
|
|
7711
|
+
if (!this.spaces) {
|
|
7712
|
+
return;
|
|
7713
|
+
}
|
|
7714
|
+
var last = this.current.last;
|
|
7715
|
+
if (last) {
|
|
7716
|
+
// `space()` routes trailing whitespace to `this.spaces` whenever the
|
|
7717
|
+
// selector so far holds nothing but comments, so `:not( /*c*/ )` lands
|
|
7718
|
+
// here rather than on the `spaces.after` path.
|
|
7719
|
+
last.spaces.after += this.spaces;
|
|
7720
|
+
this.spaces = "";
|
|
7721
|
+
return;
|
|
7722
|
+
}
|
|
7723
|
+
var token = this.currToken || this.prevToken;
|
|
7724
|
+
this.newNode(new string_1.default({
|
|
7725
|
+
value: "",
|
|
7726
|
+
source: token ? getTokenSource(token) : undefined,
|
|
7727
|
+
sourceIndex: token ? token[tokenize_1.FIELDS.START_POS] : 0,
|
|
7728
|
+
}));
|
|
7729
|
+
};
|
|
7654
7730
|
Parser.prototype.comma = function () {
|
|
7731
|
+
this.flushPendingSpaces();
|
|
7655
7732
|
if (this.position === this.tokens.length - 1) {
|
|
7656
7733
|
this.root.trailingComma = true;
|
|
7657
7734
|
this.position++;
|
|
@@ -7772,6 +7849,7 @@ function requireParser$2 () {
|
|
|
7772
7849
|
this.parse();
|
|
7773
7850
|
}
|
|
7774
7851
|
else {
|
|
7852
|
+
this.flushPendingSpaces();
|
|
7775
7853
|
this.current.source.end = tokenEnd(this.currToken);
|
|
7776
7854
|
this.current.parent.source.end = tokenEnd(this.currToken);
|
|
7777
7855
|
this.position++;
|
|
@@ -7981,6 +8059,7 @@ function requireParser$2 () {
|
|
|
7981
8059
|
while (this.position < this.tokens.length) {
|
|
7982
8060
|
this.parse(true);
|
|
7983
8061
|
}
|
|
8062
|
+
this.flushPendingSpaces();
|
|
7984
8063
|
this.current._inferEndPosition();
|
|
7985
8064
|
return this.root;
|
|
7986
8065
|
};
|
|
@@ -12232,7 +12311,7 @@ const processors = {
|
|
|
12232
12311
|
stylus: styl
|
|
12233
12312
|
};
|
|
12234
12313
|
|
|
12235
|
-
var build = {exports: {}};
|
|
12314
|
+
var build$1 = {exports: {}};
|
|
12236
12315
|
|
|
12237
12316
|
var fs = {};
|
|
12238
12317
|
|
|
@@ -14965,41 +15044,41 @@ function requireNode () {
|
|
|
14965
15044
|
return node.exports;
|
|
14966
15045
|
}
|
|
14967
15046
|
|
|
14968
|
-
var types
|
|
15047
|
+
var types = {};
|
|
14969
15048
|
|
|
14970
15049
|
var hasRequiredTypes;
|
|
14971
15050
|
|
|
14972
15051
|
function requireTypes () {
|
|
14973
|
-
if (hasRequiredTypes) return types
|
|
15052
|
+
if (hasRequiredTypes) return types;
|
|
14974
15053
|
hasRequiredTypes = 1;
|
|
14975
15054
|
|
|
14976
|
-
types
|
|
14977
|
-
types
|
|
15055
|
+
types.__esModule = true;
|
|
15056
|
+
types.UNIVERSAL = types.TAG = types.STRING = types.SELECTOR = types.ROOT = types.PSEUDO = types.NESTING = types.ID = types.COMMENT = types.COMBINATOR = types.CLASS = types.ATTRIBUTE = void 0;
|
|
14978
15057
|
var TAG = 'tag';
|
|
14979
|
-
types
|
|
15058
|
+
types.TAG = TAG;
|
|
14980
15059
|
var STRING = 'string';
|
|
14981
|
-
types
|
|
15060
|
+
types.STRING = STRING;
|
|
14982
15061
|
var SELECTOR = 'selector';
|
|
14983
|
-
types
|
|
15062
|
+
types.SELECTOR = SELECTOR;
|
|
14984
15063
|
var ROOT = 'root';
|
|
14985
|
-
types
|
|
15064
|
+
types.ROOT = ROOT;
|
|
14986
15065
|
var PSEUDO = 'pseudo';
|
|
14987
|
-
types
|
|
15066
|
+
types.PSEUDO = PSEUDO;
|
|
14988
15067
|
var NESTING = 'nesting';
|
|
14989
|
-
types
|
|
15068
|
+
types.NESTING = NESTING;
|
|
14990
15069
|
var ID = 'id';
|
|
14991
|
-
types
|
|
15070
|
+
types.ID = ID;
|
|
14992
15071
|
var COMMENT = 'comment';
|
|
14993
|
-
types
|
|
15072
|
+
types.COMMENT = COMMENT;
|
|
14994
15073
|
var COMBINATOR = 'combinator';
|
|
14995
|
-
types
|
|
15074
|
+
types.COMBINATOR = COMBINATOR;
|
|
14996
15075
|
var CLASS = 'class';
|
|
14997
|
-
types
|
|
15076
|
+
types.CLASS = CLASS;
|
|
14998
15077
|
var ATTRIBUTE = 'attribute';
|
|
14999
|
-
types
|
|
15078
|
+
types.ATTRIBUTE = ATTRIBUTE;
|
|
15000
15079
|
var UNIVERSAL = 'universal';
|
|
15001
|
-
types
|
|
15002
|
-
return types
|
|
15080
|
+
types.UNIVERSAL = UNIVERSAL;
|
|
15081
|
+
return types;
|
|
15003
15082
|
}
|
|
15004
15083
|
|
|
15005
15084
|
var hasRequiredContainer;
|
|
@@ -16302,7 +16381,7 @@ function requireSortAscending () {
|
|
|
16302
16381
|
return sortAscending.exports;
|
|
16303
16382
|
}
|
|
16304
16383
|
|
|
16305
|
-
var tokenize = {};
|
|
16384
|
+
var tokenize$1 = {};
|
|
16306
16385
|
|
|
16307
16386
|
var tokenTypes = {};
|
|
16308
16387
|
|
|
@@ -16386,7 +16465,7 @@ function requireTokenTypes () {
|
|
|
16386
16465
|
var hasRequiredTokenize;
|
|
16387
16466
|
|
|
16388
16467
|
function requireTokenize () {
|
|
16389
|
-
if (hasRequiredTokenize) return tokenize;
|
|
16468
|
+
if (hasRequiredTokenize) return tokenize$1;
|
|
16390
16469
|
hasRequiredTokenize = 1;
|
|
16391
16470
|
(function (exports) {
|
|
16392
16471
|
|
|
@@ -16625,8 +16704,8 @@ function requireTokenize () {
|
|
|
16625
16704
|
}
|
|
16626
16705
|
return tokens;
|
|
16627
16706
|
}
|
|
16628
|
-
} (tokenize));
|
|
16629
|
-
return tokenize;
|
|
16707
|
+
} (tokenize$1));
|
|
16708
|
+
return tokenize$1;
|
|
16630
16709
|
}
|
|
16631
16710
|
|
|
16632
16711
|
var hasRequiredParser;
|
|
@@ -20012,7 +20091,7 @@ function requirePluginFactory () {
|
|
|
20012
20091
|
var hasRequiredBuild;
|
|
20013
20092
|
|
|
20014
20093
|
function requireBuild () {
|
|
20015
|
-
if (hasRequiredBuild) return build.exports;
|
|
20094
|
+
if (hasRequiredBuild) return build$1.exports;
|
|
20016
20095
|
hasRequiredBuild = 1;
|
|
20017
20096
|
|
|
20018
20097
|
var _fs = require$$0;
|
|
@@ -20026,10 +20105,10 @@ function requireBuild () {
|
|
|
20026
20105
|
writeFile: _fs.writeFile
|
|
20027
20106
|
});
|
|
20028
20107
|
|
|
20029
|
-
build.exports = (opts = {}) => (0, _pluginFactory.makePlugin)(opts);
|
|
20108
|
+
build$1.exports = (opts = {}) => (0, _pluginFactory.makePlugin)(opts);
|
|
20030
20109
|
|
|
20031
|
-
build.exports.postcss = true;
|
|
20032
|
-
return build.exports;
|
|
20110
|
+
build$1.exports.postcss = true;
|
|
20111
|
+
return build$1.exports;
|
|
20033
20112
|
}
|
|
20034
20113
|
|
|
20035
20114
|
var buildExports = /*@__PURE__*/ requireBuild();
|
|
@@ -20209,10 +20288,10 @@ function toFileNameLowerCase(x) {
|
|
|
20209
20288
|
function createGetCanonicalFileName(useCaseSensitiveFileNames) {
|
|
20210
20289
|
return useCaseSensitiveFileNames ? identity : toFileNameLowerCase;
|
|
20211
20290
|
}
|
|
20212
|
-
const normalize = (path$1.posix || path$1).normalize;
|
|
20291
|
+
const normalize$1 = (path$1.posix || path$1).normalize;
|
|
20213
20292
|
const windowsSlashRE = /\\/g;
|
|
20214
20293
|
function normalizePath(p) {
|
|
20215
|
-
return normalize(p.replace(windowsSlashRE, "/"));
|
|
20294
|
+
return normalize$1(p.replace(windowsSlashRE, "/"));
|
|
20216
20295
|
}
|
|
20217
20296
|
const joinPaths = (path$1.posix || path$1).join;
|
|
20218
20297
|
const propNameEscapeSymbolsRE = /[ !"#$%&'()*+,./:;<=>?@[\\\]^`{|}~\-]/;
|
|
@@ -20291,7 +20370,7 @@ function getObjectOrArrayExpressionKeys(value) {
|
|
|
20291
20370
|
return [];
|
|
20292
20371
|
}
|
|
20293
20372
|
|
|
20294
|
-
var _a
|
|
20373
|
+
var _a, _b;
|
|
20295
20374
|
class ScriptCompileContext {
|
|
20296
20375
|
constructor(descriptor, options) {
|
|
20297
20376
|
this.descriptor = descriptor;
|
|
@@ -20300,7 +20379,7 @@ class ScriptCompileContext {
|
|
|
20300
20379
|
this.source = this.descriptor.source;
|
|
20301
20380
|
this.filename = this.descriptor.filename;
|
|
20302
20381
|
this.s = new MagicString(this.source);
|
|
20303
|
-
this.startOffset = (_a
|
|
20382
|
+
this.startOffset = (_a = this.descriptor.scriptSetup) == null ? void 0 : _a.loc.start.offset;
|
|
20304
20383
|
this.endOffset = (_b = this.descriptor.scriptSetup) == null ? void 0 : _b.loc.end.offset;
|
|
20305
20384
|
this.userImports = /* @__PURE__ */ Object.create(null);
|
|
20306
20385
|
// macros presence check
|
|
@@ -20620,6 +20699,24 @@ const EXPANSION_MAX = 100_000;
|
|
|
20620
20699
|
// realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M
|
|
20621
20700
|
// characters) so legitimate input is unaffected.
|
|
20622
20701
|
const EXPANSION_MAX_LENGTH = 4_000_000;
|
|
20702
|
+
// `expand_` recurses once per level of brace *nesting* - both when expanding a
|
|
20703
|
+
// set's comma members and when re-wrapping a set whose body is a single part.
|
|
20704
|
+
// The CVE-2026-14257 fix made the *tail* iterative (recursion on `m.post`, one
|
|
20705
|
+
// level per chained group), which left nesting depth unbounded: about 3,100
|
|
20706
|
+
// levels of `{{{...a,b...}}}` - only ~6KB of input - exhausted the native stack
|
|
20707
|
+
// and crashed the process. `EXPANSION_MAX_DEPTH` bounds how deep the parser
|
|
20708
|
+
// will follow nesting. It sits far above any realistic pattern and well below
|
|
20709
|
+
// the depth at which the stack runs out.
|
|
20710
|
+
const EXPANSION_MAX_DEPTH = 1_000;
|
|
20711
|
+
// Bash keeps a quirk where a brace group followed by a comma set still expands
|
|
20712
|
+
// (`{a},b}`). The parser implements it by rewriting the string and restarting
|
|
20713
|
+
// the scan, absorbing one `}` per pass. `n` trailing braces therefore cost `n`
|
|
20714
|
+
// full passes over a string that itself grows by one `escClose` sentinel each
|
|
20715
|
+
// time - quadratic in `n`, with a ~26x constant from the sentinel's length.
|
|
20716
|
+
// 128KB of `'{a}' + '}'.repeat(n) + ',z}'` blocked the event loop for 27
|
|
20717
|
+
// seconds to produce two results. `EXPANSION_MAX_REWRITES` bounds how many
|
|
20718
|
+
// times the scan may restart. Real `{a},b}` input needs a handful.
|
|
20719
|
+
const EXPANSION_MAX_REWRITES = 1_000;
|
|
20623
20720
|
function numeric(str) {
|
|
20624
20721
|
return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
|
|
20625
20722
|
}
|
|
@@ -20639,36 +20736,52 @@ function unescapeBraces(str) {
|
|
|
20639
20736
|
.replace(escCommaPattern, ',')
|
|
20640
20737
|
.replace(escPeriodPattern, '.');
|
|
20641
20738
|
}
|
|
20739
|
+
// Like `target.push(...items)` but doesn't overflow the stack
|
|
20740
|
+
function pushAll(target, items) {
|
|
20741
|
+
for (let i = 0; i < items.length; i++) {
|
|
20742
|
+
target.push(items[i]);
|
|
20743
|
+
}
|
|
20744
|
+
}
|
|
20642
20745
|
/**
|
|
20643
20746
|
* Basically just str.split(","), but handling cases
|
|
20644
20747
|
* where we have nested braced sections, which should be
|
|
20645
20748
|
* treated as individual members, like {a,{b,c},d}
|
|
20646
20749
|
*/
|
|
20647
20750
|
function parseCommaParts(str) {
|
|
20648
|
-
if (!str) {
|
|
20649
|
-
return [''];
|
|
20650
|
-
}
|
|
20651
20751
|
const parts = [];
|
|
20652
|
-
|
|
20653
|
-
|
|
20654
|
-
|
|
20655
|
-
|
|
20656
|
-
|
|
20657
|
-
|
|
20658
|
-
|
|
20659
|
-
|
|
20660
|
-
|
|
20661
|
-
|
|
20662
|
-
|
|
20752
|
+
// Walk the brace groups iteratively. Recursing on `post` once per group let a
|
|
20753
|
+
// chain of them exhaust the stack - the parsing-side counterpart to
|
|
20754
|
+
// the `expand_` overflow fixed for CVE-2026-14257, and not something `max` or
|
|
20755
|
+
// `maxLength` can bound, since it happens before expansion.
|
|
20756
|
+
//
|
|
20757
|
+
// The part the next chunk continues
|
|
20758
|
+
let carry = '';
|
|
20759
|
+
for (;;) {
|
|
20760
|
+
const m = balanced('{', '}', str);
|
|
20761
|
+
if (!m) {
|
|
20762
|
+
const tail = str.split(',');
|
|
20763
|
+
tail[0] = carry + tail[0];
|
|
20764
|
+
pushAll(parts, tail);
|
|
20765
|
+
return parts;
|
|
20766
|
+
}
|
|
20767
|
+
const { pre, body, post } = m;
|
|
20768
|
+
const p = pre.split(',');
|
|
20769
|
+
p[0] = carry + p[0];
|
|
20770
|
+
p[p.length - 1] += '{' + body + '}';
|
|
20771
|
+
if (!post.length) {
|
|
20772
|
+
pushAll(parts, p);
|
|
20773
|
+
return parts;
|
|
20774
|
+
}
|
|
20775
|
+
carry = p.pop();
|
|
20776
|
+
pushAll(parts, p);
|
|
20777
|
+
str = post;
|
|
20663
20778
|
}
|
|
20664
|
-
parts.push.apply(parts, p);
|
|
20665
|
-
return parts;
|
|
20666
20779
|
}
|
|
20667
20780
|
function expand(str, options = {}) {
|
|
20668
20781
|
if (!str) {
|
|
20669
20782
|
return [];
|
|
20670
20783
|
}
|
|
20671
|
-
const { max = EXPANSION_MAX, maxLength = EXPANSION_MAX_LENGTH } = options;
|
|
20784
|
+
const { max = EXPANSION_MAX, maxLength = EXPANSION_MAX_LENGTH, maxDepth = EXPANSION_MAX_DEPTH, maxRewrites = EXPANSION_MAX_REWRITES, } = options;
|
|
20672
20785
|
// I don't know why Bash 4.3 does this, but it does.
|
|
20673
20786
|
// Anything starting with {} will have the first two bytes preserved
|
|
20674
20787
|
// but *only* at the top level, so {},a}b will not expand to anything,
|
|
@@ -20678,7 +20791,7 @@ function expand(str, options = {}) {
|
|
|
20678
20791
|
if (str.slice(0, 2) === '{}') {
|
|
20679
20792
|
str = '\\{\\}' + str.slice(2);
|
|
20680
20793
|
}
|
|
20681
|
-
return expand_(escapeBraces(str), max, maxLength, true).map(unescapeBraces);
|
|
20794
|
+
return expand_(escapeBraces(str), max, maxLength, maxDepth, 0, maxRewrites, true).map(unescapeBraces);
|
|
20682
20795
|
}
|
|
20683
20796
|
function embrace(str) {
|
|
20684
20797
|
return '{' + str + '}';
|
|
@@ -20773,7 +20886,13 @@ function expandSequence(body, isAlphaSequence, max, maxLength) {
|
|
|
20773
20886
|
}
|
|
20774
20887
|
return N;
|
|
20775
20888
|
}
|
|
20776
|
-
function expand_(str, max, maxLength, isTop) {
|
|
20889
|
+
function expand_(str, max, maxLength, maxDepth, depth, maxRewrites, isTop) {
|
|
20890
|
+
// Too deeply nested to keep following: treat the rest as literal, the same
|
|
20891
|
+
// way a group that cannot expand is already handled. Truncating rather than
|
|
20892
|
+
// throwing keeps `expand` total, matching `max` and `maxLength`.
|
|
20893
|
+
if (depth > maxDepth) {
|
|
20894
|
+
return [str];
|
|
20895
|
+
}
|
|
20777
20896
|
// Consume the string's top-level brace groups left to right, threading a
|
|
20778
20897
|
// running set of combined prefixes (`acc`). Expanding the tail iteratively -
|
|
20779
20898
|
// rather than recursing on `m.post` once per group - keeps the native stack
|
|
@@ -20785,6 +20904,9 @@ function expand_(str, max, maxLength, isTop) {
|
|
|
20785
20904
|
// comma set - a sequence like `{a..\}` may legitimately yield ''. The drop
|
|
20786
20905
|
// is on the final strings, so it is applied to whichever `combine` produces
|
|
20787
20906
|
// them (the one with no brace set left in the tail).
|
|
20907
|
+
// How many times the `{a},b}` rewrite below has restarted the scan. Each pass
|
|
20908
|
+
// re-reads the whole string, so leaving this unbounded is quadratic.
|
|
20909
|
+
let rewrites = 0;
|
|
20788
20910
|
let dropEmpties = false;
|
|
20789
20911
|
let firstGroup = true;
|
|
20790
20912
|
for (;;) {
|
|
@@ -20809,7 +20931,8 @@ function expand_(str, max, maxLength, isTop) {
|
|
|
20809
20931
|
const isOptions = m.body.indexOf(',') >= 0;
|
|
20810
20932
|
if (!isSequence && !isOptions) {
|
|
20811
20933
|
// {a},b}
|
|
20812
|
-
if (m.post.match(/,(?!,).*\}/)) {
|
|
20934
|
+
if (rewrites < maxRewrites && m.post.match(/,(?!,).*\}/)) {
|
|
20935
|
+
rewrites++;
|
|
20813
20936
|
str = m.pre + '{' + m.body + escClose + m.post;
|
|
20814
20937
|
isTop = true;
|
|
20815
20938
|
continue;
|
|
@@ -20829,7 +20952,7 @@ function expand_(str, max, maxLength, isTop) {
|
|
|
20829
20952
|
let n = parseCommaParts(m.body);
|
|
20830
20953
|
if (n.length === 1 && n[0] !== undefined) {
|
|
20831
20954
|
// x{{a,b}}y ==> x{a}y x{b}y
|
|
20832
|
-
n = expand_(n[0], max, maxLength, false).map(embrace);
|
|
20955
|
+
n = expand_(n[0], max, maxLength, maxDepth, depth + 1, maxRewrites, false).map(embrace);
|
|
20833
20956
|
//XXX is this necessary? Can't seem to hit it in tests.
|
|
20834
20957
|
/* c8 ignore start */
|
|
20835
20958
|
if (n.length === 1) {
|
|
@@ -20855,12 +20978,13 @@ function expand_(str, max, maxLength, isTop) {
|
|
|
20855
20978
|
values = [];
|
|
20856
20979
|
let valuesLength = 0;
|
|
20857
20980
|
outer: for (let j = 0; j < n.length; j++) {
|
|
20858
|
-
const expanded = expand_(n[j], max, maxLength, false);
|
|
20981
|
+
const expanded = expand_(n[j], max, maxLength, maxDepth, depth + 1, maxRewrites, false);
|
|
20859
20982
|
for (let k = 0; k < expanded.length; k++) {
|
|
20860
20983
|
const v = expanded[k];
|
|
20861
20984
|
if (dropsEmpties && !v)
|
|
20862
20985
|
continue;
|
|
20863
|
-
if (values.length >= max ||
|
|
20986
|
+
if (values.length >= max ||
|
|
20987
|
+
valuesLength + v.length > maxLength) {
|
|
20864
20988
|
break outer;
|
|
20865
20989
|
}
|
|
20866
20990
|
values.push(v);
|
|
@@ -20876,49 +21000,42 @@ function expand_(str, max, maxLength, isTop) {
|
|
|
20876
21000
|
return acc;
|
|
20877
21001
|
}
|
|
20878
21002
|
|
|
20879
|
-
const MAX_PATTERN_LENGTH = 1024 * 64;
|
|
20880
|
-
const assertValidPattern = (pattern) => {
|
|
20881
|
-
if (typeof pattern !== 'string') {
|
|
20882
|
-
throw new TypeError('invalid pattern');
|
|
20883
|
-
}
|
|
20884
|
-
if (pattern.length > MAX_PATTERN_LENGTH) {
|
|
20885
|
-
throw new TypeError('pattern is too long');
|
|
20886
|
-
}
|
|
20887
|
-
};
|
|
20888
|
-
|
|
20889
21003
|
// translate the various posix character classes into unicode properties
|
|
20890
21004
|
// this works across all unicode locales
|
|
20891
|
-
// { <posix class>: [<translation>,
|
|
21005
|
+
// { <posix class>: [<translation>, negated]
|
|
20892
21006
|
const posixClasses = {
|
|
20893
|
-
'[:alnum:]': ['\\p{L}\\p{Nl}\\p{Nd}'
|
|
20894
|
-
'[:alpha:]': ['\\p{L}\\p{Nl}'
|
|
20895
|
-
'[:ascii:]': ['\\x' + '00-\\x' + '7f'
|
|
20896
|
-
'[:blank:]': ['\\p{Zs}\\t'
|
|
20897
|
-
'[:cntrl:]': ['\\p{Cc}'
|
|
20898
|
-
'[:digit:]': ['\\p{Nd}'
|
|
20899
|
-
'[:graph:]': ['\\p{Z}\\p{C}', true
|
|
20900
|
-
'[:lower:]': ['\\p{Ll}'
|
|
21007
|
+
'[:alnum:]': ['\\p{L}\\p{Nl}\\p{Nd}'],
|
|
21008
|
+
'[:alpha:]': ['\\p{L}\\p{Nl}'],
|
|
21009
|
+
'[:ascii:]': ['\\x' + '00-\\x' + '7f'],
|
|
21010
|
+
'[:blank:]': ['\\p{Zs}\\t'],
|
|
21011
|
+
'[:cntrl:]': ['\\p{Cc}'],
|
|
21012
|
+
'[:digit:]': ['\\p{Nd}'],
|
|
21013
|
+
'[:graph:]': ['\\p{Z}\\p{C}', true],
|
|
21014
|
+
'[:lower:]': ['\\p{Ll}'],
|
|
20901
21015
|
'[:print:]': ['\\p{C}', true],
|
|
20902
|
-
'[:punct:]': ['\\p{P}'
|
|
20903
|
-
'[:space:]': ['\\p{Z}\\t\\r\\n\\v\\f'
|
|
20904
|
-
'[:upper:]': ['\\p{Lu}'
|
|
20905
|
-
'[:word:]': ['\\p{L}\\p{Nl}\\p{Nd}\\p{Pc}'
|
|
20906
|
-
'[:xdigit:]': ['A-Fa-f0-9'
|
|
21016
|
+
'[:punct:]': ['\\p{P}\\p{S}'],
|
|
21017
|
+
'[:space:]': ['\\p{Z}\\t\\r\\n\\v\\f'],
|
|
21018
|
+
'[:upper:]': ['\\p{Lu}'],
|
|
21019
|
+
'[:word:]': ['\\p{L}\\p{Nl}\\p{Nd}\\p{Pc}'],
|
|
21020
|
+
'[:xdigit:]': ['A-Fa-f0-9'],
|
|
20907
21021
|
};
|
|
20908
21022
|
// only need to escape a few things inside of brace expressions
|
|
20909
21023
|
// escapes: [ \ ] -
|
|
20910
21024
|
const braceEscape = (s) => s.replace(/[[\]\\-]/g, '\\$&');
|
|
20911
|
-
|
|
20912
|
-
|
|
20913
|
-
//
|
|
20914
|
-
|
|
20915
|
-
//
|
|
20916
|
-
//
|
|
20917
|
-
//
|
|
20918
|
-
//
|
|
20919
|
-
|
|
20920
|
-
//
|
|
20921
|
-
const
|
|
21025
|
+
const noMatch = /$./;
|
|
21026
|
+
// Takes a glob string at a posix brace expression. Returns a RegExp
|
|
21027
|
+
// that tests one character, and the number of glob chars consumed.
|
|
21028
|
+
// If the class is not closed, consumed is 0, and the `[` must be
|
|
21029
|
+
// treated as a literal character.
|
|
21030
|
+
// Out of order ranges are removed. If nothing is left, the RegExp
|
|
21031
|
+
// is `/$./`, and the rest of the glob is consumed, so that the
|
|
21032
|
+
// whole glob cannot match.
|
|
21033
|
+
const parseClass = (glob, position, nocase = false, form) => {
|
|
21034
|
+
// normalize one class member, if it stays one code point
|
|
21035
|
+
const norm = (c) => {
|
|
21036
|
+
const n = form ? c.normalize(form) : c;
|
|
21037
|
+
return [...n].length === 1 ? n : c;
|
|
21038
|
+
};
|
|
20922
21039
|
const pos = position;
|
|
20923
21040
|
/* c8 ignore start */
|
|
20924
21041
|
if (glob.charAt(pos) !== '[') {
|
|
@@ -20929,13 +21046,12 @@ const parseClass = (glob, position) => {
|
|
|
20929
21046
|
const negs = [];
|
|
20930
21047
|
let i = pos + 1;
|
|
20931
21048
|
let sawStart = false;
|
|
20932
|
-
let uflag = false;
|
|
20933
21049
|
let escaping = false;
|
|
20934
21050
|
let negate = false;
|
|
20935
21051
|
let endPos = pos;
|
|
20936
21052
|
let rangeStart = '';
|
|
20937
21053
|
WHILE: while (i < glob.length) {
|
|
20938
|
-
const c = glob.
|
|
21054
|
+
const c = String.fromCodePoint(glob.codePointAt(i));
|
|
20939
21055
|
if ((c === '!' || c === '^') && i === pos + 1) {
|
|
20940
21056
|
negate = true;
|
|
20941
21057
|
i++;
|
|
@@ -20956,954 +21072,838 @@ const parseClass = (glob, position) => {
|
|
|
20956
21072
|
}
|
|
20957
21073
|
if (c === '[' && !escaping) {
|
|
20958
21074
|
// either a posix class, a collation equivalent, or just a [
|
|
20959
|
-
for (const [cls, [unip,
|
|
21075
|
+
for (const [cls, [unip, neg]] of Object.entries(posixClasses)) {
|
|
20960
21076
|
if (glob.startsWith(cls, i)) {
|
|
20961
21077
|
// invalid, [a-[] is fine, but not [a-[:alpha]]
|
|
20962
21078
|
if (rangeStart) {
|
|
20963
|
-
return [
|
|
21079
|
+
return [noMatch, glob.length - pos];
|
|
20964
21080
|
}
|
|
20965
21081
|
i += cls.length;
|
|
20966
21082
|
if (neg)
|
|
20967
21083
|
negs.push(unip);
|
|
20968
21084
|
else
|
|
20969
21085
|
ranges.push(unip);
|
|
20970
|
-
uflag = uflag || u;
|
|
20971
21086
|
continue WHILE;
|
|
20972
21087
|
}
|
|
20973
21088
|
}
|
|
20974
21089
|
}
|
|
20975
21090
|
// now it's just a normal character, effectively
|
|
20976
21091
|
escaping = false;
|
|
21092
|
+
const n = norm(c);
|
|
20977
21093
|
if (rangeStart) {
|
|
20978
21094
|
// throw this range away if it's not valid, but others
|
|
20979
21095
|
// can still match.
|
|
20980
|
-
if (
|
|
20981
|
-
ranges.push(braceEscape(rangeStart) + '-' + braceEscape(
|
|
21096
|
+
if (n.codePointAt(0) > rangeStart.codePointAt(0)) {
|
|
21097
|
+
ranges.push(braceEscape(rangeStart) + '-' + braceEscape(n));
|
|
20982
21098
|
}
|
|
20983
|
-
else if (
|
|
20984
|
-
ranges.push(braceEscape(
|
|
21099
|
+
else if (n === rangeStart) {
|
|
21100
|
+
ranges.push(braceEscape(n));
|
|
20985
21101
|
}
|
|
20986
21102
|
rangeStart = '';
|
|
20987
|
-
i
|
|
21103
|
+
i += c.length;
|
|
20988
21104
|
continue;
|
|
20989
21105
|
}
|
|
20990
21106
|
// now might be the start of a range.
|
|
20991
21107
|
// can be either c-d or c-] or c<more...>] or c] at this point
|
|
20992
|
-
if (glob.startsWith('-]', i +
|
|
20993
|
-
ranges.push(braceEscape(
|
|
20994
|
-
i +=
|
|
21108
|
+
if (glob.startsWith('-]', i + c.length)) {
|
|
21109
|
+
ranges.push(braceEscape(n + '-'));
|
|
21110
|
+
i += c.length + 1;
|
|
20995
21111
|
continue;
|
|
20996
21112
|
}
|
|
20997
|
-
if (glob.startsWith('-', i +
|
|
20998
|
-
rangeStart =
|
|
20999
|
-
i +=
|
|
21113
|
+
if (glob.startsWith('-', i + c.length)) {
|
|
21114
|
+
rangeStart = n;
|
|
21115
|
+
i += c.length + 1;
|
|
21000
21116
|
continue;
|
|
21001
21117
|
}
|
|
21002
21118
|
// not the start of a range, just a single character
|
|
21003
|
-
ranges.push(braceEscape(
|
|
21004
|
-
i
|
|
21119
|
+
ranges.push(braceEscape(n));
|
|
21120
|
+
i += c.length;
|
|
21005
21121
|
}
|
|
21006
21122
|
if (endPos < i) {
|
|
21007
21123
|
// didn't see the end of the class, not a valid class,
|
|
21008
21124
|
// but might still be valid as a literal match.
|
|
21009
|
-
return [
|
|
21125
|
+
return [noMatch, 0];
|
|
21010
21126
|
}
|
|
21011
21127
|
// if we got no ranges and no negates, then we have a range that
|
|
21012
21128
|
// cannot possibly match anything, and that poisons the whole glob
|
|
21013
21129
|
if (!ranges.length && !negs.length) {
|
|
21014
|
-
return [
|
|
21015
|
-
}
|
|
21016
|
-
|
|
21017
|
-
|
|
21018
|
-
|
|
21019
|
-
|
|
21020
|
-
|
|
21021
|
-
|
|
21022
|
-
|
|
21023
|
-
!negate) {
|
|
21024
|
-
const r = ranges[0].length === 2 ? ranges[0].slice(-1) : ranges[0];
|
|
21025
|
-
return [regexpEscape(r), false, endPos - pos, false];
|
|
21026
|
-
}
|
|
21027
|
-
const sranges = '[' + (negate ? '^' : '') + rangesToString(ranges) + ']';
|
|
21028
|
-
const snegs = '[' + (negate ? '' : '^') + rangesToString(negs) + ']';
|
|
21029
|
-
const comb = ranges.length && negs.length ? '(' + sranges + '|' + snegs + ')'
|
|
21030
|
-
: ranges.length ? sranges
|
|
21031
|
-
: snegs;
|
|
21032
|
-
return [comb, uflag, endPos - pos, true];
|
|
21130
|
+
return [noMatch, glob.length - pos];
|
|
21131
|
+
}
|
|
21132
|
+
const sranges = '[' + (negate ? '^' : '') + ranges.join('') + ']';
|
|
21133
|
+
const snegs = '[' + (negate ? '' : '^') + negs.join('') + ']';
|
|
21134
|
+
const comb = '^' +
|
|
21135
|
+
(ranges.length && negs.length ? '(' + sranges + '|' + snegs + ')'
|
|
21136
|
+
: ranges.length ? sranges
|
|
21137
|
+
: snegs);
|
|
21138
|
+
return [new RegExp(comb, nocase ? 'iu' : 'u'), endPos - pos];
|
|
21033
21139
|
};
|
|
21034
21140
|
|
|
21035
|
-
|
|
21036
|
-
|
|
21037
|
-
|
|
21038
|
-
|
|
21039
|
-
|
|
21040
|
-
|
|
21041
|
-
|
|
21042
|
-
|
|
21043
|
-
|
|
21044
|
-
|
|
21045
|
-
|
|
21046
|
-
|
|
21047
|
-
|
|
21048
|
-
|
|
21049
|
-
|
|
21050
|
-
|
|
21051
|
-
|
|
21052
|
-
|
|
21053
|
-
|
|
21054
|
-
|
|
21055
|
-
if (magicalBraces) {
|
|
21056
|
-
return windowsPathsNoEscape ?
|
|
21057
|
-
s.replace(/\[([^/\\])\]/g, '$1')
|
|
21058
|
-
: s
|
|
21059
|
-
.replace(/((?!\\).|^)\[([^/\\])\]/g, '$1$2')
|
|
21060
|
-
.replace(/\\([^/])/g, '$1');
|
|
21061
|
-
}
|
|
21062
|
-
return windowsPathsNoEscape ?
|
|
21063
|
-
s.replace(/\[([^/\\{}])\]/g, '$1')
|
|
21064
|
-
: s
|
|
21065
|
-
.replace(/((?!\\).|^)\[([^/\\{}])\]/g, '$1$2')
|
|
21066
|
-
.replace(/\\([^/{}])/g, '$1');
|
|
21141
|
+
// the end of the pattern, or of a negated sub-pattern
|
|
21142
|
+
const MATCH = { t: 'match', id: 0 };
|
|
21143
|
+
const extTypes = '!?+*@';
|
|
21144
|
+
const lit = (ch) => ({ t: 'lit', ch });
|
|
21145
|
+
const reEscape = (s) => s.replace(/[\\^$.*+?()[\]{}|/]/g, '\\$&');
|
|
21146
|
+
// a RegExp that only matches `s`, with unicode case folding
|
|
21147
|
+
const newFoldRe = (s) => new RegExp(`^${reEscape(s)}$`, 'iu');
|
|
21148
|
+
// foldRe for one literal char. The same chars are in most patterns,
|
|
21149
|
+
// so keep them. A RegExp without the `g` or `y` flag has no state to
|
|
21150
|
+
// share.
|
|
21151
|
+
const foldCache = new Map();
|
|
21152
|
+
const foldRe = (ch) => {
|
|
21153
|
+
let re = foldCache.get(ch);
|
|
21154
|
+
if (!re) {
|
|
21155
|
+
re = newFoldRe(ch);
|
|
21156
|
+
if (foldCache.size >= 1000)
|
|
21157
|
+
foldCache.clear();
|
|
21158
|
+
foldCache.set(ch, re);
|
|
21159
|
+
}
|
|
21160
|
+
return re;
|
|
21067
21161
|
};
|
|
21068
|
-
|
|
21069
|
-
|
|
21070
|
-
|
|
21071
|
-
|
|
21072
|
-
|
|
21073
|
-
const
|
|
21074
|
-
|
|
21075
|
-
|
|
21076
|
-
|
|
21077
|
-
|
|
21078
|
-
|
|
21079
|
-
|
|
21080
|
-
|
|
21081
|
-
|
|
21082
|
-
|
|
21083
|
-
|
|
21084
|
-
|
|
21085
|
-
//
|
|
21086
|
-
|
|
21087
|
-
|
|
21088
|
-
|
|
21089
|
-
|
|
21090
|
-
|
|
21091
|
-
// +(a|*(b|c)|d) => would match "", on *(b|c)
|
|
21092
|
-
// @(a|*(b|c)|d) => would match "", on *(b|c)
|
|
21093
|
-
//
|
|
21094
|
-
// + and @ CANNOT adopt ?, because 0 would be allowed
|
|
21095
|
-
// +(a|?(b|c)|d) => would match "", on ?(b|c)
|
|
21096
|
-
// @(a|?(b|c)|d) => would match "", on ?(b|c)
|
|
21097
|
-
//
|
|
21098
|
-
// ? can adopt @, because 0 or 1 is allowed
|
|
21099
|
-
// ?(a|@(b|c)|d) => ?(a|b|c|d)
|
|
21100
|
-
//
|
|
21101
|
-
// ? and @ CANNOT adopt * or +, because >1 would be allowed
|
|
21102
|
-
// ?(a|*(b|c)|d) => would match bbb on *(b|c)
|
|
21103
|
-
// @(a|*(b|c)|d) => would match bbb on *(b|c)
|
|
21104
|
-
// ?(a|+(b|c)|d) => would match bbb on +(b|c)
|
|
21105
|
-
// @(a|+(b|c)|d) => would match bbb on +(b|c)
|
|
21106
|
-
//
|
|
21107
|
-
// ! CANNOT adopt ! (nothing else can either)
|
|
21108
|
-
// !(a|!(b|c)|d) => !(a|b|c|d) would fail to match on b (not not b|c)
|
|
21109
|
-
//
|
|
21110
|
-
// ! can adopt @
|
|
21111
|
-
// !(a|@(b|c)|d) => !(a|b|c|d)
|
|
21112
|
-
//
|
|
21113
|
-
// ! CANNOT adopt *
|
|
21114
|
-
// !(a|*(b|c)|d) => !(a|b|c|d) would match on bbb, not allowed
|
|
21115
|
-
//
|
|
21116
|
-
// ! CANNOT adopt +
|
|
21117
|
-
// !(a|+(b|c)|d) => !(a|b|c|d) would match on bbb, not allowed
|
|
21118
|
-
//
|
|
21119
|
-
// ! CANNOT adopt ?
|
|
21120
|
-
// x!(a|?(b|c)|d) => x!(a|b|c|d) would fail to match "x"
|
|
21121
|
-
const adoptionMap = new Map([
|
|
21122
|
-
['!', ['@']],
|
|
21123
|
-
['?', ['?', '@']],
|
|
21124
|
-
['@', ['@']],
|
|
21125
|
-
['*', ['*', '+', '?', '@']],
|
|
21126
|
-
['+', ['+', '@']],
|
|
21127
|
-
]);
|
|
21128
|
-
// nested extglobs that can be adopted in, but with the addition of
|
|
21129
|
-
// a blank '' element.
|
|
21130
|
-
const adoptionWithSpaceMap = new Map([
|
|
21131
|
-
['!', ['?']],
|
|
21132
|
-
['@', ['?']],
|
|
21133
|
-
['+', ['?', '*']],
|
|
21134
|
-
]);
|
|
21135
|
-
// union of the previous two maps
|
|
21136
|
-
const adoptionAnyMap = new Map([
|
|
21137
|
-
['!', ['?', '@']],
|
|
21138
|
-
['?', ['?', '@']],
|
|
21139
|
-
['@', ['?', '@']],
|
|
21140
|
-
['*', ['*', '+', '?', '@']],
|
|
21141
|
-
['+', ['+', '@', '?', '*']],
|
|
21142
|
-
]);
|
|
21143
|
-
// Extglobs that can take over their parent if they are the only child
|
|
21144
|
-
// the key is parent, value maps child to resulting extglob parent type
|
|
21145
|
-
// '@' is omitted because it's a special case. An `@` extglob with a single
|
|
21146
|
-
// member can always be usurped by that subpattern.
|
|
21147
|
-
const usurpMap = new Map([
|
|
21148
|
-
['!', new Map([['!', '@']])],
|
|
21149
|
-
[
|
|
21150
|
-
'?',
|
|
21151
|
-
new Map([
|
|
21152
|
-
['*', '*'],
|
|
21153
|
-
['+', '*'],
|
|
21154
|
-
]),
|
|
21155
|
-
],
|
|
21156
|
-
[
|
|
21157
|
-
'@',
|
|
21158
|
-
new Map([
|
|
21159
|
-
['!', '!'],
|
|
21160
|
-
['?', '?'],
|
|
21161
|
-
['@', '@'],
|
|
21162
|
-
['*', '*'],
|
|
21163
|
-
['+', '+'],
|
|
21164
|
-
]),
|
|
21165
|
-
],
|
|
21166
|
-
[
|
|
21167
|
-
'+',
|
|
21168
|
-
new Map([
|
|
21169
|
-
['?', '*'],
|
|
21170
|
-
['*', '*'],
|
|
21171
|
-
]),
|
|
21172
|
-
],
|
|
21173
|
-
]);
|
|
21174
|
-
// Patterns that get prepended to bind to the start of either the
|
|
21175
|
-
// entire string, or just a single path portion, to prevent dots
|
|
21176
|
-
// and/or traversal patterns, when needed.
|
|
21177
|
-
// Exts don't need the ^ or / bit, because the root binds that already.
|
|
21178
|
-
const startNoTraversal = '(?!(?:^|/)\\.\\.?(?:$|/))';
|
|
21179
|
-
const startNoDot = '(?!\\.)';
|
|
21180
|
-
// characters that indicate a start of pattern needs the "no dots" bit,
|
|
21181
|
-
// because a dot *might* be matched. ( is not in the list, because in
|
|
21182
|
-
// the case of a child extglob, it will handle the prevention itself.
|
|
21183
|
-
const addPatternStart = new Set(['[', '.']);
|
|
21184
|
-
// cases where traversal is A-OK, no dot prevention needed
|
|
21185
|
-
const justDots = new Set(['..', '.']);
|
|
21186
|
-
const reSpecials = new Set('().*{}+?[]^$\\!');
|
|
21187
|
-
const regExpEscape$1 = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
|
21188
|
-
// any single thing other than /
|
|
21189
|
-
const qmark$1 = '[^/]';
|
|
21190
|
-
// * => any number of characters
|
|
21191
|
-
const star$1 = qmark$1 + '*?';
|
|
21192
|
-
// use + when we need to ensure that *something* matches, because the * is
|
|
21193
|
-
// the only thing in the path portion.
|
|
21194
|
-
const starNoEmpty = qmark$1 + '+?';
|
|
21195
|
-
// remove the \ chars that we added if we end up doing a nonmagic compare
|
|
21196
|
-
// const deslash = (s: string) => s.replace(/\\(.)/g, '$1')
|
|
21197
|
-
let ID = 0;
|
|
21198
|
-
class AST {
|
|
21199
|
-
type;
|
|
21200
|
-
#root;
|
|
21201
|
-
#hasMagic;
|
|
21202
|
-
#uflag = false;
|
|
21203
|
-
#parts = [];
|
|
21204
|
-
#parent;
|
|
21205
|
-
#parentIndex;
|
|
21206
|
-
#negs;
|
|
21207
|
-
#filledNegs = false;
|
|
21208
|
-
#options;
|
|
21209
|
-
#toString;
|
|
21210
|
-
// set to true if it's an extglob with no children
|
|
21211
|
-
// (which really means one child of '')
|
|
21212
|
-
#emptyExt = false;
|
|
21213
|
-
id = ++ID;
|
|
21214
|
-
get depth() {
|
|
21215
|
-
return (this.#parent?.depth ?? -1) + 1;
|
|
21216
|
-
}
|
|
21217
|
-
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
21218
|
-
return {
|
|
21219
|
-
'@@type': 'AST',
|
|
21220
|
-
id: this.id,
|
|
21221
|
-
type: this.type,
|
|
21222
|
-
root: this.#root.id,
|
|
21223
|
-
parent: this.#parent?.id,
|
|
21224
|
-
depth: this.depth,
|
|
21225
|
-
partsLength: this.#parts.length,
|
|
21226
|
-
parts: this.#parts,
|
|
21227
|
-
};
|
|
21228
|
-
}
|
|
21229
|
-
constructor(type, parent, options = {}) {
|
|
21230
|
-
this.type = type;
|
|
21231
|
-
// extglobs are inherently magical
|
|
21232
|
-
if (type)
|
|
21233
|
-
this.#hasMagic = true;
|
|
21234
|
-
this.#parent = parent;
|
|
21235
|
-
this.#root = this.#parent ? this.#parent.#root : this;
|
|
21236
|
-
this.#options = this.#root === this ? options : this.#root.#options;
|
|
21237
|
-
this.#negs = this.#root === this ? [] : this.#root.#negs;
|
|
21238
|
-
if (type === '!' && !this.#root.#filledNegs)
|
|
21239
|
-
this.#negs.push(this);
|
|
21240
|
-
this.#parentIndex = this.#parent ? this.#parent.#parts.length : 0;
|
|
21241
|
-
}
|
|
21242
|
-
get hasMagic() {
|
|
21243
|
-
/* c8 ignore start */
|
|
21244
|
-
if (this.#hasMagic !== undefined)
|
|
21245
|
-
return this.#hasMagic;
|
|
21246
|
-
/* c8 ignore stop */
|
|
21247
|
-
for (const p of this.#parts) {
|
|
21248
|
-
if (typeof p === 'string')
|
|
21249
|
-
continue;
|
|
21250
|
-
if (p.type || p.hasMagic)
|
|
21251
|
-
return (this.#hasMagic = true);
|
|
21162
|
+
const litMatch = (l, c) => {
|
|
21163
|
+
if (c === l.ch)
|
|
21164
|
+
return true;
|
|
21165
|
+
if (!l.re)
|
|
21166
|
+
return false;
|
|
21167
|
+
const code = c.charCodeAt(0);
|
|
21168
|
+
if (code >= 128)
|
|
21169
|
+
return l.re.test(c);
|
|
21170
|
+
const ascii = (l.ascii ??= new Uint8Array(128));
|
|
21171
|
+
ascii[code] ||= l.re.test(c) ? 1 : 2;
|
|
21172
|
+
return ascii[code] === 1;
|
|
21173
|
+
};
|
|
21174
|
+
const tokenize = (p, nocase, noext, form) => {
|
|
21175
|
+
const toks = [];
|
|
21176
|
+
for (let i = 0; i < p.length;) {
|
|
21177
|
+
const c = String.fromCodePoint(p.codePointAt(i));
|
|
21178
|
+
if (c === '\\') {
|
|
21179
|
+
// a trailing \ is a literal \
|
|
21180
|
+
const e = p.codePointAt(i + 1);
|
|
21181
|
+
const ch = e === undefined ? c : String.fromCodePoint(e);
|
|
21182
|
+
toks.push(lit(ch));
|
|
21183
|
+
i += 1 + ch.length;
|
|
21184
|
+
continue;
|
|
21252
21185
|
}
|
|
21253
|
-
|
|
21254
|
-
|
|
21255
|
-
|
|
21256
|
-
|
|
21257
|
-
|
|
21258
|
-
return (this.#toString !== undefined ? this.#toString
|
|
21259
|
-
: !this.type ?
|
|
21260
|
-
(this.#toString = this.#parts.map(p => String(p)).join(''))
|
|
21261
|
-
: (this.#toString =
|
|
21262
|
-
this.type +
|
|
21263
|
-
'(' +
|
|
21264
|
-
this.#parts.map(p => String(p)).join('|') +
|
|
21265
|
-
')'));
|
|
21266
|
-
}
|
|
21267
|
-
#fillNegs() {
|
|
21268
|
-
/* c8 ignore start */
|
|
21269
|
-
if (this !== this.#root)
|
|
21270
|
-
throw new Error('should only call on root');
|
|
21271
|
-
if (this.#filledNegs)
|
|
21272
|
-
return this;
|
|
21273
|
-
/* c8 ignore stop */
|
|
21274
|
-
// call toString() once to fill this out
|
|
21275
|
-
this.toString();
|
|
21276
|
-
this.#filledNegs = true;
|
|
21277
|
-
let n;
|
|
21278
|
-
while ((n = this.#negs.pop())) {
|
|
21279
|
-
if (n.type !== '!')
|
|
21186
|
+
if (c === '[') {
|
|
21187
|
+
const [re, consumed] = parseClass(p, i, nocase, form);
|
|
21188
|
+
if (consumed) {
|
|
21189
|
+
toks.push({ t: 'class', re });
|
|
21190
|
+
i += consumed;
|
|
21280
21191
|
continue;
|
|
21281
|
-
// walk up the tree, appending everthing that comes AFTER parentIndex
|
|
21282
|
-
let p = n;
|
|
21283
|
-
let pp = p.#parent;
|
|
21284
|
-
while (pp) {
|
|
21285
|
-
for (let i = p.#parentIndex + 1; !pp.type && i < pp.#parts.length; i++) {
|
|
21286
|
-
for (const part of n.#parts) {
|
|
21287
|
-
/* c8 ignore start */
|
|
21288
|
-
if (typeof part === 'string') {
|
|
21289
|
-
throw new Error('string part in extglob AST??');
|
|
21290
|
-
}
|
|
21291
|
-
/* c8 ignore stop */
|
|
21292
|
-
part.copyIn(pp.#parts[i]);
|
|
21293
|
-
}
|
|
21294
|
-
}
|
|
21295
|
-
p = pp;
|
|
21296
|
-
pp = p.#parent;
|
|
21297
21192
|
}
|
|
21298
21193
|
}
|
|
21299
|
-
|
|
21194
|
+
if (!noext && extTypes.includes(c) && p[i + 1] === '(') {
|
|
21195
|
+
toks.push({ t: 'open', type: c });
|
|
21196
|
+
i += 2;
|
|
21197
|
+
continue;
|
|
21198
|
+
}
|
|
21199
|
+
toks.push(!noext && c === '|' ? { t: 'bar' }
|
|
21200
|
+
: !noext && c === ')' ? { t: 'close' }
|
|
21201
|
+
: c === '*' ? { t: 'star' }
|
|
21202
|
+
: c === '?' ? { t: 'any' }
|
|
21203
|
+
: lit(c));
|
|
21204
|
+
i += c.length;
|
|
21205
|
+
}
|
|
21206
|
+
return toks;
|
|
21207
|
+
};
|
|
21208
|
+
// map each open token index to the index of its close token
|
|
21209
|
+
const pair = (toks) => {
|
|
21210
|
+
const pairs = new Map();
|
|
21211
|
+
const stack = [];
|
|
21212
|
+
toks.forEach((tok, i) => {
|
|
21213
|
+
if (tok.t === 'open')
|
|
21214
|
+
stack.push(i);
|
|
21215
|
+
else if (tok.t === 'close' && stack.length)
|
|
21216
|
+
pairs.set(stack.pop(), i);
|
|
21217
|
+
});
|
|
21218
|
+
return pairs;
|
|
21219
|
+
};
|
|
21220
|
+
// build the alternatives between start and end. An open token that
|
|
21221
|
+
// is not closed is never inside a closed extglob, so bar and close
|
|
21222
|
+
// tokens are only literal at the top level.
|
|
21223
|
+
const build = (toks, pairs, start, end, top) => {
|
|
21224
|
+
let seq = [];
|
|
21225
|
+
const alts = [seq];
|
|
21226
|
+
for (let i = start; i < end; i++) {
|
|
21227
|
+
const tok = toks[i];
|
|
21228
|
+
const close = pairs.get(i);
|
|
21229
|
+
if (tok.t === 'open' && close !== undefined) {
|
|
21230
|
+
const sub = build(toks, pairs, i + 1, close, false);
|
|
21231
|
+
seq.push({ t: 'ext', type: tok.type, alts: sub });
|
|
21232
|
+
i = close;
|
|
21233
|
+
}
|
|
21234
|
+
else if (tok.t === 'bar' && !top) {
|
|
21235
|
+
alts.push((seq = []));
|
|
21236
|
+
}
|
|
21237
|
+
else if (tok.t === 'open') {
|
|
21238
|
+
seq.push(lit(tok.type), lit('('));
|
|
21239
|
+
}
|
|
21240
|
+
else if (tok.t === 'bar') {
|
|
21241
|
+
seq.push(lit('|'));
|
|
21242
|
+
}
|
|
21243
|
+
else if (tok.t === 'close') {
|
|
21244
|
+
seq.push(lit(')'));
|
|
21245
|
+
}
|
|
21246
|
+
else {
|
|
21247
|
+
seq.push(tok);
|
|
21248
|
+
}
|
|
21300
21249
|
}
|
|
21301
|
-
|
|
21302
|
-
|
|
21303
|
-
|
|
21304
|
-
|
|
21305
|
-
|
|
21306
|
-
|
|
21307
|
-
|
|
21308
|
-
|
|
21309
|
-
|
|
21310
|
-
|
|
21311
|
-
|
|
21312
|
-
|
|
21313
|
-
|
|
21314
|
-
|
|
21315
|
-
|
|
21316
|
-
|
|
21317
|
-
|
|
21318
|
-
|
|
21319
|
-
|
|
21320
|
-
|
|
21321
|
-
|
|
21322
|
-
|
|
21323
|
-
|
|
21324
|
-
|
|
21325
|
-
|
|
21326
|
-
|
|
21327
|
-
|
|
21328
|
-
|
|
21329
|
-
|
|
21330
|
-
|
|
21331
|
-
|
|
21332
|
-
|
|
21333
|
-
|
|
21334
|
-
|
|
21335
|
-
|
|
21336
|
-
|
|
21337
|
-
|
|
21338
|
-
|
|
21339
|
-
|
|
21340
|
-
|
|
21341
|
-
|
|
21342
|
-
|
|
21343
|
-
|
|
21250
|
+
return alts;
|
|
21251
|
+
};
|
|
21252
|
+
// normalize each run of literal chars as one string, so that a char
|
|
21253
|
+
// and the combining marks after it compose (or decompose) together.
|
|
21254
|
+
// Syntax is already parsed, so a char that normalizes to a syntax
|
|
21255
|
+
// char (such as full-width `*` in NFKC) stays a literal.
|
|
21256
|
+
const normalize = (items, form) => {
|
|
21257
|
+
const out = [];
|
|
21258
|
+
let run = '';
|
|
21259
|
+
const flush = () => {
|
|
21260
|
+
for (const ch of run.normalize(form))
|
|
21261
|
+
out.push(lit(ch));
|
|
21262
|
+
run = '';
|
|
21263
|
+
};
|
|
21264
|
+
for (const it of items) {
|
|
21265
|
+
if (it.t === 'lit') {
|
|
21266
|
+
run += it.ch;
|
|
21267
|
+
continue;
|
|
21268
|
+
}
|
|
21269
|
+
flush();
|
|
21270
|
+
out.push(it.t === 'ext' ?
|
|
21271
|
+
{ ...it, alts: it.alts.map(a => normalize(a, form)) }
|
|
21272
|
+
: it);
|
|
21273
|
+
}
|
|
21274
|
+
flush();
|
|
21275
|
+
return out;
|
|
21276
|
+
};
|
|
21277
|
+
// the start node, and the number of node ids. Ids are dense, from 0
|
|
21278
|
+
// for the match node.
|
|
21279
|
+
const compile = (items, nocase) => {
|
|
21280
|
+
let id = 1;
|
|
21281
|
+
const split = (out) => ({ t: 'split', id: id++, out });
|
|
21282
|
+
const seq = (items, next) => items.reduceRight((next, it) => item(it, next), next);
|
|
21283
|
+
const item = (it, next) => {
|
|
21284
|
+
switch (it.t) {
|
|
21285
|
+
case 'lit':
|
|
21286
|
+
const re = nocase ? foldRe(it.ch) : undefined;
|
|
21287
|
+
return { t: 'lit', id: id++, ch: it.ch, re, next };
|
|
21288
|
+
case 'any':
|
|
21289
|
+
case 'star':
|
|
21290
|
+
return { t: it.t, id: id++, next };
|
|
21291
|
+
case 'class':
|
|
21292
|
+
return { t: 'class', id: id++, re: it.re, next };
|
|
21293
|
+
}
|
|
21294
|
+
const alts = (next) => it.alts.map(a => seq(a, next));
|
|
21295
|
+
switch (it.type) {
|
|
21296
|
+
case '@':
|
|
21297
|
+
return split(alts(next));
|
|
21298
|
+
case '?':
|
|
21299
|
+
return split([next, ...alts(next)]);
|
|
21300
|
+
case '!':
|
|
21301
|
+
return { t: 'neg', id: id++, sub: split(alts(MATCH)), next };
|
|
21302
|
+
}
|
|
21303
|
+
// * and +, loop back after each match
|
|
21304
|
+
const after = split([]);
|
|
21305
|
+
const entry = split(alts(after));
|
|
21306
|
+
after.out.push(next, entry);
|
|
21307
|
+
return it.type === '*' ? after : entry;
|
|
21308
|
+
};
|
|
21309
|
+
const start = seq(items, MATCH);
|
|
21310
|
+
return [start, id];
|
|
21311
|
+
};
|
|
21312
|
+
// one line per node, in the order that a walk from the start
|
|
21313
|
+
// reaches them. Edges point to node ids. The nodes of a negated
|
|
21314
|
+
// sub-pattern are indented under their negation.
|
|
21315
|
+
const show = (start) => {
|
|
21316
|
+
const lines = [];
|
|
21317
|
+
const seen = new Set();
|
|
21318
|
+
const ref = (n) => (n.t === 'match' ? 'match' : String(n.id));
|
|
21319
|
+
const walk = (n, indent) => {
|
|
21320
|
+
if (n.t === 'match' || seen.has(n))
|
|
21321
|
+
return;
|
|
21322
|
+
seen.add(n);
|
|
21323
|
+
const line = (desc) => lines.push(`${indent}${n.id}: ${desc}`);
|
|
21324
|
+
switch (n.t) {
|
|
21325
|
+
case 'split':
|
|
21326
|
+
line(`split -> ${n.out.map(ref).join(', ')}`);
|
|
21327
|
+
for (const o of n.out)
|
|
21328
|
+
walk(o, indent);
|
|
21329
|
+
return;
|
|
21330
|
+
case 'neg':
|
|
21331
|
+
line(`!(${ref(n.sub)}) -> ${ref(n.next)}`);
|
|
21332
|
+
walk(n.sub, indent + ' ');
|
|
21333
|
+
return walk(n.next, indent);
|
|
21334
|
+
case 'lit':
|
|
21335
|
+
line(`${JSON.stringify(n.ch)} -> ${ref(n.next)}`);
|
|
21336
|
+
break;
|
|
21337
|
+
case 'class':
|
|
21338
|
+
line(`${n.re} -> ${ref(n.next)}`);
|
|
21339
|
+
break;
|
|
21340
|
+
default:
|
|
21341
|
+
line(`${n.t === 'any' ? '?' : '*'} -> ${ref(n.next)}`);
|
|
21344
21342
|
}
|
|
21343
|
+
walk(n.next, indent);
|
|
21344
|
+
};
|
|
21345
|
+
walk(start, '');
|
|
21346
|
+
return [`start -> ${ref(start)}`, ...lines].join('\n');
|
|
21347
|
+
};
|
|
21348
|
+
// The threads at one position in the string. Each node thread is
|
|
21349
|
+
// only kept once, and runs with the same state are only kept once,
|
|
21350
|
+
// so that identical threads merge. The match node is not in
|
|
21351
|
+
// `threads`, because it can not step. It sets `match` instead.
|
|
21352
|
+
class State {
|
|
21353
|
+
// set by the Sim, to mark the nodes that this state has
|
|
21354
|
+
gen;
|
|
21355
|
+
threads = [];
|
|
21356
|
+
match = false;
|
|
21357
|
+
runs = [];
|
|
21358
|
+
// the sorted ids of the threads, with 0 for a match, once the
|
|
21359
|
+
// state is done
|
|
21360
|
+
ids = [];
|
|
21361
|
+
constructor(gen) {
|
|
21362
|
+
this.gen = gen;
|
|
21363
|
+
}
|
|
21364
|
+
// no threads, so nothing more can match
|
|
21365
|
+
get dead() {
|
|
21366
|
+
return !this.threads.length && !this.match && !this.runs.length;
|
|
21367
|
+
}
|
|
21368
|
+
}
|
|
21369
|
+
// true if the two states hold the same threads
|
|
21370
|
+
const sameState = (a, b) => {
|
|
21371
|
+
if (a.ids.length !== b.ids.length)
|
|
21372
|
+
return false;
|
|
21373
|
+
if (a.runs.length !== b.runs.length)
|
|
21374
|
+
return false;
|
|
21375
|
+
if (a.ids.some((id, i) => id !== b.ids[i]))
|
|
21376
|
+
return false;
|
|
21377
|
+
return a.runs.every(r => b.runs.some(o => o.neg === r.neg && sameState(o.state, r.state)));
|
|
21378
|
+
};
|
|
21379
|
+
const marks = (size) => ({
|
|
21380
|
+
has: new Float64Array(size),
|
|
21381
|
+
seen: new Float64Array(size),
|
|
21382
|
+
gen: 0,
|
|
21383
|
+
});
|
|
21384
|
+
class Sim {
|
|
21385
|
+
// `.` and `..` only match literal dots, even with `dot:true`
|
|
21386
|
+
dots;
|
|
21387
|
+
// the string starts with `.`, and `dot:true` is not set
|
|
21388
|
+
dotStart;
|
|
21389
|
+
#marks;
|
|
21390
|
+
constructor(dots, dotStart, marks) {
|
|
21391
|
+
this.dots = dots;
|
|
21392
|
+
this.dotStart = dotStart;
|
|
21393
|
+
this.#marks = marks;
|
|
21394
|
+
}
|
|
21395
|
+
state() {
|
|
21396
|
+
return new State(++this.#marks.gen);
|
|
21397
|
+
}
|
|
21398
|
+
// sort the ids of a state, once it has all of its threads
|
|
21399
|
+
done(state) {
|
|
21400
|
+
state.ids = state.threads.map(n => n.id).sort((a, b) => a - b);
|
|
21401
|
+
if (state.match)
|
|
21402
|
+
state.ids.unshift(MATCH.id);
|
|
21403
|
+
return state;
|
|
21404
|
+
}
|
|
21405
|
+
// true the first time that the state walks through the node, so
|
|
21406
|
+
// that loops in the graph stop
|
|
21407
|
+
#visit(state, node) {
|
|
21408
|
+
const { seen } = this.#marks;
|
|
21409
|
+
if (seen[node.id] === state.gen)
|
|
21410
|
+
return false;
|
|
21411
|
+
seen[node.id] = state.gen;
|
|
21345
21412
|
return true;
|
|
21346
21413
|
}
|
|
21347
|
-
|
|
21348
|
-
|
|
21349
|
-
|
|
21350
|
-
if (this.#parent?.type === '!')
|
|
21351
|
-
return true;
|
|
21352
|
-
if (!this.#parent?.isEnd())
|
|
21414
|
+
#addThread(state, node) {
|
|
21415
|
+
const { has } = this.#marks;
|
|
21416
|
+
if (has[node.id] === state.gen)
|
|
21353
21417
|
return false;
|
|
21354
|
-
|
|
21355
|
-
|
|
21356
|
-
|
|
21357
|
-
|
|
21358
|
-
|
|
21359
|
-
|
|
21360
|
-
|
|
21361
|
-
|
|
21362
|
-
|
|
21363
|
-
|
|
21364
|
-
|
|
21365
|
-
|
|
21366
|
-
|
|
21367
|
-
|
|
21368
|
-
|
|
21369
|
-
|
|
21370
|
-
|
|
21371
|
-
|
|
21372
|
-
|
|
21373
|
-
|
|
21374
|
-
|
|
21375
|
-
|
|
21376
|
-
|
|
21377
|
-
|
|
21378
|
-
|
|
21379
|
-
|
|
21380
|
-
|
|
21381
|
-
|
|
21382
|
-
|
|
21383
|
-
|
|
21384
|
-
|
|
21385
|
-
|
|
21386
|
-
|
|
21387
|
-
|
|
21388
|
-
|
|
21389
|
-
|
|
21390
|
-
|
|
21391
|
-
|
|
21392
|
-
|
|
21393
|
-
|
|
21394
|
-
|
|
21395
|
-
|
|
21396
|
-
|
|
21397
|
-
|
|
21398
|
-
|
|
21418
|
+
has[node.id] = state.gen;
|
|
21419
|
+
state.threads.push(node);
|
|
21420
|
+
return true;
|
|
21421
|
+
}
|
|
21422
|
+
// wildcards only match a leading dot if `dot:true`. In a negated
|
|
21423
|
+
// sub-pattern, this does not apply, because the negation itself
|
|
21424
|
+
// can not match a leading dot.
|
|
21425
|
+
restricted(i, top) {
|
|
21426
|
+
return top && (this.dots || (this.dotStart && i === 0));
|
|
21427
|
+
}
|
|
21428
|
+
add(state, node, i, top) {
|
|
21429
|
+
switch (node.t) {
|
|
21430
|
+
case 'split':
|
|
21431
|
+
if (!this.#visit(state, node))
|
|
21432
|
+
return;
|
|
21433
|
+
for (const o of node.out)
|
|
21434
|
+
this.add(state, o, i, top);
|
|
21435
|
+
return;
|
|
21436
|
+
case 'neg':
|
|
21437
|
+
if (!this.#visit(state, node))
|
|
21438
|
+
return;
|
|
21439
|
+
const sub = this.state();
|
|
21440
|
+
this.add(sub, node.sub, i, false);
|
|
21441
|
+
this.done(sub);
|
|
21442
|
+
return this.addRun(state, { t: 'run', neg: node, state: sub }, i, top);
|
|
21443
|
+
case 'star':
|
|
21444
|
+
// a * can not start a dotfile, even if it matches nothing
|
|
21445
|
+
if (this.restricted(i, top))
|
|
21446
|
+
return;
|
|
21447
|
+
if (this.#addThread(state, node))
|
|
21448
|
+
this.add(state, node.next, i, top);
|
|
21449
|
+
return;
|
|
21450
|
+
case 'match':
|
|
21451
|
+
state.match = true;
|
|
21452
|
+
return;
|
|
21453
|
+
default:
|
|
21454
|
+
this.#addThread(state, node);
|
|
21455
|
+
}
|
|
21456
|
+
}
|
|
21457
|
+
addRun(state, run, i, top) {
|
|
21458
|
+
for (const r of state.runs) {
|
|
21459
|
+
if (r.neg === run.neg && sameState(r.state, run.state))
|
|
21460
|
+
return;
|
|
21461
|
+
}
|
|
21462
|
+
state.runs.push(run);
|
|
21463
|
+
if (!run.state.match) {
|
|
21464
|
+
this.add(state, run.neg.next, i, top);
|
|
21465
|
+
}
|
|
21466
|
+
}
|
|
21467
|
+
// the threads after char `c`, at index `i`
|
|
21468
|
+
step(state, c, i, top) {
|
|
21469
|
+
const next = this.state();
|
|
21470
|
+
for (const th of state.threads) {
|
|
21471
|
+
switch (th.t) {
|
|
21472
|
+
case 'lit':
|
|
21473
|
+
if (litMatch(th, c)) {
|
|
21474
|
+
this.add(next, th.next, i + 1, top);
|
|
21399
21475
|
}
|
|
21400
|
-
|
|
21401
|
-
|
|
21476
|
+
break;
|
|
21477
|
+
case 'any':
|
|
21478
|
+
if (!this.restricted(i, top))
|
|
21479
|
+
this.add(next, th.next, i + 1, top);
|
|
21480
|
+
break;
|
|
21481
|
+
case 'class':
|
|
21482
|
+
if (!this.restricted(i, top) && th.re.test(c)) {
|
|
21483
|
+
this.add(next, th.next, i + 1, top);
|
|
21402
21484
|
}
|
|
21403
|
-
|
|
21404
|
-
|
|
21405
|
-
|
|
21406
|
-
|
|
21407
|
-
inBrace = true;
|
|
21408
|
-
braceStart = i;
|
|
21409
|
-
braceNeg = false;
|
|
21410
|
-
acc += c;
|
|
21411
|
-
continue;
|
|
21412
|
-
}
|
|
21413
|
-
// we don't have to check for adoption here, because that's
|
|
21414
|
-
// done at the other recursion point.
|
|
21415
|
-
const doRecurse = !opt.noext &&
|
|
21416
|
-
isExtglobType(c) &&
|
|
21417
|
-
str.charAt(i) === '(' &&
|
|
21418
|
-
extDepth <= maxDepth;
|
|
21419
|
-
if (doRecurse) {
|
|
21420
|
-
ast.push(acc);
|
|
21421
|
-
acc = '';
|
|
21422
|
-
const ext = new _a(c, ast);
|
|
21423
|
-
i = _a.#parseAST(str, ext, i, opt, extDepth + 1);
|
|
21424
|
-
ast.push(ext);
|
|
21425
|
-
continue;
|
|
21426
|
-
}
|
|
21427
|
-
acc += c;
|
|
21485
|
+
break;
|
|
21486
|
+
case 'star':
|
|
21487
|
+
if (!this.restricted(i, top))
|
|
21488
|
+
this.add(next, th, i + 1, top);
|
|
21428
21489
|
}
|
|
21429
|
-
ast.push(acc);
|
|
21430
|
-
return i;
|
|
21431
21490
|
}
|
|
21432
|
-
|
|
21433
|
-
|
|
21434
|
-
|
|
21435
|
-
|
|
21436
|
-
|
|
21437
|
-
|
|
21438
|
-
|
|
21439
|
-
const c = str.charAt(i++);
|
|
21440
|
-
// still accumulate escapes at this point, but we do ignore
|
|
21441
|
-
// starts that are escaped
|
|
21442
|
-
if (escaping || c === '\\') {
|
|
21443
|
-
escaping = !escaping;
|
|
21444
|
-
acc += c;
|
|
21445
|
-
continue;
|
|
21446
|
-
}
|
|
21447
|
-
if (inBrace) {
|
|
21448
|
-
if (i === braceStart + 1) {
|
|
21449
|
-
if (c === '^' || c === '!') {
|
|
21450
|
-
braceNeg = true;
|
|
21451
|
-
}
|
|
21452
|
-
}
|
|
21453
|
-
else if (c === ']' && !(i === braceStart + 2 && braceNeg)) {
|
|
21454
|
-
inBrace = false;
|
|
21455
|
-
}
|
|
21456
|
-
acc += c;
|
|
21457
|
-
continue;
|
|
21458
|
-
}
|
|
21459
|
-
else if (c === '[') {
|
|
21460
|
-
inBrace = true;
|
|
21461
|
-
braceStart = i;
|
|
21462
|
-
braceNeg = false;
|
|
21463
|
-
acc += c;
|
|
21464
|
-
continue;
|
|
21465
|
-
}
|
|
21466
|
-
const doRecurse = !opt.noext &&
|
|
21467
|
-
isExtglobType(c) &&
|
|
21468
|
-
str.charAt(i) === '(' &&
|
|
21469
|
-
/* c8 ignore start - the maxDepth is sufficient here */
|
|
21470
|
-
(extDepth <= maxDepth || (ast && ast.#canAdoptType(c)));
|
|
21471
|
-
/* c8 ignore stop */
|
|
21472
|
-
if (doRecurse) {
|
|
21473
|
-
const depthAdd = ast && ast.#canAdoptType(c) ? 0 : 1;
|
|
21474
|
-
part.push(acc);
|
|
21475
|
-
acc = '';
|
|
21476
|
-
const ext = new _a(c, part);
|
|
21477
|
-
part.push(ext);
|
|
21478
|
-
i = _a.#parseAST(str, ext, i, opt, extDepth + depthAdd);
|
|
21479
|
-
continue;
|
|
21480
|
-
}
|
|
21481
|
-
if (c === '|') {
|
|
21482
|
-
part.push(acc);
|
|
21483
|
-
acc = '';
|
|
21484
|
-
parts.push(part);
|
|
21485
|
-
part = new _a(null, ast);
|
|
21486
|
-
continue;
|
|
21487
|
-
}
|
|
21488
|
-
if (c === ')') {
|
|
21489
|
-
if (acc === '' && ast.#parts.length === 0) {
|
|
21490
|
-
ast.#emptyExt = true;
|
|
21491
|
+
if (!this.restricted(i, top)) {
|
|
21492
|
+
for (const run of state.runs) {
|
|
21493
|
+
// a sub-pattern with no threads can not match again, so the
|
|
21494
|
+
// run stays the same
|
|
21495
|
+
if (run.state.dead) {
|
|
21496
|
+
this.addRun(next, run, i + 1, top);
|
|
21497
|
+
continue;
|
|
21491
21498
|
}
|
|
21492
|
-
|
|
21493
|
-
|
|
21494
|
-
ast.push(...parts, part);
|
|
21495
|
-
return i;
|
|
21499
|
+
const sub = this.step(run.state, c, i, false);
|
|
21500
|
+
this.addRun(next, { t: 'run', neg: run.neg, state: sub }, i + 1, top);
|
|
21496
21501
|
}
|
|
21497
|
-
acc += c;
|
|
21498
|
-
}
|
|
21499
|
-
// unfinished extglob
|
|
21500
|
-
// if we got here, it was a malformed extglob! not an extglob, but
|
|
21501
|
-
// maybe something else in there.
|
|
21502
|
-
ast.type = null;
|
|
21503
|
-
ast.#hasMagic = undefined;
|
|
21504
|
-
ast.#parts = [str.substring(pos - 1)];
|
|
21505
|
-
return i;
|
|
21506
|
-
}
|
|
21507
|
-
#canAdoptWithSpace(child) {
|
|
21508
|
-
return this.#canAdopt(child, adoptionWithSpaceMap);
|
|
21509
|
-
}
|
|
21510
|
-
#canAdopt(child, map = adoptionMap) {
|
|
21511
|
-
if (!child ||
|
|
21512
|
-
typeof child !== 'object' ||
|
|
21513
|
-
child.type !== null ||
|
|
21514
|
-
child.#parts.length !== 1 ||
|
|
21515
|
-
this.type === null) {
|
|
21516
|
-
return false;
|
|
21517
|
-
}
|
|
21518
|
-
const gc = child.#parts[0];
|
|
21519
|
-
if (!gc || typeof gc !== 'object' || gc.type === null) {
|
|
21520
|
-
return false;
|
|
21521
|
-
}
|
|
21522
|
-
return this.#canAdoptType(gc.type, map);
|
|
21523
|
-
}
|
|
21524
|
-
#canAdoptType(c, map = adoptionAnyMap) {
|
|
21525
|
-
return !!map.get(this.type)?.includes(c);
|
|
21526
|
-
}
|
|
21527
|
-
#adoptWithSpace(child, index) {
|
|
21528
|
-
const gc = child.#parts[0];
|
|
21529
|
-
const blank = new _a(null, gc, this.options);
|
|
21530
|
-
blank.#parts.push('');
|
|
21531
|
-
gc.push(blank);
|
|
21532
|
-
this.#adopt(child, index);
|
|
21533
|
-
}
|
|
21534
|
-
#adopt(child, index) {
|
|
21535
|
-
const gc = child.#parts[0];
|
|
21536
|
-
this.#parts.splice(index, 1, ...gc.#parts);
|
|
21537
|
-
for (const p of gc.#parts) {
|
|
21538
|
-
if (typeof p === 'object')
|
|
21539
|
-
p.#parent = this;
|
|
21540
|
-
}
|
|
21541
|
-
this.#toString = undefined;
|
|
21542
|
-
}
|
|
21543
|
-
#canUsurpType(c) {
|
|
21544
|
-
const m = usurpMap.get(this.type);
|
|
21545
|
-
return !!m?.has(c);
|
|
21546
|
-
}
|
|
21547
|
-
#canUsurp(child) {
|
|
21548
|
-
if (!child ||
|
|
21549
|
-
typeof child !== 'object' ||
|
|
21550
|
-
child.type !== null ||
|
|
21551
|
-
child.#parts.length !== 1 ||
|
|
21552
|
-
this.type === null ||
|
|
21553
|
-
this.#parts.length !== 1) {
|
|
21554
|
-
return false;
|
|
21555
|
-
}
|
|
21556
|
-
const gc = child.#parts[0];
|
|
21557
|
-
if (!gc || typeof gc !== 'object' || gc.type === null) {
|
|
21558
|
-
return false;
|
|
21559
21502
|
}
|
|
21560
|
-
return this
|
|
21503
|
+
return this.done(next);
|
|
21561
21504
|
}
|
|
21562
|
-
|
|
21563
|
-
|
|
21564
|
-
|
|
21565
|
-
|
|
21566
|
-
|
|
21567
|
-
|
|
21568
|
-
|
|
21569
|
-
|
|
21570
|
-
|
|
21571
|
-
|
|
21572
|
-
|
|
21573
|
-
|
|
21574
|
-
|
|
21575
|
-
|
|
21576
|
-
|
|
21577
|
-
|
|
21578
|
-
|
|
21579
|
-
|
|
21580
|
-
|
|
21581
|
-
|
|
21582
|
-
|
|
21583
|
-
|
|
21584
|
-
|
|
21585
|
-
|
|
21586
|
-
|
|
21587
|
-
|
|
21588
|
-
|
|
21589
|
-
|
|
21590
|
-
|
|
21591
|
-
|
|
21592
|
-
|
|
21593
|
-
|
|
21594
|
-
|
|
21595
|
-
|
|
21596
|
-
|
|
21597
|
-
|
|
21598
|
-
|
|
21599
|
-
|
|
21600
|
-
|
|
21601
|
-
|
|
21602
|
-
|
|
21603
|
-
|
|
21604
|
-
return body;
|
|
21605
|
-
}
|
|
21606
|
-
const flags = (this.#options.nocase ? 'i' : '') + (uflag ? 'u' : '');
|
|
21607
|
-
return Object.assign(new RegExp(`^${re}$`, flags), {
|
|
21608
|
-
_src: re,
|
|
21609
|
-
_glob: glob,
|
|
21610
|
-
});
|
|
21505
|
+
}
|
|
21506
|
+
// A canonical key for the threads in a state. States with the same
|
|
21507
|
+
// key hold the same threads, so they match the same strings.
|
|
21508
|
+
const stateKey = (state) => {
|
|
21509
|
+
const ids = state.ids.join();
|
|
21510
|
+
if (!state.runs.length)
|
|
21511
|
+
return ids;
|
|
21512
|
+
const runs = state.runs.map(r => `${r.neg.id}(${stateKey(r.state)})`);
|
|
21513
|
+
return `${ids}|${runs.sort().join('|')}`;
|
|
21514
|
+
};
|
|
21515
|
+
// The cache can hold about this many chars of state keys and
|
|
21516
|
+
// transitions. When it is full, it is cleared, so that a pattern
|
|
21517
|
+
// can not use an unbounded amount of memory.
|
|
21518
|
+
const DFA_BUDGET = 1 << 18;
|
|
21519
|
+
// A cache of the states that the simulation reaches, built as the
|
|
21520
|
+
// matcher is used. Each char of a string is then one Map lookup,
|
|
21521
|
+
// once the states that it leads to are known.
|
|
21522
|
+
//
|
|
21523
|
+
// The dot rules only restrict the first char of a dotfile (strings
|
|
21524
|
+
// that are only `.` or `..` do not use the cache). So a dotfile
|
|
21525
|
+
// starts at its own state, which takes its first step with the
|
|
21526
|
+
// restriction, and every other state takes steps without it.
|
|
21527
|
+
class Dfa {
|
|
21528
|
+
#start;
|
|
21529
|
+
#states = new Map();
|
|
21530
|
+
#size = 0;
|
|
21531
|
+
#plain;
|
|
21532
|
+
#dotStart;
|
|
21533
|
+
#sim;
|
|
21534
|
+
#dotSim;
|
|
21535
|
+
constructor(start, marks) {
|
|
21536
|
+
this.#start = start;
|
|
21537
|
+
this.#sim = new Sim(false, false, marks);
|
|
21538
|
+
this.#dotSim = new Sim(false, true, marks);
|
|
21539
|
+
}
|
|
21540
|
+
#make(state) {
|
|
21541
|
+
return {
|
|
21542
|
+
state,
|
|
21543
|
+
match: state.match,
|
|
21544
|
+
dead: state.dead,
|
|
21545
|
+
next: new Map(),
|
|
21546
|
+
};
|
|
21611
21547
|
}
|
|
21612
|
-
|
|
21613
|
-
|
|
21614
|
-
|
|
21615
|
-
|
|
21616
|
-
|
|
21617
|
-
|
|
21618
|
-
|
|
21619
|
-
|
|
21620
|
-
|
|
21621
|
-
|
|
21622
|
-
|
|
21623
|
-
|
|
21624
|
-
|
|
21625
|
-
|
|
21626
|
-
|
|
21627
|
-
|
|
21628
|
-
|
|
21629
|
-
|
|
21630
|
-
|
|
21631
|
-
|
|
21632
|
-
|
|
21633
|
-
|
|
21634
|
-
|
|
21635
|
-
|
|
21636
|
-
|
|
21637
|
-
// - if traversal possible, but not allowed: /(?!\.\.?(?:$|/))
|
|
21638
|
-
// - if dots allowed or not possible: /
|
|
21639
|
-
// - if dots possible and not allowed: /(?!\.)
|
|
21640
|
-
// end is:
|
|
21641
|
-
// - if last pattern, same as part-matching mode
|
|
21642
|
-
// - else nothing
|
|
21643
|
-
//
|
|
21644
|
-
// Always put the (?:$|/) on negated tails, though, because that has to be
|
|
21645
|
-
// there to bind the end of the negated pattern portion, and it's easier to
|
|
21646
|
-
// just stick it in now rather than try to inject it later in the middle of
|
|
21647
|
-
// the pattern.
|
|
21648
|
-
//
|
|
21649
|
-
// We can just always return the same end, and leave it up to the caller
|
|
21650
|
-
// to know whether it's going to be used joined or in parts.
|
|
21651
|
-
// And, if the start is adjusted slightly, can do the same there:
|
|
21652
|
-
// - if not isStart: nothing
|
|
21653
|
-
// - if traversal possible, but not allowed: (?:/|^)(?!\.\.?$)
|
|
21654
|
-
// - if dots allowed or not possible: (?:/|^)
|
|
21655
|
-
// - if dots possible and not allowed: (?:/|^)(?!\.)
|
|
21656
|
-
//
|
|
21657
|
-
// But it's better to have a simpler binding without a conditional, for
|
|
21658
|
-
// performance, so probably better to return both start options.
|
|
21659
|
-
//
|
|
21660
|
-
// Then the caller just ignores the end if it's not the first pattern,
|
|
21661
|
-
// and the start always gets applied.
|
|
21662
|
-
//
|
|
21663
|
-
// But that's always going to be $ if it's the ending pattern, or nothing,
|
|
21664
|
-
// so the caller can just attach $ at the end of the pattern when building.
|
|
21665
|
-
//
|
|
21666
|
-
// So the todo is:
|
|
21667
|
-
// - better detect what kind of start is needed
|
|
21668
|
-
// - return both flavors of starting pattern
|
|
21669
|
-
// - attach $ at the end of the pattern when creating the actual RegExp
|
|
21670
|
-
//
|
|
21671
|
-
// Ah, but wait, no, that all only applies to the root when the first pattern
|
|
21672
|
-
// is not an extglob. If the first pattern IS an extglob, then we need all
|
|
21673
|
-
// that dot prevention biz to live in the extglob portions, because eg
|
|
21674
|
-
// +(*|.x*) can match .xy but not .yx.
|
|
21675
|
-
//
|
|
21676
|
-
// So, return the two flavors if it's #root and the first child is not an
|
|
21677
|
-
// AST, otherwise leave it to the child AST to handle it, and there,
|
|
21678
|
-
// use the (?:^|/) style of start binding.
|
|
21679
|
-
//
|
|
21680
|
-
// Even simplified further:
|
|
21681
|
-
// - Since the start for a join is eg /(?!\.) and the start for a part
|
|
21682
|
-
// is ^(?!\.), we can just prepend (?!\.) to the pattern (either root
|
|
21683
|
-
// or start or whatever) and prepend ^ or / at the Regexp construction.
|
|
21684
|
-
toRegExpSource(allowDot) {
|
|
21685
|
-
const dot = allowDot ?? !!this.#options.dot;
|
|
21686
|
-
if (this.#root === this) {
|
|
21687
|
-
this.#flatten();
|
|
21688
|
-
this.#fillNegs();
|
|
21689
|
-
}
|
|
21690
|
-
if (!isExtglobAST(this)) {
|
|
21691
|
-
const noEmpty = this.isStart() &&
|
|
21692
|
-
this.isEnd() &&
|
|
21693
|
-
!this.#parts.some(s => typeof s !== 'string');
|
|
21694
|
-
const src = this.#parts
|
|
21695
|
-
.map(p => {
|
|
21696
|
-
const [re, _, hasMagic, uflag] = typeof p === 'string' ?
|
|
21697
|
-
_a.#parseGlob(p, this.#hasMagic, noEmpty)
|
|
21698
|
-
: p.toRegExpSource(allowDot);
|
|
21699
|
-
this.#hasMagic = this.#hasMagic || hasMagic;
|
|
21700
|
-
this.#uflag = this.#uflag || uflag;
|
|
21701
|
-
return re;
|
|
21702
|
-
})
|
|
21703
|
-
.join('');
|
|
21704
|
-
let start = '';
|
|
21705
|
-
if (this.isStart()) {
|
|
21706
|
-
if (typeof this.#parts[0] === 'string') {
|
|
21707
|
-
// this is the string that will match the start of the pattern,
|
|
21708
|
-
// so we need to protect against dots and such.
|
|
21709
|
-
// '.' and '..' cannot match unless the pattern is that exactly,
|
|
21710
|
-
// even if it starts with . or dot:true is set.
|
|
21711
|
-
const dotTravAllowed = this.#parts.length === 1 && justDots.has(this.#parts[0]);
|
|
21712
|
-
if (!dotTravAllowed) {
|
|
21713
|
-
const aps = addPatternStart;
|
|
21714
|
-
// check if we have a possibility of matching . or ..,
|
|
21715
|
-
// and prevent that.
|
|
21716
|
-
const needNoTrav =
|
|
21717
|
-
// dots are allowed, and the pattern starts with [ or .
|
|
21718
|
-
(dot && aps.has(src.charAt(0))) ||
|
|
21719
|
-
// the pattern starts with \., and then [ or .
|
|
21720
|
-
(src.startsWith('\\.') && aps.has(src.charAt(2))) ||
|
|
21721
|
-
// the pattern starts with \.\., and then [ or .
|
|
21722
|
-
(src.startsWith('\\.\\.') && aps.has(src.charAt(4)));
|
|
21723
|
-
// no need to prevent dots if it can't match a dot, or if a
|
|
21724
|
-
// sub-pattern will be preventing it anyway.
|
|
21725
|
-
const needNoDot = !dot && !allowDot && aps.has(src.charAt(0));
|
|
21726
|
-
start =
|
|
21727
|
-
needNoTrav ? startNoTraversal
|
|
21728
|
-
: needNoDot ? startNoDot
|
|
21729
|
-
: '';
|
|
21730
|
-
}
|
|
21731
|
-
}
|
|
21732
|
-
}
|
|
21733
|
-
// append the "end of path portion" pattern to negation tails
|
|
21734
|
-
let end = '';
|
|
21735
|
-
if (this.isEnd() &&
|
|
21736
|
-
this.#root.#filledNegs &&
|
|
21737
|
-
this.#parent?.type === '!') {
|
|
21738
|
-
end = '(?:$|\\/)';
|
|
21739
|
-
}
|
|
21740
|
-
const final = start + src + end;
|
|
21741
|
-
return [
|
|
21742
|
-
final,
|
|
21743
|
-
unescape(src),
|
|
21744
|
-
(this.#hasMagic = !!this.#hasMagic),
|
|
21745
|
-
this.#uflag,
|
|
21746
|
-
];
|
|
21747
|
-
}
|
|
21748
|
-
// We need to calculate the body *twice* if it's a repeat pattern
|
|
21749
|
-
// at the start, once in nodot mode, then again in dot mode, so a
|
|
21750
|
-
// pattern like *(?) can match 'x.y'
|
|
21751
|
-
const repeated = this.type === '*' || this.type === '+';
|
|
21752
|
-
// some kind of extglob
|
|
21753
|
-
const start = this.type === '!' ? '(?:(?!(?:' : '(?:';
|
|
21754
|
-
let body = this.#partsToRegExp(dot);
|
|
21755
|
-
if (this.isStart() && this.isEnd() && !body && this.type !== '!') {
|
|
21756
|
-
// invalid extglob, has to at least be *something* present, if it's
|
|
21757
|
-
// the entire path portion.
|
|
21758
|
-
const s = this.toString();
|
|
21759
|
-
const me = this;
|
|
21760
|
-
me.#parts = [s];
|
|
21761
|
-
me.type = null;
|
|
21762
|
-
me.#hasMagic = undefined;
|
|
21763
|
-
return [s, unescape(this.toString()), false, false];
|
|
21764
|
-
}
|
|
21765
|
-
let bodyDotAllowed = !repeated || allowDot || dot || !startNoDot ?
|
|
21766
|
-
''
|
|
21767
|
-
: this.#partsToRegExp(true);
|
|
21768
|
-
if (bodyDotAllowed === body) {
|
|
21769
|
-
bodyDotAllowed = '';
|
|
21770
|
-
}
|
|
21771
|
-
if (bodyDotAllowed) {
|
|
21772
|
-
body = `(?:${body})(?:${bodyDotAllowed})*?`;
|
|
21773
|
-
}
|
|
21774
|
-
// an empty !() is exactly equivalent to a starNoEmpty
|
|
21775
|
-
let final = '';
|
|
21776
|
-
if (this.type === '!' && this.#emptyExt) {
|
|
21777
|
-
final = (this.isStart() && !dot ? startNoDot : '') + starNoEmpty;
|
|
21548
|
+
#intern(state) {
|
|
21549
|
+
const key = stateKey(state);
|
|
21550
|
+
const found = this.#states.get(key);
|
|
21551
|
+
if (found)
|
|
21552
|
+
return found;
|
|
21553
|
+
if (this.#size > DFA_BUDGET)
|
|
21554
|
+
this.#clear();
|
|
21555
|
+
const d = this.#make(state);
|
|
21556
|
+
this.#states.set(key, d);
|
|
21557
|
+
this.#size += key.length + 1;
|
|
21558
|
+
return d;
|
|
21559
|
+
}
|
|
21560
|
+
#clear() {
|
|
21561
|
+
this.#states.clear();
|
|
21562
|
+
this.#size = 0;
|
|
21563
|
+
this.#plain = undefined;
|
|
21564
|
+
this.#dotStart = undefined;
|
|
21565
|
+
}
|
|
21566
|
+
start(dotStart) {
|
|
21567
|
+
if (dotStart) {
|
|
21568
|
+
if (this.#dotStart)
|
|
21569
|
+
return this.#dotStart;
|
|
21570
|
+
const state = this.#dotSim.state();
|
|
21571
|
+
this.#dotSim.add(state, this.#start, 0, true);
|
|
21572
|
+
return (this.#dotStart = this.#make(this.#dotSim.done(state)));
|
|
21778
21573
|
}
|
|
21779
|
-
|
|
21780
|
-
|
|
21781
|
-
|
|
21782
|
-
|
|
21783
|
-
|
|
21784
|
-
|
|
21785
|
-
|
|
21786
|
-
|
|
21787
|
-
|
|
21788
|
-
|
|
21789
|
-
|
|
21790
|
-
|
|
21791
|
-
|
|
21792
|
-
|
|
21793
|
-
|
|
21794
|
-
|
|
21795
|
-
|
|
21796
|
-
(
|
|
21797
|
-
|
|
21798
|
-
|
|
21799
|
-
}
|
|
21800
|
-
#flatten() {
|
|
21801
|
-
if (!isExtglobAST(this)) {
|
|
21802
|
-
for (const p of this.#parts) {
|
|
21803
|
-
if (typeof p === 'object') {
|
|
21804
|
-
p.#flatten();
|
|
21805
|
-
}
|
|
21574
|
+
if (this.#plain)
|
|
21575
|
+
return this.#plain;
|
|
21576
|
+
const state = this.#sim.state();
|
|
21577
|
+
this.#sim.add(state, this.#start, 0, true);
|
|
21578
|
+
return (this.#plain = this.#intern(this.#sim.done(state)));
|
|
21579
|
+
}
|
|
21580
|
+
// the next state, after a miss in `d.ascii`
|
|
21581
|
+
next(d, c) {
|
|
21582
|
+
const code = c.charCodeAt(0);
|
|
21583
|
+
const found = code < 128 ? undefined : d.next.get(c);
|
|
21584
|
+
if (found)
|
|
21585
|
+
return found;
|
|
21586
|
+
// the dotfile start is not in the cache, so it is never shared
|
|
21587
|
+
const n = d === this.#dotStart ?
|
|
21588
|
+
this.#intern(this.#dotSim.step(d.state, c, 0, true))
|
|
21589
|
+
: this.#intern(this.#sim.step(d.state, c, 1, true));
|
|
21590
|
+
if (code < 128) {
|
|
21591
|
+
if (!d.ascii) {
|
|
21592
|
+
d.ascii = new Array(128);
|
|
21593
|
+
this.#size += 128;
|
|
21806
21594
|
}
|
|
21595
|
+
d.ascii[code] = n;
|
|
21807
21596
|
}
|
|
21808
21597
|
else {
|
|
21809
|
-
|
|
21810
|
-
let iterations = 0;
|
|
21811
|
-
let done = false;
|
|
21812
|
-
do {
|
|
21813
|
-
done = true;
|
|
21814
|
-
for (let i = 0; i < this.#parts.length; i++) {
|
|
21815
|
-
const c = this.#parts[i];
|
|
21816
|
-
if (typeof c === 'object') {
|
|
21817
|
-
c.#flatten();
|
|
21818
|
-
if (this.#canAdopt(c)) {
|
|
21819
|
-
done = false;
|
|
21820
|
-
this.#adopt(c, i);
|
|
21821
|
-
}
|
|
21822
|
-
else if (this.#canAdoptWithSpace(c)) {
|
|
21823
|
-
done = false;
|
|
21824
|
-
this.#adoptWithSpace(c, i);
|
|
21825
|
-
}
|
|
21826
|
-
else if (this.#canUsurp(c)) {
|
|
21827
|
-
done = false;
|
|
21828
|
-
this.#usurp(c);
|
|
21829
|
-
}
|
|
21830
|
-
}
|
|
21831
|
-
}
|
|
21832
|
-
} while (!done && ++iterations < 10);
|
|
21598
|
+
d.next.set(c, n);
|
|
21833
21599
|
}
|
|
21834
|
-
this.#
|
|
21600
|
+
this.#size++;
|
|
21601
|
+
return n;
|
|
21835
21602
|
}
|
|
21836
|
-
|
|
21837
|
-
|
|
21838
|
-
|
|
21839
|
-
|
|
21840
|
-
|
|
21841
|
-
|
|
21842
|
-
|
|
21843
|
-
|
|
21844
|
-
|
|
21845
|
-
|
|
21846
|
-
|
|
21847
|
-
|
|
21848
|
-
|
|
21849
|
-
|
|
21850
|
-
|
|
21851
|
-
|
|
21852
|
-
|
|
21853
|
-
|
|
21854
|
-
|
|
21855
|
-
|
|
21856
|
-
|
|
21857
|
-
|
|
21858
|
-
|
|
21859
|
-
|
|
21860
|
-
|
|
21861
|
-
|
|
21862
|
-
|
|
21863
|
-
|
|
21864
|
-
|
|
21603
|
+
}
|
|
21604
|
+
// the nodes in order, if the graph is a single chain
|
|
21605
|
+
const linear = (start) => {
|
|
21606
|
+
const nodes = [];
|
|
21607
|
+
for (let n = start; n.t !== 'match'; n = n.next) {
|
|
21608
|
+
if (n.t === 'split' || n.t === 'neg')
|
|
21609
|
+
return undefined;
|
|
21610
|
+
nodes.push(n);
|
|
21611
|
+
}
|
|
21612
|
+
return nodes;
|
|
21613
|
+
};
|
|
21614
|
+
// Match a chain of nodes. Each node other than `*` matches exactly
|
|
21615
|
+
// one char, so on a failure it is enough to go back to the last `*`
|
|
21616
|
+
// and let it match one more char. This takes at most
|
|
21617
|
+
// nodes.length * chars.length steps.
|
|
21618
|
+
const testLinear = (nodes, chars, start, end) => {
|
|
21619
|
+
let ni = 0;
|
|
21620
|
+
let ci = start;
|
|
21621
|
+
let starNi = -1;
|
|
21622
|
+
let starCi = 0;
|
|
21623
|
+
while (ci < end) {
|
|
21624
|
+
const n = nodes[ni];
|
|
21625
|
+
if (n?.t === 'star') {
|
|
21626
|
+
starNi = ni++;
|
|
21627
|
+
starCi = ci;
|
|
21628
|
+
continue;
|
|
21629
|
+
}
|
|
21630
|
+
const c = chars[ci];
|
|
21631
|
+
if (n &&
|
|
21632
|
+
(n.t === 'any' ||
|
|
21633
|
+
(n.t === 'lit' && litMatch(n, c)) ||
|
|
21634
|
+
(n.t === 'class' && n.re.test(c)))) {
|
|
21635
|
+
ni++;
|
|
21636
|
+
ci++;
|
|
21637
|
+
continue;
|
|
21638
|
+
}
|
|
21639
|
+
if (starNi === -1)
|
|
21640
|
+
return false;
|
|
21641
|
+
ni = starNi + 1;
|
|
21642
|
+
ci = ++starCi;
|
|
21643
|
+
}
|
|
21644
|
+
while (nodes[ni]?.t === 'star')
|
|
21645
|
+
ni++;
|
|
21646
|
+
return ni === nodes.length;
|
|
21647
|
+
};
|
|
21648
|
+
// The least and most chars that the items can match. These are only
|
|
21649
|
+
// bounds: a negation can match a string of any length, so it counts
|
|
21650
|
+
// as 0 to Infinity.
|
|
21651
|
+
const lengths = (items) => {
|
|
21652
|
+
let min = 0;
|
|
21653
|
+
let max = 0;
|
|
21654
|
+
for (const it of items) {
|
|
21655
|
+
const [lo, hi] = itemLengths(it);
|
|
21656
|
+
min += lo;
|
|
21657
|
+
max += hi;
|
|
21658
|
+
}
|
|
21659
|
+
return [min, max];
|
|
21660
|
+
};
|
|
21661
|
+
const itemLengths = (it) => {
|
|
21662
|
+
if (it.t === 'star')
|
|
21663
|
+
return [0, Infinity];
|
|
21664
|
+
if (it.t !== 'ext')
|
|
21665
|
+
return [1, 1];
|
|
21666
|
+
if (it.type === '!')
|
|
21667
|
+
return [0, Infinity];
|
|
21668
|
+
const alts = it.alts.map(lengths);
|
|
21669
|
+
const min = Math.min(...alts.map(a => a[0]));
|
|
21670
|
+
const max = Math.max(...alts.map(a => a[1]));
|
|
21671
|
+
// a loop of alternatives that only match the empty string is empty
|
|
21672
|
+
const loop = max === 0 ? 0 : Infinity;
|
|
21673
|
+
return (it.type === '@' ? [min, max]
|
|
21674
|
+
: it.type === '?' ? [0, max]
|
|
21675
|
+
: it.type === '*' ? [0, loop]
|
|
21676
|
+
: [min, loop]);
|
|
21677
|
+
};
|
|
21678
|
+
// true if the chars from `start` match the literals
|
|
21679
|
+
const hasAffix = (lits, chars, start) => {
|
|
21680
|
+
for (let j = 0; j < lits.length; j++) {
|
|
21681
|
+
if (!litMatch(lits[j], chars[start + j]))
|
|
21682
|
+
return false;
|
|
21683
|
+
}
|
|
21684
|
+
return true;
|
|
21685
|
+
};
|
|
21686
|
+
// a `/`, or half of a surrogate pair
|
|
21687
|
+
const slashOrSurrogate = /[/\ud800-\udfff]/;
|
|
21688
|
+
const surrogate = /[\ud800-\udfff]/;
|
|
21689
|
+
// a string can be indexed by code point, unless it has surrogate
|
|
21690
|
+
// pairs
|
|
21691
|
+
const codePoints = (s) => surrogate.test(s) ? [...s] : s;
|
|
21692
|
+
const noSlash = (s) => {
|
|
21693
|
+
if (s.includes('/')) {
|
|
21694
|
+
throw new Error('can only match a single path portion, got: ' + s);
|
|
21695
|
+
}
|
|
21696
|
+
};
|
|
21697
|
+
class Matcher {
|
|
21698
|
+
pattern;
|
|
21699
|
+
options;
|
|
21700
|
+
#start;
|
|
21701
|
+
// the number of node ids
|
|
21702
|
+
#size;
|
|
21703
|
+
#marks;
|
|
21704
|
+
// the Sim for strings that are only `.` or `..`
|
|
21705
|
+
#dotsSim;
|
|
21706
|
+
// the string to compare, if the pattern has no magic. With
|
|
21707
|
+
// `nocase:true`, the RegExp that folds case is made when it is
|
|
21708
|
+
// first used.
|
|
21709
|
+
#literal;
|
|
21710
|
+
#literalFold = false;
|
|
21711
|
+
#literalRe;
|
|
21712
|
+
// the nodes between the prefix and suffix, if the graph is a
|
|
21713
|
+
// single chain
|
|
21714
|
+
#linear;
|
|
21715
|
+
// the linear nodes are only `*` and `?`, so the length bounds and
|
|
21716
|
+
// the prefix and suffix decide the match
|
|
21717
|
+
#wild = false;
|
|
21718
|
+
// the least and most chars that a match can have
|
|
21719
|
+
#min = 0;
|
|
21720
|
+
#max = Infinity;
|
|
21721
|
+
// the literals that a match must start and end with. Each one
|
|
21722
|
+
// matches exactly one char, and they are distinct items in the
|
|
21723
|
+
// pattern, so a string that does not have them can not match.
|
|
21724
|
+
#prefix = [];
|
|
21725
|
+
#suffix = [];
|
|
21726
|
+
// the prefix and suffix as strings, if they do not fold case
|
|
21727
|
+
#prefixStr;
|
|
21728
|
+
#suffixStr;
|
|
21729
|
+
// there is a prefix or suffix to check
|
|
21730
|
+
#affix = false;
|
|
21731
|
+
#dfa;
|
|
21732
|
+
#form;
|
|
21733
|
+
constructor(pattern, options = {}) {
|
|
21734
|
+
if (pattern.includes('/')) {
|
|
21735
|
+
throw new Error('can only match a single path portion, got pattern: ' + pattern);
|
|
21736
|
+
}
|
|
21737
|
+
this.pattern = pattern;
|
|
21738
|
+
this.options = options;
|
|
21739
|
+
const { nocase = false, noext = false, normalize: n } = options;
|
|
21740
|
+
this.#form = n === true ? 'NFC' : n || undefined;
|
|
21741
|
+
// a pattern that is only an empty extglob is a literal string,
|
|
21742
|
+
// except for `!()`, which matches any non-empty string
|
|
21743
|
+
const literal = /^[?*+@]\(\)$/.test(pattern);
|
|
21744
|
+
const toks = tokenize(pattern, nocase, noext || literal, this.#form);
|
|
21745
|
+
let [items] = build(toks, pair(toks), 0, toks.length, true);
|
|
21746
|
+
if (this.#form)
|
|
21747
|
+
items = normalize(items, this.#form);
|
|
21748
|
+
const [start, size] = compile(items, nocase);
|
|
21749
|
+
this.#start = start;
|
|
21750
|
+
this.#size = size;
|
|
21751
|
+
if (items.every(it => it.t === 'lit')) {
|
|
21752
|
+
this.#literal = items.map(it => it.ch).join('');
|
|
21753
|
+
this.#literalFold = nocase;
|
|
21754
|
+
}
|
|
21755
|
+
else {
|
|
21756
|
+
const lit = (it) => it.t !== 'lit' ? undefined
|
|
21757
|
+
: nocase ? { ch: it.ch, re: foldRe(it.ch) }
|
|
21758
|
+
: { ch: it.ch };
|
|
21759
|
+
for (const it of items) {
|
|
21760
|
+
const l = lit(it);
|
|
21761
|
+
if (!l)
|
|
21762
|
+
break;
|
|
21763
|
+
this.#prefix.push(l);
|
|
21865
21764
|
}
|
|
21866
|
-
|
|
21867
|
-
|
|
21868
|
-
|
|
21869
|
-
|
|
21870
|
-
|
|
21871
|
-
hasMagic = true;
|
|
21872
|
-
continue;
|
|
21765
|
+
for (let j = items.length - 1; j >= 0; j--) {
|
|
21766
|
+
const l = lit(items[j]);
|
|
21767
|
+
if (!l)
|
|
21768
|
+
break;
|
|
21769
|
+
this.#suffix.unshift(l);
|
|
21873
21770
|
}
|
|
21874
|
-
|
|
21875
|
-
|
|
21771
|
+
this.#affix = !!(this.#prefix.length || this.#suffix.length);
|
|
21772
|
+
if (!nocase) {
|
|
21773
|
+
this.#prefixStr = this.#prefix.map(l => l.ch).join('');
|
|
21774
|
+
this.#suffixStr = this.#suffix.map(l => l.ch).join('');
|
|
21876
21775
|
}
|
|
21877
|
-
|
|
21878
|
-
|
|
21879
|
-
|
|
21880
|
-
|
|
21881
|
-
|
|
21882
|
-
|
|
21776
|
+
this.#linear = linear(this.#start)?.slice(this.#prefix.length, -this.#suffix.length || undefined);
|
|
21777
|
+
this.#wild = !!this.#linear?.every(n => n.t === 'star' || n.t === 'any');
|
|
21778
|
+
const [min, max] = lengths(items);
|
|
21779
|
+
this.#min = min;
|
|
21780
|
+
this.#max = max;
|
|
21781
|
+
}
|
|
21782
|
+
}
|
|
21783
|
+
test(s) {
|
|
21784
|
+
// The `/` check uses the string as given, so with normalization it
|
|
21785
|
+
// is a separate step. Otherwise, one scan finds both a `/` and the
|
|
21786
|
+
// surrogate pairs that stop the string being indexed by code point.
|
|
21787
|
+
if (this.#form) {
|
|
21788
|
+
noSlash(s);
|
|
21789
|
+
return this.#test(s.normalize(this.#form));
|
|
21790
|
+
}
|
|
21791
|
+
if (slashOrSurrogate.test(s)) {
|
|
21792
|
+
noSlash(s);
|
|
21793
|
+
return this.#test(s, [...s]);
|
|
21794
|
+
}
|
|
21795
|
+
return this.#test(s, s);
|
|
21796
|
+
}
|
|
21797
|
+
/**
|
|
21798
|
+
* The same as {@link Matcher#test}, but the string is not checked
|
|
21799
|
+
* for `/` chars, so the result for a string that has one is not
|
|
21800
|
+
* defined. Only use it for a string that is known to be one path
|
|
21801
|
+
* portion, such as a part of a path that was split on `/`. It can
|
|
21802
|
+
* be faster, because some patterns do not need to look at each char
|
|
21803
|
+
* of the string.
|
|
21804
|
+
*/
|
|
21805
|
+
testUnchecked(s) {
|
|
21806
|
+
return this.#test(this.#form ? s.normalize(this.#form) : s);
|
|
21807
|
+
}
|
|
21808
|
+
// Test a string that has no `/`. `chars` indexes it by code point.
|
|
21809
|
+
// If it is not given, it is only found if a step needs it.
|
|
21810
|
+
#test(s, chars) {
|
|
21811
|
+
if (this.#literal !== undefined) {
|
|
21812
|
+
return this.#literalFold ?
|
|
21813
|
+
(this.#literalRe ??= newFoldRe(this.#literal)).test(s)
|
|
21814
|
+
: s === this.#literal;
|
|
21815
|
+
}
|
|
21816
|
+
// the length check means that the prefix and suffix do not
|
|
21817
|
+
// overlap. Without the chars, the length in code points is from
|
|
21818
|
+
// half of the UTF-16 length (if each one is a surrogate pair) to
|
|
21819
|
+
// all of it, which is often enough to know.
|
|
21820
|
+
const min = this.#min;
|
|
21821
|
+
const max = this.#max;
|
|
21822
|
+
if (chars === undefined) {
|
|
21823
|
+
const most = s.length;
|
|
21824
|
+
const least = (most + 1) >> 1;
|
|
21825
|
+
if (most < min || least > max)
|
|
21826
|
+
return false;
|
|
21827
|
+
if (least < min || most > max)
|
|
21828
|
+
chars = codePoints(s);
|
|
21829
|
+
}
|
|
21830
|
+
if (chars !== undefined &&
|
|
21831
|
+
(chars.length < min || chars.length > max)) {
|
|
21832
|
+
return false;
|
|
21833
|
+
}
|
|
21834
|
+
const prefix = this.#prefix.length;
|
|
21835
|
+
if (this.#affix) {
|
|
21836
|
+
if (this.#prefixStr !== undefined && this.#suffixStr !== undefined) {
|
|
21837
|
+
if (!s.startsWith(this.#prefixStr) ||
|
|
21838
|
+
!s.endsWith(this.#suffixStr)) {
|
|
21839
|
+
return false;
|
|
21883
21840
|
}
|
|
21884
|
-
continue;
|
|
21885
21841
|
}
|
|
21886
|
-
|
|
21887
|
-
|
|
21888
|
-
|
|
21889
|
-
|
|
21890
|
-
|
|
21891
|
-
|
|
21892
|
-
hasMagic = hasMagic || magic;
|
|
21893
|
-
continue;
|
|
21842
|
+
else {
|
|
21843
|
+
chars ??= codePoints(s);
|
|
21844
|
+
const end = chars.length - this.#suffix.length;
|
|
21845
|
+
if (!hasAffix(this.#prefix, chars, 0) ||
|
|
21846
|
+
!hasAffix(this.#suffix, chars, end)) {
|
|
21847
|
+
return false;
|
|
21894
21848
|
}
|
|
21895
21849
|
}
|
|
21896
|
-
|
|
21897
|
-
|
|
21898
|
-
|
|
21899
|
-
|
|
21850
|
+
}
|
|
21851
|
+
const dotStart = !this.options.dot && s.startsWith('.');
|
|
21852
|
+
if (this.#linear) {
|
|
21853
|
+
// `.` and `..` only match literal dots, even with `dot:true`
|
|
21854
|
+
if (s === '.' || s === '..')
|
|
21855
|
+
return false;
|
|
21856
|
+
// only a literal can match the leading dot. A `*` can not
|
|
21857
|
+
// start a dotfile, even if it matches nothing.
|
|
21858
|
+
if (dotStart && !prefix)
|
|
21859
|
+
return false;
|
|
21860
|
+
if (this.#wild)
|
|
21861
|
+
return true;
|
|
21862
|
+
chars ??= codePoints(s);
|
|
21863
|
+
const end = chars.length - this.#suffix.length;
|
|
21864
|
+
return testLinear(this.#linear, chars, prefix, end);
|
|
21865
|
+
}
|
|
21866
|
+
chars ??= codePoints(s);
|
|
21867
|
+
if (s === '.' || s === '..') {
|
|
21868
|
+
this.#marks ??= marks(this.#size);
|
|
21869
|
+
const sim = (this.#dotsSim ??= new Sim(true, false, this.#marks));
|
|
21870
|
+
const start = sim.state();
|
|
21871
|
+
sim.add(start, this.#start, 0, true);
|
|
21872
|
+
let state = sim.done(start);
|
|
21873
|
+
for (let i = 0; i < chars.length; i++) {
|
|
21874
|
+
state = sim.step(state, chars[i], i, true);
|
|
21900
21875
|
}
|
|
21901
|
-
|
|
21876
|
+
return state.match;
|
|
21877
|
+
}
|
|
21878
|
+
this.#marks ??= marks(this.#size);
|
|
21879
|
+
const dfa = (this.#dfa ??= new Dfa(this.#start, this.#marks));
|
|
21880
|
+
let d = dfa.start(dotStart);
|
|
21881
|
+
// read char codes from the string, so that a one-char string is
|
|
21882
|
+
// only made for a cache miss
|
|
21883
|
+
const str = chars === s;
|
|
21884
|
+
for (let i = 0; i < chars.length; i++) {
|
|
21885
|
+
if (d.dead)
|
|
21886
|
+
return false;
|
|
21887
|
+
const code = str ? s.charCodeAt(i) : chars[i].charCodeAt(0);
|
|
21888
|
+
d = d.ascii?.[code] ?? dfa.next(d, chars[i]);
|
|
21902
21889
|
}
|
|
21903
|
-
return
|
|
21890
|
+
return d.match;
|
|
21891
|
+
}
|
|
21892
|
+
/** a readable listing of the state machine */
|
|
21893
|
+
toString() {
|
|
21894
|
+
return show(this.#start);
|
|
21904
21895
|
}
|
|
21905
21896
|
}
|
|
21906
|
-
|
|
21897
|
+
|
|
21898
|
+
const MAX_PATTERN_LENGTH = 1024 * 64;
|
|
21899
|
+
const assertValidPattern = (pattern) => {
|
|
21900
|
+
if (typeof pattern !== 'string') {
|
|
21901
|
+
throw new TypeError('invalid pattern');
|
|
21902
|
+
}
|
|
21903
|
+
if (pattern.length > MAX_PATTERN_LENGTH) {
|
|
21904
|
+
throw new TypeError('pattern is too long');
|
|
21905
|
+
}
|
|
21906
|
+
};
|
|
21907
21907
|
|
|
21908
21908
|
/**
|
|
21909
21909
|
* Escape all magic characters in a glob pattern.
|
|
@@ -21931,71 +21931,72 @@ const escape = (s, { windowsPathsNoEscape = false, magicalBraces = false, } = {}
|
|
|
21931
21931
|
: s.replace(/[?*()[\]\\]/g, '\\$&');
|
|
21932
21932
|
};
|
|
21933
21933
|
|
|
21934
|
+
/**
|
|
21935
|
+
* Un-escape a string that has been escaped with {@link escape}.
|
|
21936
|
+
*
|
|
21937
|
+
* If the {@link MinimatchOptions.windowsPathsNoEscape} option is used, then
|
|
21938
|
+
* square-bracket escapes are removed, but not backslash escapes.
|
|
21939
|
+
*
|
|
21940
|
+
* For example, it will turn the string `'[*]'` into `*`, but it will not
|
|
21941
|
+
* turn `'\\*'` into `'*'`, because `\` is a path separator in
|
|
21942
|
+
* `windowsPathsNoEscape` mode.
|
|
21943
|
+
*
|
|
21944
|
+
* When `windowsPathsNoEscape` is not set, then both square-bracket escapes and
|
|
21945
|
+
* backslash escapes are removed.
|
|
21946
|
+
*
|
|
21947
|
+
* Slashes (and backslashes in `windowsPathsNoEscape` mode) cannot be escaped
|
|
21948
|
+
* or unescaped.
|
|
21949
|
+
*
|
|
21950
|
+
* When `magicalBraces` is not set, escapes of braces (`{` and `}`) will not be
|
|
21951
|
+
* unescaped.
|
|
21952
|
+
*/
|
|
21953
|
+
const unescape = (s, { windowsPathsNoEscape = false, magicalBraces = true, } = {}) => {
|
|
21954
|
+
if (magicalBraces) {
|
|
21955
|
+
return windowsPathsNoEscape ?
|
|
21956
|
+
s.replace(/\[([^/\\])\]/g, '$1')
|
|
21957
|
+
: s
|
|
21958
|
+
.replace(/((?!\\).|^)\[([^/\\])\]/g, '$1$2')
|
|
21959
|
+
.replace(/\\([^/])/g, '$1');
|
|
21960
|
+
}
|
|
21961
|
+
return windowsPathsNoEscape ?
|
|
21962
|
+
s.replace(/\[([^/\\{}])\]/g, '$1')
|
|
21963
|
+
: s
|
|
21964
|
+
.replace(/((?!\\).|^)\[([^/\\{}])\]/g, '$1$2')
|
|
21965
|
+
.replace(/\\([^/{}])/g, '$1');
|
|
21966
|
+
};
|
|
21967
|
+
|
|
21934
21968
|
const minimatch = (p, pattern, options = {}) => {
|
|
21935
21969
|
assertValidPattern(pattern);
|
|
21936
21970
|
// shortcut: comments match nothing.
|
|
21937
21971
|
if (!options.nocomment && pattern.charAt(0) === '#') {
|
|
21938
21972
|
return false;
|
|
21939
21973
|
}
|
|
21940
|
-
return
|
|
21941
|
-
};
|
|
21942
|
-
// Optimized checking for the most common glob patterns.
|
|
21943
|
-
const starDotExtRE = /^\*+([^+@!?*[(]*)$/;
|
|
21944
|
-
const starDotExtTest = (ext) => (f) => !f.startsWith('.') && f.endsWith(ext);
|
|
21945
|
-
const starDotExtTestDot = (ext) => (f) => f.endsWith(ext);
|
|
21946
|
-
const starDotExtTestNocase = (ext) => {
|
|
21947
|
-
ext = ext.toLowerCase();
|
|
21948
|
-
return (f) => !f.startsWith('.') && f.toLowerCase().endsWith(ext);
|
|
21974
|
+
return cachedMinimatch(pattern, options).match(p);
|
|
21949
21975
|
};
|
|
21950
|
-
|
|
21951
|
-
|
|
21952
|
-
|
|
21953
|
-
|
|
21954
|
-
const
|
|
21955
|
-
const
|
|
21956
|
-
const
|
|
21957
|
-
|
|
21958
|
-
|
|
21959
|
-
|
|
21960
|
-
|
|
21961
|
-
|
|
21962
|
-
|
|
21963
|
-
|
|
21964
|
-
|
|
21965
|
-
|
|
21966
|
-
|
|
21967
|
-
|
|
21968
|
-
|
|
21969
|
-
|
|
21970
|
-
const qmarksTestNocaseDot = ([$0, ext = '']) => {
|
|
21971
|
-
const noext = qmarksTestNoExtDot([$0]);
|
|
21972
|
-
if (!ext)
|
|
21973
|
-
return noext;
|
|
21974
|
-
ext = ext.toLowerCase();
|
|
21975
|
-
return (f) => noext(f) && f.toLowerCase().endsWith(ext);
|
|
21976
|
-
};
|
|
21977
|
-
const qmarksTestDot = ([$0, ext = '']) => {
|
|
21978
|
-
const noext = qmarksTestNoExtDot([$0]);
|
|
21979
|
-
return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
|
|
21980
|
-
};
|
|
21981
|
-
const qmarksTest = ([$0, ext = '']) => {
|
|
21982
|
-
const noext = qmarksTestNoExt([$0]);
|
|
21983
|
-
return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
|
|
21984
|
-
};
|
|
21985
|
-
const qmarksTestNoExt = ([$0]) => {
|
|
21986
|
-
const len = $0.length;
|
|
21987
|
-
return (f) => f.length === len && !f.startsWith('.');
|
|
21988
|
-
};
|
|
21989
|
-
const qmarksTestNoExtDot = ([$0]) => {
|
|
21990
|
-
const len = $0.length;
|
|
21991
|
-
return (f) => f.length === len && f !== '.' && f !== '..';
|
|
21976
|
+
// The Minimatch objects that minimatch() used most recently. A Map
|
|
21977
|
+
// keeps its keys in the order they were set, so the first key is the
|
|
21978
|
+
// one used least recently.
|
|
21979
|
+
const cache = new Map();
|
|
21980
|
+
const cacheMax = 256;
|
|
21981
|
+
const cachedMinimatch = (pattern, options) => {
|
|
21982
|
+
const key = pattern + '\0' + JSON.stringify(options);
|
|
21983
|
+
let mm = cache.get(key);
|
|
21984
|
+
if (mm) {
|
|
21985
|
+
cache.delete(key);
|
|
21986
|
+
}
|
|
21987
|
+
else {
|
|
21988
|
+
// a copy, so a later change to the options can not change it
|
|
21989
|
+
mm = new Minimatch(pattern, { ...options });
|
|
21990
|
+
if (cache.size >= cacheMax) {
|
|
21991
|
+
cache.delete(cache.keys().next().value);
|
|
21992
|
+
}
|
|
21993
|
+
}
|
|
21994
|
+
cache.set(key, mm);
|
|
21995
|
+
return mm;
|
|
21992
21996
|
};
|
|
21993
21997
|
/* c8 ignore start */
|
|
21994
21998
|
const defaultPlatform = (typeof process === 'object' && process ?
|
|
21995
|
-
|
|
21996
|
-
process.env &&
|
|
21997
|
-
process.env.__MINIMATCH_TESTING_PLATFORM__) ||
|
|
21998
|
-
process.platform
|
|
21999
|
+
process.env?.__MINIMATCH_TESTING_PLATFORM__ || process.platform
|
|
21999
22000
|
: 'posix');
|
|
22000
22001
|
const path = {
|
|
22001
22002
|
win32: { sep: '\\' },
|
|
@@ -22006,18 +22007,6 @@ const sep = defaultPlatform === 'win32' ? path.win32.sep : path.posix.sep;
|
|
|
22006
22007
|
minimatch.sep = sep;
|
|
22007
22008
|
const GLOBSTAR = Symbol('globstar **');
|
|
22008
22009
|
minimatch.GLOBSTAR = GLOBSTAR;
|
|
22009
|
-
// any single thing other than /
|
|
22010
|
-
// don't need to escape / when using new RegExp()
|
|
22011
|
-
const qmark = '[^/]';
|
|
22012
|
-
// * => any number of characters
|
|
22013
|
-
const star = qmark + '*?';
|
|
22014
|
-
// ** when dots are allowed. Anything goes, except .. and .
|
|
22015
|
-
// not (^ or / followed by one or two dots followed by $ or /),
|
|
22016
|
-
// followed by anything, any number of times.
|
|
22017
|
-
const twoStarDot = '(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?';
|
|
22018
|
-
// not a ^ or / followed by a dot,
|
|
22019
|
-
// followed by anything, any number of times.
|
|
22020
|
-
const twoStarNoDot = '(?:(?!(?:\\/|^)\\.).)*?';
|
|
22021
22010
|
const filter = (pattern, options = {}) => (p) => minimatch(p, pattern, options);
|
|
22022
22011
|
minimatch.filter = filter;
|
|
22023
22012
|
const ext = (a, b = {}) => Object.assign({}, a, b);
|
|
@@ -22036,21 +22025,10 @@ const defaults = (def) => {
|
|
|
22036
22025
|
return orig.defaults(ext(def, options)).Minimatch;
|
|
22037
22026
|
}
|
|
22038
22027
|
},
|
|
22039
|
-
AST: class AST extends orig.AST {
|
|
22040
|
-
/* c8 ignore start */
|
|
22041
|
-
constructor(type, parent, options = {}) {
|
|
22042
|
-
super(type, parent, ext(def, options));
|
|
22043
|
-
}
|
|
22044
|
-
/* c8 ignore stop */
|
|
22045
|
-
static fromGlob(pattern, options = {}) {
|
|
22046
|
-
return orig.AST.fromGlob(pattern, ext(def, options));
|
|
22047
|
-
}
|
|
22048
|
-
},
|
|
22049
22028
|
unescape: (s, options = {}) => orig.unescape(s, ext(def, options)),
|
|
22050
22029
|
escape: (s, options = {}) => orig.escape(s, ext(def, options)),
|
|
22051
22030
|
filter: (pattern, options = {}) => orig.filter(pattern, ext(def, options)),
|
|
22052
22031
|
defaults: (options) => orig.defaults(ext(def, options)),
|
|
22053
|
-
makeRe: (pattern, options = {}) => orig.makeRe(pattern, ext(def, options)),
|
|
22054
22032
|
braceExpand: (pattern, options = {}) => orig.braceExpand(pattern, ext(def, options)),
|
|
22055
22033
|
match: (list, pattern, options = {}) => orig.match(list, pattern, ext(def, options)),
|
|
22056
22034
|
sep: orig.sep,
|
|
@@ -22079,19 +22057,6 @@ const braceExpand = (pattern, options = {}) => {
|
|
|
22079
22057
|
return expand(pattern, { max: options.braceExpandMax });
|
|
22080
22058
|
};
|
|
22081
22059
|
minimatch.braceExpand = braceExpand;
|
|
22082
|
-
// parse a component of the expanded set.
|
|
22083
|
-
// At this point, no pattern may contain "/" in it
|
|
22084
|
-
// so we're going to return a 2d array, where each entry is the full
|
|
22085
|
-
// pattern, split on '/', and then turned into a regular expression.
|
|
22086
|
-
// A regexp is made at the end which joins each array with an
|
|
22087
|
-
// escaped /, and another full one which joins each regexp with |.
|
|
22088
|
-
//
|
|
22089
|
-
// Following the lead of Bash 4.1, note that "**" only has special meaning
|
|
22090
|
-
// when it is the *only* thing in a path portion. Otherwise, any series
|
|
22091
|
-
// of * is equivalent to a single *. Globstar behavior is enabled by
|
|
22092
|
-
// default, and can be disabled by setting options.noglobstar.
|
|
22093
|
-
const makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe();
|
|
22094
|
-
minimatch.makeRe = makeRe;
|
|
22095
22060
|
const match = (list, pattern, options = {}) => {
|
|
22096
22061
|
const mm = new Minimatch(pattern, options);
|
|
22097
22062
|
list = list.filter(f => mm.match(f));
|
|
@@ -22101,9 +22066,201 @@ const match = (list, pattern, options = {}) => {
|
|
|
22101
22066
|
return list;
|
|
22102
22067
|
};
|
|
22103
22068
|
minimatch.match = match;
|
|
22104
|
-
// replace stuff like \* with *
|
|
22105
22069
|
const globMagic = /[?*]|[+@!]\(.*?\)|\[|\]/;
|
|
22106
|
-
|
|
22070
|
+
// Index of the `]` that closes the class that starts at `start`,
|
|
22071
|
+
// or -1 if it is not closed. Posix classes such as `[:alpha:]` are
|
|
22072
|
+
// not skipped, so this can find a `]` before the real end. That
|
|
22073
|
+
// only makes a class look less like a literal.
|
|
22074
|
+
const classEnd = (pattern, start) => {
|
|
22075
|
+
let i = start + 1;
|
|
22076
|
+
if (pattern.charAt(i) === '!' || pattern.charAt(i) === '^')
|
|
22077
|
+
i++;
|
|
22078
|
+
let sawStart = false;
|
|
22079
|
+
for (; i < pattern.length; i++) {
|
|
22080
|
+
const c = pattern.charAt(i);
|
|
22081
|
+
if (c === ']' && sawStart)
|
|
22082
|
+
return i;
|
|
22083
|
+
sawStart = true;
|
|
22084
|
+
if (c === '\\')
|
|
22085
|
+
i++;
|
|
22086
|
+
}
|
|
22087
|
+
return -1;
|
|
22088
|
+
};
|
|
22089
|
+
// If a path portion pattern has no magic, return the string it
|
|
22090
|
+
// matches. Otherwise, return undefined. This can report magic for
|
|
22091
|
+
// a pattern that is in fact literal (eg, `[]`), but never the
|
|
22092
|
+
// reverse, so a string result is always safe to compare directly.
|
|
22093
|
+
const literal = (pattern, noext) => {
|
|
22094
|
+
if (!noext && (pattern === '+()' || pattern === '@()'))
|
|
22095
|
+
return pattern;
|
|
22096
|
+
let lit = '';
|
|
22097
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
22098
|
+
const c = pattern.charAt(i);
|
|
22099
|
+
if (c === '\\') {
|
|
22100
|
+
// a trailing \ is a literal \
|
|
22101
|
+
lit += pattern.charAt(++i) || c;
|
|
22102
|
+
}
|
|
22103
|
+
else if (c === '*' || c === '?') {
|
|
22104
|
+
return undefined;
|
|
22105
|
+
}
|
|
22106
|
+
else if (c === '[') {
|
|
22107
|
+
const close = classEnd(pattern, i);
|
|
22108
|
+
if (close === -1) {
|
|
22109
|
+
// not closed, so the [ is a literal
|
|
22110
|
+
lit += c;
|
|
22111
|
+
continue;
|
|
22112
|
+
}
|
|
22113
|
+
// a class of one char, such as `[*]` or `[\b]`, is a literal
|
|
22114
|
+
let body = pattern.slice(i + 1, close);
|
|
22115
|
+
if (body.startsWith('\\'))
|
|
22116
|
+
body = body.slice(1);
|
|
22117
|
+
if ([...body].length !== 1 || '!^'.includes(pattern.charAt(i + 1))) {
|
|
22118
|
+
return undefined;
|
|
22119
|
+
}
|
|
22120
|
+
lit += body;
|
|
22121
|
+
i = close;
|
|
22122
|
+
}
|
|
22123
|
+
else if (!noext &&
|
|
22124
|
+
'+@!'.includes(c) &&
|
|
22125
|
+
pattern.charAt(i + 1) === '(' &&
|
|
22126
|
+
pattern.includes(')', i + 2)) {
|
|
22127
|
+
return undefined;
|
|
22128
|
+
}
|
|
22129
|
+
else {
|
|
22130
|
+
lit += c;
|
|
22131
|
+
}
|
|
22132
|
+
}
|
|
22133
|
+
return lit;
|
|
22134
|
+
};
|
|
22135
|
+
// True if the portion pattern has the same meaning as an alternative
|
|
22136
|
+
// inside `@(...)`. It must not have a `|` or `)` that is not in a
|
|
22137
|
+
// closed extglob (those are literal at the top level), an extglob
|
|
22138
|
+
// that is not closed (the `)` of the `@(...)` would close it), or a
|
|
22139
|
+
// trailing `\` (it would escape the next `|`). A pattern that is
|
|
22140
|
+
// only an empty extglob, such as `?()`, is literal on its own, but
|
|
22141
|
+
// not in `@(...)`. Posix classes such as `[:alpha:]` can hide a `]`
|
|
22142
|
+
// from classEnd, so patterns with them are not merged.
|
|
22143
|
+
const extSafe = (pattern) => {
|
|
22144
|
+
if (/^[?*+@]\(\)$/.test(pattern) || pattern.includes('[:'))
|
|
22145
|
+
return false;
|
|
22146
|
+
let depth = 0;
|
|
22147
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
22148
|
+
const c = pattern.charAt(i);
|
|
22149
|
+
if (c === '\\') {
|
|
22150
|
+
if (++i === pattern.length)
|
|
22151
|
+
return false;
|
|
22152
|
+
}
|
|
22153
|
+
else if (c === '[') {
|
|
22154
|
+
const close = classEnd(pattern, i);
|
|
22155
|
+
if (close !== -1)
|
|
22156
|
+
i = close;
|
|
22157
|
+
}
|
|
22158
|
+
else if ('+@!?*'.includes(c) && pattern.charAt(i + 1) === '(') {
|
|
22159
|
+
depth++;
|
|
22160
|
+
i++;
|
|
22161
|
+
}
|
|
22162
|
+
else if (c === ')') {
|
|
22163
|
+
if (!depth--)
|
|
22164
|
+
return false;
|
|
22165
|
+
}
|
|
22166
|
+
else if (c === '|' && !depth) {
|
|
22167
|
+
return false;
|
|
22168
|
+
}
|
|
22169
|
+
}
|
|
22170
|
+
return !depth;
|
|
22171
|
+
};
|
|
22172
|
+
// The last path that Minimatch#match split, and its parts. A path is
|
|
22173
|
+
// often tested against many patterns in a row (such as a list of
|
|
22174
|
+
// ignore patterns), so this saves splitting it again. The parts are
|
|
22175
|
+
// never changed, so they can be shared.
|
|
22176
|
+
let lastSplit;
|
|
22177
|
+
// The last path that Minimatch#match checked before splitting it. If
|
|
22178
|
+
// the same path is checked again, it is being tested against many
|
|
22179
|
+
// patterns, so it is split and the parts are kept for the others.
|
|
22180
|
+
let lastChecked;
|
|
22181
|
+
// true if a pattern portion that is not ** matches a path portion.
|
|
22182
|
+
// An empty path portion only matches an empty pattern portion. A path
|
|
22183
|
+
// portion never has a `/`, so the Matcher does not need to check it.
|
|
22184
|
+
const portionMatch = (p, f) => typeof p === 'string' ? f === p : f !== '' && p.testUnchecked(f);
|
|
22185
|
+
// Where the last portion of a row matches in a path: the start of the
|
|
22186
|
+
// last portion of the path, or of the one before a trailing `/`. -1 if
|
|
22187
|
+
// it matches neither.
|
|
22188
|
+
const endIndex = (p, last, lastStart, prev, prevStart) => portionMatch(p, last) ? lastStart
|
|
22189
|
+
: prev !== undefined && portionMatch(p, prev) ? prevStart
|
|
22190
|
+
: -1;
|
|
22191
|
+
const isDots = (p) => p === '.' || p === '..';
|
|
22192
|
+
// a Windows drive letter portion, like `c:`
|
|
22193
|
+
const isDrive = (p) => typeof p === 'string' && /^[a-z]:$/i.test(p);
|
|
22194
|
+
// true for the `UNC` portion of a long UNC root, //?/UNC/host/share
|
|
22195
|
+
const isLongUNC = (p) => typeof p === 'string' && /^unc$/i.test(p);
|
|
22196
|
+
// The index of the host in a row or split path that starts with a
|
|
22197
|
+
// Windows UNC root: 2 for `//host/share`, and 4 for
|
|
22198
|
+
// `//?/UNC/host/share`. Otherwise -1. `//?/c:` is not one.
|
|
22199
|
+
const uncHost = (p) => {
|
|
22200
|
+
if (p[0] !== '' || p[1] !== '')
|
|
22201
|
+
return -1;
|
|
22202
|
+
const h = p[2] !== '?' ? 2
|
|
22203
|
+
: isLongUNC(p[3]) ? 4
|
|
22204
|
+
: -1;
|
|
22205
|
+
const host = p[h];
|
|
22206
|
+
const share = p[h + 1];
|
|
22207
|
+
return (h !== -1 &&
|
|
22208
|
+
host !== undefined &&
|
|
22209
|
+
host !== '' &&
|
|
22210
|
+
host !== GLOBSTAR &&
|
|
22211
|
+
share !== undefined &&
|
|
22212
|
+
share !== '' &&
|
|
22213
|
+
share !== GLOBSTAR) ?
|
|
22214
|
+
h
|
|
22215
|
+
: -1;
|
|
22216
|
+
};
|
|
22217
|
+
// true if ** can walk the path portion: not `.` or `..`, and not a
|
|
22218
|
+
// dotfile unless `dot` is set
|
|
22219
|
+
const walkable = (p, dot) => !isDots(p) && (dot || !p.startsWith('.'));
|
|
22220
|
+
// True if a portion of the path from `start` to `end` can not be
|
|
22221
|
+
// walked by **: one that starts with `.`, or with `dot`, one that is
|
|
22222
|
+
// `.` or `..`. `start` is the start of a portion, and `end` is the end
|
|
22223
|
+
// of the path, or just after a separator.
|
|
22224
|
+
const dotPortion = (f, start, end, dot, sep) => {
|
|
22225
|
+
for (let k = start; k < end;) {
|
|
22226
|
+
if (f.charCodeAt(k) === 46) {
|
|
22227
|
+
if (!dot)
|
|
22228
|
+
return true;
|
|
22229
|
+
const n = f.charCodeAt(k + 1) === 46 ? k + 2 : k + 1;
|
|
22230
|
+
if (n >= end || isSep(f.charCodeAt(n), sep))
|
|
22231
|
+
return true;
|
|
22232
|
+
}
|
|
22233
|
+
// the start of the next portion, after any run of separators
|
|
22234
|
+
const s = nextSep(f, k, sep);
|
|
22235
|
+
if (s === -1)
|
|
22236
|
+
return false;
|
|
22237
|
+
k = s + 1;
|
|
22238
|
+
while (k < end && isSep(f.charCodeAt(k), sep))
|
|
22239
|
+
k++;
|
|
22240
|
+
}
|
|
22241
|
+
return false;
|
|
22242
|
+
};
|
|
22243
|
+
const isSep = (c, sep) => sep === '/' ? c === 47
|
|
22244
|
+
: sep === '\\' ? c === 92
|
|
22245
|
+
: c === 47 || c === 92;
|
|
22246
|
+
// the index of the first separator at or after `from`, or -1
|
|
22247
|
+
const nextSep = (f, from, sep) => {
|
|
22248
|
+
if (sep !== 'both')
|
|
22249
|
+
return f.indexOf(sep, from);
|
|
22250
|
+
const s = f.indexOf('/', from);
|
|
22251
|
+
const b = f.indexOf('\\', from);
|
|
22252
|
+
return (s === -1 ? b
|
|
22253
|
+
: b === -1 ? s
|
|
22254
|
+
: Math.min(s, b));
|
|
22255
|
+
};
|
|
22256
|
+
// the index of the last separator at or before `from`, or -1
|
|
22257
|
+
const lastSep = (f, from, sep) => sep !== 'both' ?
|
|
22258
|
+
f.lastIndexOf(sep, from)
|
|
22259
|
+
: Math.max(f.lastIndexOf('/', from), f.lastIndexOf('\\', from));
|
|
22260
|
+
// What parse() returns in place of a Matcher while make() builds and
|
|
22261
|
+
// merges the rows. Most of the Matchers in rows that are merged would
|
|
22262
|
+
// never be used, so they are only made for the rows that are left.
|
|
22263
|
+
const PENDING = {};
|
|
22107
22264
|
class Minimatch {
|
|
22108
22265
|
options;
|
|
22109
22266
|
set;
|
|
@@ -22122,7 +22279,27 @@ class Minimatch {
|
|
|
22122
22279
|
platform;
|
|
22123
22280
|
windowsNoMagicRoot;
|
|
22124
22281
|
maxGlobstarRecursion;
|
|
22125
|
-
|
|
22282
|
+
// the path can be checked against the last portion, and the string
|
|
22283
|
+
// portions, of each row before it is split. See #canMatch.
|
|
22284
|
+
#endCheck;
|
|
22285
|
+
#literalCheck;
|
|
22286
|
+
// level 2 resolves `.` and `..` portions in the path
|
|
22287
|
+
#level2;
|
|
22288
|
+
// the unicode normalization form, if any
|
|
22289
|
+
#form;
|
|
22290
|
+
// the string portions of each row in the set
|
|
22291
|
+
#literals = [];
|
|
22292
|
+
// the rows that #canMatch can match without splitting the path
|
|
22293
|
+
#shapes = [];
|
|
22294
|
+
// the rows whose last portion can be checked against the path's
|
|
22295
|
+
#endRows = [];
|
|
22296
|
+
// brace expansion can make the same portion in many rows, so they
|
|
22297
|
+
// share one Matcher, and the states that it caches
|
|
22298
|
+
#matchers = new Map();
|
|
22299
|
+
// parse() returns PENDING in place of a Matcher
|
|
22300
|
+
#pending = false;
|
|
22301
|
+
// the GlobstarParts of each pattern row, by start index and partial
|
|
22302
|
+
#globstarParts = new WeakMap();
|
|
22126
22303
|
constructor(pattern, options = {}) {
|
|
22127
22304
|
assertValidPattern(pattern);
|
|
22128
22305
|
options = options || {};
|
|
@@ -22139,7 +22316,6 @@ class Minimatch {
|
|
|
22139
22316
|
this.pattern = this.pattern.replace(/\\/g, '/');
|
|
22140
22317
|
}
|
|
22141
22318
|
this.preserveMultipleSlashes = !!options.preserveMultipleSlashes;
|
|
22142
|
-
this.regexp = null;
|
|
22143
22319
|
this.negate = false;
|
|
22144
22320
|
this.nonegate = !!options.nonegate;
|
|
22145
22321
|
this.comment = false;
|
|
@@ -22153,8 +22329,81 @@ class Minimatch {
|
|
|
22153
22329
|
this.globSet = [];
|
|
22154
22330
|
this.globParts = [];
|
|
22155
22331
|
this.set = [];
|
|
22156
|
-
|
|
22332
|
+
this.#endCheck = !this.preserveMultipleSlashes;
|
|
22333
|
+
this.#level2 = (options.optimizationLevel ?? 1) >= 2;
|
|
22334
|
+
const n = options.normalize;
|
|
22335
|
+
this.#form = n === true ? 'NFC' : n || undefined;
|
|
22336
|
+
// make the set of Matchers etc.
|
|
22157
22337
|
this.make();
|
|
22338
|
+
// On Windows, the portions of a row up to its drive letter or UNC
|
|
22339
|
+
// share are skipped or compared without case, if the path has one
|
|
22340
|
+
// too. So the checks only use the portions after it.
|
|
22341
|
+
const drives = this.set.map(row => this.#rootIndex(row));
|
|
22342
|
+
this.#endRows = this.set.map((row, r) => this.#endCheck && row.length - 1 > drives[r]);
|
|
22343
|
+
// with the end check, the last portion is already checked
|
|
22344
|
+
this.#literals = this.set.map((row, r) => {
|
|
22345
|
+
const end = this.#endRows[r] ? row.length - 1 : row.length;
|
|
22346
|
+
const lits = row
|
|
22347
|
+
.slice(drives[r] + 1, end)
|
|
22348
|
+
.filter((p) => typeof p === 'string' && !!p);
|
|
22349
|
+
return [...new Set(lits)];
|
|
22350
|
+
});
|
|
22351
|
+
this.#literalCheck = this.#literals.some(l => l.length);
|
|
22352
|
+
this.#shapes = this.set.map((row, r) => {
|
|
22353
|
+
const [p0, p1, p2] = row;
|
|
22354
|
+
if (this.#endRows[r] && row.length === 2) {
|
|
22355
|
+
if (p0 === GLOBSTAR && p1 !== GLOBSTAR)
|
|
22356
|
+
return 'tail';
|
|
22357
|
+
}
|
|
22358
|
+
// the basename of a path that is split on / is its last portion,
|
|
22359
|
+
// or the one before a trailing /, the same as the end check
|
|
22360
|
+
if (this.#endRows[r] &&
|
|
22361
|
+
options.matchBase &&
|
|
22362
|
+
row.length === 1 &&
|
|
22363
|
+
p0 !== GLOBSTAR &&
|
|
22364
|
+
p0 !== '') {
|
|
22365
|
+
return 'base';
|
|
22366
|
+
}
|
|
22367
|
+
// the portion must not be a root, or '', which can be a
|
|
22368
|
+
// different portion on Windows (where //x paths get an extra '')
|
|
22369
|
+
if (!this.#endCheck || drives[r] !== -1)
|
|
22370
|
+
return undefined;
|
|
22371
|
+
if (row.length === 3 &&
|
|
22372
|
+
p0 === GLOBSTAR &&
|
|
22373
|
+
p2 === GLOBSTAR &&
|
|
22374
|
+
p1 !== GLOBSTAR &&
|
|
22375
|
+
p1 !== '' &&
|
|
22376
|
+
// the portion between is only matched below this limit
|
|
22377
|
+
this.maxGlobstarRecursion > 0) {
|
|
22378
|
+
return 'mid';
|
|
22379
|
+
}
|
|
22380
|
+
if (row.length === 2 &&
|
|
22381
|
+
p1 === GLOBSTAR &&
|
|
22382
|
+
p0 !== GLOBSTAR &&
|
|
22383
|
+
p0 !== '') {
|
|
22384
|
+
return 'head';
|
|
22385
|
+
}
|
|
22386
|
+
return undefined;
|
|
22387
|
+
});
|
|
22388
|
+
}
|
|
22389
|
+
// a string portion of a pattern, normalized if the option is set
|
|
22390
|
+
#norm(p) {
|
|
22391
|
+
return this.#form ? p.normalize(this.#form) : p;
|
|
22392
|
+
}
|
|
22393
|
+
// On Windows, the index of the last root portion of a row, as
|
|
22394
|
+
// #matchRow finds it: 0 for `c:/...`, 3 for `//?/c:/...` and
|
|
22395
|
+
// `//host/share/...`, and 5 for `//?/UNC/host/share/...`. Otherwise
|
|
22396
|
+
// -1.
|
|
22397
|
+
#rootIndex(row) {
|
|
22398
|
+
if (!this.isWindows)
|
|
22399
|
+
return -1;
|
|
22400
|
+
if (isDrive(row[0]))
|
|
22401
|
+
return 0;
|
|
22402
|
+
const uncDrive = row[0] === '' && row[1] === '' && row[2] === '?' && isDrive(row[3]);
|
|
22403
|
+
if (uncDrive)
|
|
22404
|
+
return 3;
|
|
22405
|
+
const h = uncHost(row);
|
|
22406
|
+
return h === -1 ? -1 : h + 1;
|
|
22158
22407
|
}
|
|
22159
22408
|
hasMagic() {
|
|
22160
22409
|
if (this.options.magicalBraces && this.set.length > 1) {
|
|
@@ -22168,7 +22417,6 @@ class Minimatch {
|
|
|
22168
22417
|
}
|
|
22169
22418
|
return false;
|
|
22170
22419
|
}
|
|
22171
|
-
debug(..._) { }
|
|
22172
22420
|
make() {
|
|
22173
22421
|
const pattern = this.pattern;
|
|
22174
22422
|
const options = this.options;
|
|
@@ -22185,45 +22433,44 @@ class Minimatch {
|
|
|
22185
22433
|
this.parseNegate();
|
|
22186
22434
|
// step 2: expand braces
|
|
22187
22435
|
this.globSet = [...new Set(this.braceExpand())];
|
|
22188
|
-
if (options.debug) {
|
|
22189
|
-
//oxlint-disable-next-line no-console
|
|
22190
|
-
this.debug = (...args) => console.error(...args);
|
|
22191
|
-
}
|
|
22192
|
-
this.debug(this.pattern, this.globSet);
|
|
22193
22436
|
// step 3: now we have a set, so turn each one into a series of
|
|
22194
22437
|
// path-portion matching patterns.
|
|
22195
|
-
// These will be
|
|
22438
|
+
// These will be Matchers, except in the case of "**", which is
|
|
22196
22439
|
// set to the GLOBSTAR object for globstar behavior,
|
|
22197
22440
|
// and will not contain any / characters
|
|
22198
22441
|
//
|
|
22199
22442
|
// First, we preprocess to make the glob pattern sets a bit simpler
|
|
22200
22443
|
// and deduped. There are some perf-killing patterns that can cause
|
|
22201
22444
|
// problems with a glob walk, but we can simplify them down a bit.
|
|
22202
|
-
const rawGlobParts = this.globSet.map(s => this
|
|
22445
|
+
const rawGlobParts = this.globSet.map(s => this.#slashSplit(s));
|
|
22203
22446
|
this.globParts = this.preprocess(rawGlobParts);
|
|
22204
|
-
|
|
22205
|
-
|
|
22447
|
+
// glob --> Matchers
|
|
22448
|
+
this.#pending = true;
|
|
22206
22449
|
let set = this.globParts.map((s, _, __) => {
|
|
22207
22450
|
if (this.isWindows && this.windowsNoMagicRoot) {
|
|
22208
|
-
// check if it's a drive or unc path.
|
|
22451
|
+
// check if it's a drive or unc path. The root of a long UNC
|
|
22452
|
+
// path, //?/UNC/host/share, is 6 portions.
|
|
22453
|
+
const n = s[2] === '?' && isLongUNC(s[3]) ? 6 : 4;
|
|
22209
22454
|
const isUNC = s[0] === '' &&
|
|
22210
22455
|
s[1] === '' &&
|
|
22211
22456
|
(s[2] === '?' || !globMagic.test(s[2])) &&
|
|
22212
|
-
!globMagic.test(
|
|
22457
|
+
s.slice(3, n).every(p => !globMagic.test(p));
|
|
22213
22458
|
const isDrive = /^[a-z]:/i.test(s[0]);
|
|
22214
22459
|
if (isUNC) {
|
|
22215
22460
|
return [
|
|
22216
|
-
...s.slice(0,
|
|
22217
|
-
...s.slice(
|
|
22461
|
+
...s.slice(0, n).map(p => this.#norm(p)),
|
|
22462
|
+
...s.slice(n).map(ss => this.parse(ss)),
|
|
22218
22463
|
];
|
|
22219
22464
|
}
|
|
22220
22465
|
else if (isDrive) {
|
|
22221
|
-
return [
|
|
22466
|
+
return [
|
|
22467
|
+
this.#norm(s[0]),
|
|
22468
|
+
...s.slice(1).map(ss => this.parse(ss)),
|
|
22469
|
+
];
|
|
22222
22470
|
}
|
|
22223
22471
|
}
|
|
22224
22472
|
return s.map(ss => this.parse(ss));
|
|
22225
22473
|
});
|
|
22226
|
-
this.debug(this.pattern, set);
|
|
22227
22474
|
// filter out everything that didn't compile properly.
|
|
22228
22475
|
this.set = set.filter(s => s.indexOf(false) === -1);
|
|
22229
22476
|
// do not treat the ? in UNC paths as magic
|
|
@@ -22233,13 +22480,70 @@ class Minimatch {
|
|
|
22233
22480
|
if (p[0] === '' &&
|
|
22234
22481
|
p[1] === '' &&
|
|
22235
22482
|
this.globParts[i][2] === '?' &&
|
|
22236
|
-
|
|
22237
|
-
|
|
22483
|
+
(isDrive(p[3]) || isLongUNC(this.globParts[i][3]))) {
|
|
22484
|
+
if (isLongUNC(this.globParts[i][3]))
|
|
22485
|
+
p[3] = 'UNC';
|
|
22238
22486
|
p[2] = '?';
|
|
22239
22487
|
}
|
|
22240
22488
|
}
|
|
22241
22489
|
}
|
|
22242
|
-
|
|
22490
|
+
// with noext, `@(...)` would be literal
|
|
22491
|
+
if (!options.noext)
|
|
22492
|
+
this.mergeRows();
|
|
22493
|
+
this.#pending = false;
|
|
22494
|
+
this.set.forEach((row, i) => {
|
|
22495
|
+
for (let k = 0; k < row.length; k++) {
|
|
22496
|
+
if (row[k] === PENDING) {
|
|
22497
|
+
row[k] = this.parse(this.globParts[i][k]);
|
|
22498
|
+
}
|
|
22499
|
+
}
|
|
22500
|
+
});
|
|
22501
|
+
}
|
|
22502
|
+
// Merge rows that only differ in one portion, where each of them
|
|
22503
|
+
// is a Matcher, into one row that matches any of them with
|
|
22504
|
+
// `@(a|b|...)`. Then a path is only walked once for all of them,
|
|
22505
|
+
// for example with `**/*.{js,ts}`.
|
|
22506
|
+
mergeRows() {
|
|
22507
|
+
let merged = true;
|
|
22508
|
+
while (merged) {
|
|
22509
|
+
merged = false;
|
|
22510
|
+
const len = Math.max(0, ...this.set.map(r => r.length));
|
|
22511
|
+
for (let k = 0; k < len; k++) {
|
|
22512
|
+
// the rows that are the same other than at portion k
|
|
22513
|
+
const groups = new Map();
|
|
22514
|
+
this.set.forEach((row, i) => {
|
|
22515
|
+
if (!(row[k] instanceof Matcher || row[k] === PENDING) ||
|
|
22516
|
+
!extSafe(this.globParts[i][k])) {
|
|
22517
|
+
return;
|
|
22518
|
+
}
|
|
22519
|
+
const parts = [...this.globParts[i]];
|
|
22520
|
+
parts[k] = '';
|
|
22521
|
+
const key = `${row.length}/${parts.join('/')}`;
|
|
22522
|
+
const g = groups.get(key);
|
|
22523
|
+
if (g)
|
|
22524
|
+
g.push(i);
|
|
22525
|
+
else
|
|
22526
|
+
groups.set(key, [i]);
|
|
22527
|
+
});
|
|
22528
|
+
const drop = new Set();
|
|
22529
|
+
for (const g of groups.values()) {
|
|
22530
|
+
if (g.length < 2)
|
|
22531
|
+
continue;
|
|
22532
|
+
const [first, ...rest] = g;
|
|
22533
|
+
const alts = g.map(i => this.globParts[i][k]);
|
|
22534
|
+
const glob = `@(${alts.join('|')})`;
|
|
22535
|
+
this.globParts[first][k] = glob;
|
|
22536
|
+
this.set[first][k] = this.parse(glob);
|
|
22537
|
+
for (const i of rest)
|
|
22538
|
+
drop.add(i);
|
|
22539
|
+
}
|
|
22540
|
+
if (drop.size) {
|
|
22541
|
+
merged = true;
|
|
22542
|
+
this.set = this.set.filter((_, i) => !drop.has(i));
|
|
22543
|
+
this.globParts = this.globParts.filter((_, i) => !drop.has(i));
|
|
22544
|
+
}
|
|
22545
|
+
}
|
|
22546
|
+
}
|
|
22243
22547
|
}
|
|
22244
22548
|
// various transforms to equivalent pattern sets that are
|
|
22245
22549
|
// faster to process in a filesystem walk. The goal is to
|
|
@@ -22292,13 +22596,19 @@ class Minimatch {
|
|
|
22292
22596
|
// get rid of adjascent ** and resolve .. portions
|
|
22293
22597
|
levelOneOptimize(globParts) {
|
|
22294
22598
|
return globParts.map(parts => {
|
|
22599
|
+
// .. can not remove the root of a Windows path
|
|
22600
|
+
const root = this.#rootIndex(parts) + 1;
|
|
22295
22601
|
parts = parts.reduce((set, part) => {
|
|
22296
22602
|
const prev = set[set.length - 1];
|
|
22297
22603
|
if (part === '**' && prev === '**') {
|
|
22298
22604
|
return set;
|
|
22299
22605
|
}
|
|
22300
22606
|
if (part === '..') {
|
|
22301
|
-
if (
|
|
22607
|
+
if (set.length > root &&
|
|
22608
|
+
prev &&
|
|
22609
|
+
prev !== '..' &&
|
|
22610
|
+
prev !== '.' &&
|
|
22611
|
+
prev !== '**') {
|
|
22302
22612
|
set.pop();
|
|
22303
22613
|
return set;
|
|
22304
22614
|
}
|
|
@@ -22309,10 +22619,214 @@ class Minimatch {
|
|
|
22309
22619
|
return parts.length === 0 ? [''] : parts;
|
|
22310
22620
|
});
|
|
22311
22621
|
}
|
|
22312
|
-
|
|
22313
|
-
|
|
22314
|
-
|
|
22622
|
+
// Check the path against each row before it is split. 'no' if no
|
|
22623
|
+
// row can match, so it does not need to be split. 'yes' if a row of
|
|
22624
|
+
// `**` and one more portion matches. 'maybe' if it must be split to
|
|
22625
|
+
// know. None of this applies with partial, where the path can end
|
|
22626
|
+
// before the row does.
|
|
22627
|
+
//
|
|
22628
|
+
// On Windows, `\` is a separator in the path too, and the portions of
|
|
22629
|
+
// a row up to its drive letter or UNC share are not checked (see
|
|
22630
|
+
// #rootIndex).
|
|
22631
|
+
//
|
|
22632
|
+
// Each string portion of a row must be a portion of the path, so the
|
|
22633
|
+
// path must contain it. Level 2 can only take portions out of the
|
|
22634
|
+
// path, so this is still true then.
|
|
22635
|
+
//
|
|
22636
|
+
// The last portion of a row must match the last portion of the path,
|
|
22637
|
+
// or the one before a trailing `/` (as a/* and a/**/* match a/b/).
|
|
22638
|
+
// This does not apply to rows that end in **, rows that end in a
|
|
22639
|
+
// root, or preserveMultipleSlashes (which can leave more
|
|
22640
|
+
// than one '' at the end). At level 2, it does not apply if that
|
|
22641
|
+
// portion is `.` or `..`, which can be
|
|
22642
|
+
// resolved away. Level 2 only takes other portions out of the
|
|
22643
|
+
// middle of the path.
|
|
22644
|
+
//
|
|
22645
|
+
// A row of `**/x` then matches if the ** can walk the portions
|
|
22646
|
+
// before the one that x matches, the same as #matchGlobstar. At
|
|
22647
|
+
// level 2, this is only known if none of them are `.` or `..`, so
|
|
22648
|
+
// that the path does not change when it is resolved.
|
|
22649
|
+
#canMatch(f) {
|
|
22650
|
+
const sep = !this.isWindows || !f.includes('\\') ? '/'
|
|
22651
|
+
: f.includes('/') ? 'both'
|
|
22652
|
+
: '\\';
|
|
22653
|
+
// the portions that f.split(/\/+/) would end with, and where they
|
|
22654
|
+
// start in f, found when a row needs them. `ends` is 0 until they
|
|
22655
|
+
// are found, then 1, or -1 if they can not be used.
|
|
22656
|
+
let ends = this.#endCheck ? 0 : -1;
|
|
22657
|
+
let last = '';
|
|
22658
|
+
let lastStart = 0;
|
|
22659
|
+
let prev;
|
|
22660
|
+
let prevStart = 0;
|
|
22661
|
+
const dot = !!this.options.dot;
|
|
22662
|
+
// A string compare is cheaper than includes(), and a Matcher test
|
|
22663
|
+
// costs more, so the cheaper check goes first.
|
|
22664
|
+
ROWS: for (let r = 0; r < this.set.length; r++) {
|
|
22665
|
+
const row = this.set[r];
|
|
22666
|
+
const p = row[row.length - 1];
|
|
22667
|
+
let end = ends !== -1 && this.#endRows[r] && p !== GLOBSTAR;
|
|
22668
|
+
if (end && ends === 0) {
|
|
22669
|
+
const i = lastSep(f, f.length, sep);
|
|
22670
|
+
lastStart = i + 1;
|
|
22671
|
+
last = f.slice(lastStart);
|
|
22672
|
+
if (last === '' && i >= 0) {
|
|
22673
|
+
let j = i;
|
|
22674
|
+
while (j > 0 && isSep(f.charCodeAt(j - 1), sep))
|
|
22675
|
+
j--;
|
|
22676
|
+
prevStart = j === 0 ? 0 : lastSep(f, j - 1, sep) + 1;
|
|
22677
|
+
prev = f.slice(prevStart, j);
|
|
22678
|
+
}
|
|
22679
|
+
const resolves = this.#level2 &&
|
|
22680
|
+
(isDots(last) ||
|
|
22681
|
+
(last === '' && prev !== undefined && isDots(prev)));
|
|
22682
|
+
ends = resolves ? -1 : 1;
|
|
22683
|
+
end = !resolves;
|
|
22684
|
+
}
|
|
22685
|
+
let tailStart = -1;
|
|
22686
|
+
if (end && typeof p === 'string') {
|
|
22687
|
+
tailStart = endIndex(p, last, lastStart, prev, prevStart);
|
|
22688
|
+
if (tailStart === -1)
|
|
22689
|
+
continue;
|
|
22690
|
+
}
|
|
22691
|
+
if (this.#literalCheck) {
|
|
22692
|
+
for (const l of this.#literals[r]) {
|
|
22693
|
+
if (!f.includes(l))
|
|
22694
|
+
continue ROWS;
|
|
22695
|
+
}
|
|
22696
|
+
}
|
|
22697
|
+
if (end && typeof p === 'object') {
|
|
22698
|
+
tailStart = endIndex(p, last, lastStart, prev, prevStart);
|
|
22699
|
+
if (tailStart === -1)
|
|
22700
|
+
continue;
|
|
22701
|
+
}
|
|
22702
|
+
const shape = this.#shapes[r];
|
|
22703
|
+
if (shape === 'base' && end)
|
|
22704
|
+
return 'yes';
|
|
22705
|
+
if (shape === 'tail' && end) {
|
|
22706
|
+
if (this.#level2 && dotPortion(f, 0, tailStart, true, sep)) {
|
|
22707
|
+
return 'maybe';
|
|
22708
|
+
}
|
|
22709
|
+
if (!dotPortion(f, 0, tailStart, dot, sep))
|
|
22710
|
+
return 'yes';
|
|
22711
|
+
continue;
|
|
22712
|
+
}
|
|
22713
|
+
if (shape === 'mid' || shape === 'head') {
|
|
22714
|
+
const m = this.#walk(f, row, shape === 'head', dot, sep);
|
|
22715
|
+
if (m !== 'no')
|
|
22716
|
+
return m;
|
|
22717
|
+
continue;
|
|
22718
|
+
}
|
|
22719
|
+
return 'maybe';
|
|
22720
|
+
}
|
|
22721
|
+
return 'no';
|
|
22722
|
+
}
|
|
22723
|
+
// Match a row of a known shape against the split path, the same as
|
|
22724
|
+
// #matchGlobstar and #matchGlobStarBodySections do. None of these
|
|
22725
|
+
// rows have a drive letter, so they start at the first portion.
|
|
22726
|
+
#matchShape(file, row, shape) {
|
|
22727
|
+
const dot = !!this.options.dot;
|
|
22728
|
+
const n = file.length;
|
|
22729
|
+
if (shape === 'head') {
|
|
22730
|
+
// x, then at least one portion that ** can walk
|
|
22731
|
+
if (n < 2 || !portionMatch(row[0], file[0])) {
|
|
22732
|
+
return false;
|
|
22733
|
+
}
|
|
22734
|
+
for (let i = 1; i < n; i++)
|
|
22735
|
+
if (!walkable(file[i], dot))
|
|
22736
|
+
return false;
|
|
22737
|
+
return true;
|
|
22315
22738
|
}
|
|
22739
|
+
const x = row[1];
|
|
22740
|
+
if (shape === 'tail') {
|
|
22741
|
+
// x is the last portion, or the one before a trailing ''
|
|
22742
|
+
let t = n - 1;
|
|
22743
|
+
if (!portionMatch(x, file[t])) {
|
|
22744
|
+
if (file[t] !== '' || n === 1 || !portionMatch(x, file[--t])) {
|
|
22745
|
+
return false;
|
|
22746
|
+
}
|
|
22747
|
+
}
|
|
22748
|
+
for (let i = 0; i < t; i++)
|
|
22749
|
+
if (!walkable(file[i], dot))
|
|
22750
|
+
return false;
|
|
22751
|
+
return true;
|
|
22752
|
+
}
|
|
22753
|
+
// mid: the first x that ** can walk to, with a portion after it,
|
|
22754
|
+
// and ** can walk all of those
|
|
22755
|
+
for (let k = 0; k < n; k++) {
|
|
22756
|
+
if (portionMatch(x, file[k]) && k + 1 < n) {
|
|
22757
|
+
let i = k + 1;
|
|
22758
|
+
while (i < n && walkable(file[i], dot))
|
|
22759
|
+
i++;
|
|
22760
|
+
if (i === n)
|
|
22761
|
+
return true;
|
|
22762
|
+
}
|
|
22763
|
+
if (!walkable(file[k], dot))
|
|
22764
|
+
return false;
|
|
22765
|
+
}
|
|
22766
|
+
return false;
|
|
22767
|
+
}
|
|
22768
|
+
// Match a row of `**/x/**` or `x/**` against the path, the same as
|
|
22769
|
+
// #matchGlobstar and #matchGlobStarBodySections do once it is split.
|
|
22770
|
+
// x must match a portion (the first one, for `x/**`), the ** before
|
|
22771
|
+
// it must be able to walk the portions before that one, and there
|
|
22772
|
+
// must be a portion after it, which the ** after it can walk. At
|
|
22773
|
+
// level 2, this is only known if no portion is `.` or `..`.
|
|
22774
|
+
#walk(f, row, head, dot, sep) {
|
|
22775
|
+
if (this.#level2 && dotPortion(f, 0, f.length, true, sep))
|
|
22776
|
+
return 'maybe';
|
|
22777
|
+
const x = row[head ? 0 : 1];
|
|
22778
|
+
// the last portion has none after it, so it can not be x
|
|
22779
|
+
let s = 0;
|
|
22780
|
+
for (let e = nextSep(f, s, sep); e !== -1; e = nextSep(f, s, sep)) {
|
|
22781
|
+
// the start of the next portion
|
|
22782
|
+
let next = e + 1;
|
|
22783
|
+
while (next < f.length && isSep(f.charCodeAt(next), sep))
|
|
22784
|
+
next++;
|
|
22785
|
+
const hit = typeof x === 'string' ?
|
|
22786
|
+
e - s === x.length && f.startsWith(x, s)
|
|
22787
|
+
: e > s && x.testUnchecked(f.slice(s, e));
|
|
22788
|
+
if (hit && !dotPortion(f, next, f.length, dot, sep))
|
|
22789
|
+
return 'yes';
|
|
22790
|
+
if (head || dotPortion(f, s, next, dot, sep))
|
|
22791
|
+
return 'no';
|
|
22792
|
+
s = next;
|
|
22793
|
+
}
|
|
22794
|
+
return 'no';
|
|
22795
|
+
}
|
|
22796
|
+
// the last split, if it was the same path with the same split
|
|
22797
|
+
// settings
|
|
22798
|
+
#cachedSplit(f) {
|
|
22799
|
+
const last = lastSplit;
|
|
22800
|
+
return (last?.f === f &&
|
|
22801
|
+
last.isWindows === this.isWindows &&
|
|
22802
|
+
last.preserveMultipleSlashes === this.preserveMultipleSlashes &&
|
|
22803
|
+
last.normalize === this.#form) ?
|
|
22804
|
+
last
|
|
22805
|
+
: undefined;
|
|
22806
|
+
}
|
|
22807
|
+
// split a path for match(), and keep the parts for the next call
|
|
22808
|
+
#split(f) {
|
|
22809
|
+
const { isWindows, preserveMultipleSlashes } = this;
|
|
22810
|
+
// windows: need to use /, not \
|
|
22811
|
+
let parts = this.#slashSplit(isWindows ? f.split('\\').join('/') : f);
|
|
22812
|
+
// normalize each portion, so that a char that normalizes to `/`
|
|
22813
|
+
// does not make a new portion
|
|
22814
|
+
const normalize = this.#form;
|
|
22815
|
+
if (normalize)
|
|
22816
|
+
parts = parts.map(p => p.normalize(normalize));
|
|
22817
|
+
lastSplit = {
|
|
22818
|
+
f,
|
|
22819
|
+
isWindows,
|
|
22820
|
+
preserveMultipleSlashes,
|
|
22821
|
+
normalize,
|
|
22822
|
+
parts,
|
|
22823
|
+
};
|
|
22824
|
+
return lastSplit;
|
|
22825
|
+
}
|
|
22826
|
+
// resolve `.` and `..` portions of a path, for level 2
|
|
22827
|
+
#levelTwoFileOptimize(file) {
|
|
22828
|
+
// work on a copy, so that the cached parts do not change
|
|
22829
|
+
const parts = [...file];
|
|
22316
22830
|
let didSomething = false;
|
|
22317
22831
|
do {
|
|
22318
22832
|
didSomething = false;
|
|
@@ -22337,17 +22851,15 @@ class Minimatch {
|
|
|
22337
22851
|
}
|
|
22338
22852
|
}
|
|
22339
22853
|
// <pre>/<p>/../<rest> -> <pre>/<rest>
|
|
22340
|
-
|
|
22854
|
+
// .. can not remove the root of a Windows path
|
|
22855
|
+
const root = this.#rootIndex(parts) + 1;
|
|
22856
|
+
let dd = root;
|
|
22341
22857
|
while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
|
|
22342
22858
|
const p = parts[dd - 1];
|
|
22343
|
-
if (p &&
|
|
22344
|
-
p !== '.' &&
|
|
22345
|
-
p !== '..' &&
|
|
22346
|
-
p !== '**' &&
|
|
22347
|
-
!(this.isWindows && /^[a-z]:$/i.test(p))) {
|
|
22859
|
+
if (p && p !== '.' && p !== '..' && p !== '**') {
|
|
22348
22860
|
didSomething = true;
|
|
22349
22861
|
parts.splice(dd - 1, 2);
|
|
22350
|
-
dd
|
|
22862
|
+
dd = Math.max(dd - 2, root);
|
|
22351
22863
|
}
|
|
22352
22864
|
}
|
|
22353
22865
|
} while (didSomething);
|
|
@@ -22372,6 +22884,8 @@ class Minimatch {
|
|
|
22372
22884
|
// **/*/<rest> -> */**/<rest> <== not valid because ** doesn't follow
|
|
22373
22885
|
// this WOULD be allowed if ** did follow symlinks, or * didn't
|
|
22374
22886
|
firstPhasePreProcess(globParts) {
|
|
22887
|
+
// each **/.. split doubles the patterns, so stop at the brace max
|
|
22888
|
+
const { braceExpandMax = 100_000 } = this.options;
|
|
22375
22889
|
let didSomething = false;
|
|
22376
22890
|
do {
|
|
22377
22891
|
didSomething = false;
|
|
@@ -22399,7 +22913,8 @@ class Minimatch {
|
|
|
22399
22913
|
p === '..' ||
|
|
22400
22914
|
!p2 ||
|
|
22401
22915
|
p2 === '.' ||
|
|
22402
|
-
p2 === '..'
|
|
22916
|
+
p2 === '..' ||
|
|
22917
|
+
globParts.length >= braceExpandMax) {
|
|
22403
22918
|
continue;
|
|
22404
22919
|
}
|
|
22405
22920
|
didSomething = true;
|
|
@@ -22431,7 +22946,9 @@ class Minimatch {
|
|
|
22431
22946
|
}
|
|
22432
22947
|
}
|
|
22433
22948
|
// <pre>/<p>/../<rest> -> <pre>/<rest>
|
|
22434
|
-
|
|
22949
|
+
// .. can not remove the root of a Windows path
|
|
22950
|
+
const root = this.#rootIndex(parts) + 1;
|
|
22951
|
+
let dd = root;
|
|
22435
22952
|
while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
|
|
22436
22953
|
const p = parts[dd - 1];
|
|
22437
22954
|
if (p && p !== '.' && p !== '..' && p !== '**') {
|
|
@@ -22441,7 +22958,7 @@ class Minimatch {
|
|
|
22441
22958
|
parts.splice(dd - 1, 2, ...splin);
|
|
22442
22959
|
if (parts.length === 0)
|
|
22443
22960
|
parts.push('');
|
|
22444
|
-
dd
|
|
22961
|
+
dd = Math.max(dd - 2, root);
|
|
22445
22962
|
}
|
|
22446
22963
|
}
|
|
22447
22964
|
}
|
|
@@ -22456,6 +22973,10 @@ class Minimatch {
|
|
|
22456
22973
|
// {<pre>/**/<rest>,<pre>/**/<p>/<rest>} -> <pre>/**/<rest>
|
|
22457
22974
|
// ^-- not valid because ** doens't follow symlinks
|
|
22458
22975
|
secondPhasePreProcess(globParts) {
|
|
22976
|
+
// each pattern is compared to each other one, so skip this for
|
|
22977
|
+
// large sets. The patterns match the same paths either way.
|
|
22978
|
+
if (globParts.length > 1000)
|
|
22979
|
+
return globParts;
|
|
22459
22980
|
for (let i = 0; i < globParts.length - 1; i++) {
|
|
22460
22981
|
for (let j = i + 1; j < globParts.length; j++) {
|
|
22461
22982
|
const matched = this.partsMatch(globParts[i], globParts[j], !this.preserveMultipleSlashes);
|
|
@@ -22531,18 +23052,36 @@ class Minimatch {
|
|
|
22531
23052
|
this.pattern = pattern.slice(negateOffset);
|
|
22532
23053
|
this.negate = negate;
|
|
22533
23054
|
}
|
|
22534
|
-
//
|
|
22535
|
-
//
|
|
22536
|
-
//
|
|
22537
|
-
//
|
|
22538
|
-
//
|
|
22539
|
-
|
|
23055
|
+
// Match the parts of a path against one row of the set. `resolved`
|
|
23056
|
+
// is the parts after level 2 resolves `.` and `..` in them, or the
|
|
23057
|
+
// same parts below level 2. Set partial to true to test if, for
|
|
23058
|
+
// example, "/a/b" matches the start of "/*/b/*/d". Partial means, if
|
|
23059
|
+
// you run out of file before you run out of pattern, then that's
|
|
23060
|
+
// fine, as long as all the parts match.
|
|
23061
|
+
#matchRow(file, resolved, pattern, partial) {
|
|
22540
23062
|
let fileStartIndex = 0;
|
|
22541
23063
|
let patternStartIndex = 0;
|
|
22542
|
-
// UNC paths like //?/X:/... can match X:/... and vice versa
|
|
22543
|
-
//
|
|
22544
|
-
//
|
|
22545
|
-
|
|
23064
|
+
// UNC paths like //?/X:/... can match X:/... and vice versa, and
|
|
23065
|
+
// //?/UNC/host/share/... can match //host/share/... and vice versa.
|
|
23066
|
+
// Drive letters in absolute drive or unc paths, and the host and
|
|
23067
|
+
// share of UNC paths, are always compared case-insensitively.
|
|
23068
|
+
const fh = this.isWindows ? uncHost(resolved) : -1;
|
|
23069
|
+
const ph = fh === -1 ? -1 : uncHost(pattern);
|
|
23070
|
+
if (ph !== -1) {
|
|
23071
|
+
const host = pattern[ph];
|
|
23072
|
+
const share = pattern[ph + 1];
|
|
23073
|
+
if (typeof host !== 'string' || typeof share !== 'string') {
|
|
23074
|
+
// a host or share with magic is matched as usual
|
|
23075
|
+
fileStartIndex = fh;
|
|
23076
|
+
patternStartIndex = ph;
|
|
23077
|
+
}
|
|
23078
|
+
else if (resolved[fh].toLowerCase() === host.toLowerCase() &&
|
|
23079
|
+
resolved[fh + 1].toLowerCase() === share.toLowerCase()) {
|
|
23080
|
+
fileStartIndex = fh + 2;
|
|
23081
|
+
patternStartIndex = ph + 2;
|
|
23082
|
+
}
|
|
23083
|
+
}
|
|
23084
|
+
else if (this.isWindows) {
|
|
22546
23085
|
const fileDrive = typeof file[0] === 'string' && /^[a-z]:$/i.test(file[0]);
|
|
22547
23086
|
const fileUNC = !fileDrive &&
|
|
22548
23087
|
file[0] === '' &&
|
|
@@ -22567,47 +23106,27 @@ class Minimatch {
|
|
|
22567
23106
|
file[fdi],
|
|
22568
23107
|
pattern[pdi],
|
|
22569
23108
|
];
|
|
22570
|
-
//
|
|
23109
|
+
// the drives match, so start matching after them
|
|
22571
23110
|
if (fd.toLowerCase() === pd.toLowerCase()) {
|
|
22572
|
-
|
|
22573
|
-
|
|
22574
|
-
fileStartIndex = fdi;
|
|
23111
|
+
patternStartIndex = pdi + 1;
|
|
23112
|
+
fileStartIndex = fdi + 1;
|
|
22575
23113
|
}
|
|
22576
23114
|
}
|
|
22577
23115
|
}
|
|
22578
|
-
//
|
|
22579
|
-
//
|
|
22580
|
-
|
|
22581
|
-
if (optimizationLevel >= 2) {
|
|
22582
|
-
file = this.levelTwoFileOptimize(file);
|
|
22583
|
-
}
|
|
23116
|
+
// the drive letters are found in the parts before level 2 resolves
|
|
23117
|
+
// them, and the match uses the resolved parts
|
|
23118
|
+
file = resolved;
|
|
22584
23119
|
if (pattern.includes(GLOBSTAR)) {
|
|
22585
23120
|
return this.#matchGlobstar(file, pattern, partial, fileStartIndex, patternStartIndex);
|
|
22586
23121
|
}
|
|
22587
23122
|
return this.#matchOne(file, pattern, partial, fileStartIndex, patternStartIndex);
|
|
22588
23123
|
}
|
|
22589
23124
|
#matchGlobstar(file, pattern, partial, fileIndex, patternIndex) {
|
|
22590
|
-
|
|
22591
|
-
const firstgs = pattern.indexOf(GLOBSTAR, patternIndex);
|
|
22592
|
-
const lastgs = pattern.lastIndexOf(GLOBSTAR);
|
|
22593
|
-
// split the pattern up into globstar-delimited sections
|
|
22594
|
-
// the tail has to be at the end, and the others just have
|
|
22595
|
-
// to be found in order from the head.
|
|
22596
|
-
const [head, body, tail] = partial ?
|
|
22597
|
-
[
|
|
22598
|
-
pattern.slice(patternIndex, firstgs),
|
|
22599
|
-
pattern.slice(firstgs + 1),
|
|
22600
|
-
[],
|
|
22601
|
-
]
|
|
22602
|
-
: [
|
|
22603
|
-
pattern.slice(patternIndex, firstgs),
|
|
22604
|
-
pattern.slice(firstgs + 1, lastgs),
|
|
22605
|
-
pattern.slice(lastgs + 1),
|
|
22606
|
-
];
|
|
23125
|
+
const { head, body, tail, segments } = this.#getGlobstarParts(pattern, partial, patternIndex);
|
|
22607
23126
|
// check the head, from the current file/pattern index.
|
|
22608
23127
|
if (head.length) {
|
|
22609
|
-
const
|
|
22610
|
-
if (!this.#matchOne(
|
|
23128
|
+
const headEnd = fileIndex + head.length;
|
|
23129
|
+
if (!this.#matchOne(file, head, partial, fileIndex, 0, headEnd)) {
|
|
22611
23130
|
return false;
|
|
22612
23131
|
}
|
|
22613
23132
|
fileIndex += head.length;
|
|
@@ -22665,36 +23184,64 @@ class Minimatch {
|
|
|
22665
23184
|
// now we know that there's one or more body sections, which can
|
|
22666
23185
|
// be matched anywhere from the 0 index (because the head was pruned)
|
|
22667
23186
|
// through to the length-fileTailMatch index.
|
|
22668
|
-
|
|
22669
|
-
|
|
22670
|
-
|
|
22671
|
-
|
|
22672
|
-
|
|
23187
|
+
return !!this.#matchGlobStarBodySections(file, segments, file.length - fileTailMatch, fileIndex, 0, partial, 0, !!fileTailMatch, new Set());
|
|
23188
|
+
}
|
|
23189
|
+
// Split the pattern into head, tail, and middle of ** delimited
|
|
23190
|
+
// parts. The tail has to be at the end, and the others just have to
|
|
23191
|
+
// be found in order from the head. These only depend on the pattern
|
|
23192
|
+
// row, so they are kept for the next path.
|
|
23193
|
+
#getGlobstarParts(pattern, partial, patternIndex) {
|
|
23194
|
+
let byStart = this.#globstarParts.get(pattern);
|
|
23195
|
+
if (!byStart) {
|
|
23196
|
+
byStart = [];
|
|
23197
|
+
this.#globstarParts.set(pattern, byStart);
|
|
23198
|
+
}
|
|
23199
|
+
const key = patternIndex * 2 + (partial ? 1 : 0);
|
|
23200
|
+
const found = byStart[key];
|
|
23201
|
+
if (found)
|
|
23202
|
+
return found;
|
|
23203
|
+
const firstgs = pattern.indexOf(GLOBSTAR, patternIndex);
|
|
23204
|
+
const lastgs = pattern.lastIndexOf(GLOBSTAR);
|
|
23205
|
+
const head = pattern.slice(patternIndex, firstgs);
|
|
23206
|
+
const body = pattern.slice(firstgs + 1, partial ? undefined : lastgs);
|
|
23207
|
+
const tail = partial ? [] : pattern.slice(lastgs + 1);
|
|
23208
|
+
// split the body up into sections, and note the number of
|
|
23209
|
+
// portions that must come after the start of each one
|
|
23210
|
+
const segments = [[[], 0]];
|
|
23211
|
+
let current = segments[0];
|
|
22673
23212
|
let nonGsParts = 0;
|
|
22674
23213
|
const nonGsPartsSums = [0];
|
|
22675
23214
|
for (const b of body) {
|
|
22676
23215
|
if (b === GLOBSTAR) {
|
|
22677
23216
|
nonGsPartsSums.push(nonGsParts);
|
|
22678
|
-
|
|
22679
|
-
|
|
23217
|
+
current = [[], 0];
|
|
23218
|
+
segments.push(current);
|
|
22680
23219
|
}
|
|
22681
23220
|
else {
|
|
22682
|
-
|
|
23221
|
+
current[0].push(b);
|
|
22683
23222
|
nonGsParts++;
|
|
22684
23223
|
}
|
|
22685
23224
|
}
|
|
22686
|
-
|
|
22687
|
-
|
|
22688
|
-
|
|
22689
|
-
|
|
22690
|
-
}
|
|
22691
|
-
|
|
23225
|
+
// the portions in this section and the ones after it
|
|
23226
|
+
segments.forEach((b, i) => {
|
|
23227
|
+
b[1] = nonGsParts - nonGsPartsSums[i];
|
|
23228
|
+
});
|
|
23229
|
+
const parts = { head, body, tail, segments };
|
|
23230
|
+
byStart[key] = parts;
|
|
23231
|
+
return parts;
|
|
22692
23232
|
}
|
|
22693
23233
|
// return false for "nope, not matching"
|
|
22694
23234
|
// return null for "not matching, cannot keep trying"
|
|
22695
23235
|
#matchGlobStarBodySections(file,
|
|
22696
|
-
// pattern section,
|
|
22697
|
-
bodySegments,
|
|
23236
|
+
// pattern section, and the portions that it and the rest need
|
|
23237
|
+
bodySegments,
|
|
23238
|
+
// the end of the file portions that the body can match
|
|
23239
|
+
fileLength, fileIndex, bodyIndex, partial, globStarDepth, sawTail,
|
|
23240
|
+
// the places that a walk has already tried, as
|
|
23241
|
+
// bodyIndex * (file.length + 1) + fileIndex. A walk from a place
|
|
23242
|
+
// does the same no matter how it got there, and it only comes back
|
|
23243
|
+
// if it found no match, so a walk that gets to one stops.
|
|
23244
|
+
tried) {
|
|
22698
23245
|
// take the first body segment, and walk from fileIndex to its "after"
|
|
22699
23246
|
// value at the end
|
|
22700
23247
|
// If it doesn't match at that position, we increment, until we hit
|
|
@@ -22706,8 +23253,16 @@ class Minimatch {
|
|
|
22706
23253
|
// can't possibly be a valid matching condition.
|
|
22707
23254
|
const bs = bodySegments[bodyIndex];
|
|
22708
23255
|
if (!bs) {
|
|
22709
|
-
//
|
|
22710
|
-
|
|
23256
|
+
// with partial, the body is the rest of the pattern, so it
|
|
23257
|
+
// matches if no portions are left, or only the '' of a trailing
|
|
23258
|
+
// / (as a/* matches a/b/). A ** at the end walks them as its own
|
|
23259
|
+
// empty section.
|
|
23260
|
+
if (partial) {
|
|
23261
|
+
return (fileIndex >= fileLength ||
|
|
23262
|
+
(fileIndex === fileLength - 1 && file[fileIndex] === ''));
|
|
23263
|
+
}
|
|
23264
|
+
// just make sure that there's no bad dots before the tail
|
|
23265
|
+
for (let i = fileIndex; i < fileLength; i++) {
|
|
22711
23266
|
sawTail = true;
|
|
22712
23267
|
const f = file[i];
|
|
22713
23268
|
if (f === '.' ||
|
|
@@ -22718,19 +23273,29 @@ class Minimatch {
|
|
|
22718
23273
|
}
|
|
22719
23274
|
return sawTail;
|
|
22720
23275
|
}
|
|
22721
|
-
// have a non-globstar body section to test
|
|
22722
|
-
|
|
23276
|
+
// have a non-globstar body section to test, up to the last index
|
|
23277
|
+
// where it can start
|
|
23278
|
+
const [body, need] = bs;
|
|
23279
|
+
// with partial, the path can end before the body does
|
|
23280
|
+
const after = partial ? fileLength : fileLength - need;
|
|
22723
23281
|
while (fileIndex <= after) {
|
|
22724
|
-
const
|
|
23282
|
+
const key = bodyIndex * (file.length + 1) + fileIndex;
|
|
23283
|
+
if (tried.has(key))
|
|
23284
|
+
return false;
|
|
23285
|
+
tried.add(key);
|
|
23286
|
+
const m = this.#matchOne(file, body, partial, fileIndex, 0, fileIndex + body.length);
|
|
22725
23287
|
// if limit exceeded, no match. intentional false negative,
|
|
22726
23288
|
// acceptable break in correctness for security.
|
|
22727
23289
|
if (m && globStarDepth < this.maxGlobstarRecursion) {
|
|
22728
23290
|
// match! see if the rest match. if so, we're done!
|
|
22729
|
-
const sub = this.#matchGlobStarBodySections(file, bodySegments, fileIndex + body.length, bodyIndex + 1, partial, globStarDepth + 1, sawTail);
|
|
23291
|
+
const sub = this.#matchGlobStarBodySections(file, bodySegments, fileLength, fileIndex + body.length, bodyIndex + 1, partial, globStarDepth + 1, sawTail, tried);
|
|
22730
23292
|
if (sub !== false) {
|
|
22731
23293
|
return sub;
|
|
22732
23294
|
}
|
|
22733
23295
|
}
|
|
23296
|
+
// the ** does not walk past the last place the body can start
|
|
23297
|
+
if (fileIndex === after)
|
|
23298
|
+
break;
|
|
22734
23299
|
const f = file[fileIndex];
|
|
22735
23300
|
if (f === '.' ||
|
|
22736
23301
|
f === '..' ||
|
|
@@ -22742,21 +23307,20 @@ class Minimatch {
|
|
|
22742
23307
|
// walked off. no point continuing
|
|
22743
23308
|
return partial || null;
|
|
22744
23309
|
}
|
|
22745
|
-
#matchOne(file, pattern, partial, fileIndex, patternIndex
|
|
23310
|
+
#matchOne(file, pattern, partial, fileIndex, patternIndex,
|
|
23311
|
+
// only match the file portions before this index
|
|
23312
|
+
fileEnd = file.length) {
|
|
22746
23313
|
let fi;
|
|
22747
23314
|
let pi;
|
|
22748
23315
|
let pl;
|
|
22749
23316
|
let fl;
|
|
22750
23317
|
for (fi = fileIndex,
|
|
22751
23318
|
pi = patternIndex,
|
|
22752
|
-
fl = file.length,
|
|
23319
|
+
fl = Math.min(fileEnd, file.length),
|
|
22753
23320
|
pl = pattern.length; fi < fl && pi < pl; fi++, pi++) {
|
|
22754
|
-
this.debug('matchOne loop');
|
|
22755
23321
|
let p = pattern[pi];
|
|
22756
23322
|
let f = file[fi];
|
|
22757
|
-
this.debug(pattern, p, f);
|
|
22758
23323
|
// should be impossible.
|
|
22759
|
-
// some invalid regexp stuff in the set.
|
|
22760
23324
|
/* c8 ignore start */
|
|
22761
23325
|
if (p === false || p === GLOBSTAR) {
|
|
22762
23326
|
return false;
|
|
@@ -22764,17 +23328,8 @@ class Minimatch {
|
|
|
22764
23328
|
/* c8 ignore stop */
|
|
22765
23329
|
// something other than **
|
|
22766
23330
|
// non-magic patterns just have to match exactly
|
|
22767
|
-
// patterns with magic have been turned into
|
|
22768
|
-
|
|
22769
|
-
if (typeof p === 'string') {
|
|
22770
|
-
hit = f === p;
|
|
22771
|
-
this.debug('string match', p, f, hit);
|
|
22772
|
-
}
|
|
22773
|
-
else {
|
|
22774
|
-
hit = p.test(f);
|
|
22775
|
-
this.debug('pattern match', p, f, hit);
|
|
22776
|
-
}
|
|
22777
|
-
if (!hit)
|
|
23331
|
+
// patterns with magic have been turned into Matchers.
|
|
23332
|
+
if (!portionMatch(p, f))
|
|
22778
23333
|
return false;
|
|
22779
23334
|
}
|
|
22780
23335
|
// Note: ending in / means that we'll get a final ""
|
|
@@ -22783,9 +23338,8 @@ class Minimatch {
|
|
|
22783
23338
|
// If the file ends in /, then it can only match a
|
|
22784
23339
|
// a pattern that ends in /, unless the pattern just
|
|
22785
23340
|
// doesn't have any more for it. But, a/b/ should *not*
|
|
22786
|
-
// match "a/b/*", even though ""
|
|
22787
|
-
//
|
|
22788
|
-
// simply not be reached yet.
|
|
23341
|
+
// match "a/b/*", even though * can match "", except in
|
|
23342
|
+
// partial mode, where it might simply not be reached yet.
|
|
22789
23343
|
// However, a/b/ should still satisfy a/*
|
|
22790
23344
|
// now either we fell off the end of the pattern, or we're done.
|
|
22791
23345
|
if (fi === fl && pi === pl) {
|
|
@@ -22824,139 +23378,26 @@ class Minimatch {
|
|
|
22824
23378
|
return GLOBSTAR;
|
|
22825
23379
|
if (pattern === '')
|
|
22826
23380
|
return '';
|
|
22827
|
-
|
|
22828
|
-
|
|
22829
|
-
|
|
22830
|
-
|
|
22831
|
-
if (
|
|
22832
|
-
|
|
22833
|
-
|
|
22834
|
-
|
|
22835
|
-
|
|
22836
|
-
options.dot ?
|
|
22837
|
-
starDotExtTestNocaseDot
|
|
22838
|
-
: starDotExtTestNocase
|
|
22839
|
-
: options.dot ? starDotExtTestDot
|
|
22840
|
-
: starDotExtTest)(m[1]);
|
|
22841
|
-
}
|
|
22842
|
-
else if ((m = pattern.match(qmarksRE))) {
|
|
22843
|
-
fastTest = (options.nocase ?
|
|
22844
|
-
options.dot ?
|
|
22845
|
-
qmarksTestNocaseDot
|
|
22846
|
-
: qmarksTestNocase
|
|
22847
|
-
: options.dot ? qmarksTestDot
|
|
22848
|
-
: qmarksTest)(m);
|
|
22849
|
-
}
|
|
22850
|
-
else if ((m = pattern.match(starDotStarRE))) {
|
|
22851
|
-
fastTest = options.dot ? starDotStarTestDot : starDotStarTest;
|
|
22852
|
-
}
|
|
22853
|
-
else if ((m = pattern.match(dotStarRE))) {
|
|
22854
|
-
fastTest = dotStarTest;
|
|
22855
|
-
}
|
|
22856
|
-
const re = AST.fromGlob(pattern, this.options).toMMPattern();
|
|
22857
|
-
if (fastTest && typeof re === 'object') {
|
|
22858
|
-
// Avoids overriding in frozen environments
|
|
22859
|
-
Reflect.defineProperty(re, 'test', { value: fastTest });
|
|
22860
|
-
}
|
|
22861
|
-
return re;
|
|
22862
|
-
}
|
|
22863
|
-
makeRe() {
|
|
22864
|
-
if (this.regexp || this.regexp === false)
|
|
22865
|
-
return this.regexp;
|
|
22866
|
-
// at this point, this.set is a 2d array of partial
|
|
22867
|
-
// pattern strings, or "**".
|
|
22868
|
-
//
|
|
22869
|
-
// It's better to use .match(). This function shouldn't
|
|
22870
|
-
// be used, really, but it's pretty convenient sometimes,
|
|
22871
|
-
// when you just want to work with a regex.
|
|
22872
|
-
const set = this.set;
|
|
22873
|
-
if (!set.length) {
|
|
22874
|
-
this.regexp = false;
|
|
22875
|
-
return this.regexp;
|
|
22876
|
-
}
|
|
22877
|
-
const options = this.options;
|
|
22878
|
-
const twoStar = options.noglobstar ? star
|
|
22879
|
-
: options.dot ? twoStarDot
|
|
22880
|
-
: twoStarNoDot;
|
|
22881
|
-
const flags = new Set(options.nocase ? ['i'] : []);
|
|
22882
|
-
// regexpify non-globstar patterns
|
|
22883
|
-
// if ** is only item, then we just do one twoStar
|
|
22884
|
-
// if ** is first, and there are more, prepend (\/|twoStar\/)? to next
|
|
22885
|
-
// if ** is last, append (\/twoStar|) to previous
|
|
22886
|
-
// if ** is in the middle, append (\/|\/twoStar\/) to previous
|
|
22887
|
-
// then filter out GLOBSTAR symbols
|
|
22888
|
-
let re = set
|
|
22889
|
-
.map(pattern => {
|
|
22890
|
-
const pp = pattern.map(p => {
|
|
22891
|
-
if (p instanceof RegExp) {
|
|
22892
|
-
for (const f of p.flags.split(''))
|
|
22893
|
-
flags.add(f);
|
|
22894
|
-
}
|
|
22895
|
-
return (typeof p === 'string' ? regExpEscape(p)
|
|
22896
|
-
: p === GLOBSTAR ? GLOBSTAR
|
|
22897
|
-
: p._src);
|
|
22898
|
-
});
|
|
22899
|
-
pp.forEach((p, i) => {
|
|
22900
|
-
const next = pp[i + 1];
|
|
22901
|
-
const prev = pp[i - 1];
|
|
22902
|
-
if (p !== GLOBSTAR || prev === GLOBSTAR) {
|
|
22903
|
-
return;
|
|
22904
|
-
}
|
|
22905
|
-
if (prev === undefined) {
|
|
22906
|
-
if (next !== undefined && next !== GLOBSTAR) {
|
|
22907
|
-
pp[i + 1] = '(?:\\/|' + twoStar + '\\/)?' + next;
|
|
22908
|
-
}
|
|
22909
|
-
else {
|
|
22910
|
-
pp[i] = twoStar;
|
|
22911
|
-
}
|
|
22912
|
-
}
|
|
22913
|
-
else if (next === undefined) {
|
|
22914
|
-
pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + ')?';
|
|
22915
|
-
}
|
|
22916
|
-
else if (next !== GLOBSTAR) {
|
|
22917
|
-
pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + '\\/)' + next;
|
|
22918
|
-
pp[i + 1] = GLOBSTAR;
|
|
22919
|
-
}
|
|
22920
|
-
});
|
|
22921
|
-
const filtered = pp.filter(p => p !== GLOBSTAR);
|
|
22922
|
-
// For partial matches, we need to make the pattern match
|
|
22923
|
-
// any prefix of the full path. We do this by generating
|
|
22924
|
-
// alternative patterns that match progressively longer prefixes.
|
|
22925
|
-
if (this.partial && filtered.length >= 1) {
|
|
22926
|
-
const prefixes = [];
|
|
22927
|
-
for (let i = 1; i <= filtered.length; i++) {
|
|
22928
|
-
prefixes.push(filtered.slice(0, i).join('/'));
|
|
22929
|
-
}
|
|
22930
|
-
return '(?:' + prefixes.join('|') + ')';
|
|
22931
|
-
}
|
|
22932
|
-
return filtered.join('/');
|
|
22933
|
-
})
|
|
22934
|
-
.join('|');
|
|
22935
|
-
// need to wrap in parens if we had more than one thing with |,
|
|
22936
|
-
// otherwise only the first will be anchored to ^ and the last to $
|
|
22937
|
-
const [open, close] = set.length > 1 ? ['(?:', ')'] : ['', ''];
|
|
22938
|
-
// must match entire pattern
|
|
22939
|
-
// ending in a * or ** will make it less strict.
|
|
22940
|
-
re = '^' + open + re + close + '$';
|
|
22941
|
-
// In partial mode, '/' should always match as it's a valid prefix for any pattern
|
|
22942
|
-
if (this.partial) {
|
|
22943
|
-
re = '^(?:\\/|' + open + re.slice(1, -1) + close + ')$';
|
|
22944
|
-
}
|
|
22945
|
-
// can match anything, as long as it's not this.
|
|
22946
|
-
if (this.negate)
|
|
22947
|
-
re = '^(?!' + re + ').+$';
|
|
22948
|
-
try {
|
|
22949
|
-
this.regexp = new RegExp(re, [...flags].join(''));
|
|
22950
|
-
/* c8 ignore start */
|
|
23381
|
+
const { nocase, nocaseMagicOnly, noext = false, dot, normalize, } = options;
|
|
23382
|
+
const lit = literal(pattern, noext);
|
|
23383
|
+
// in nocase mode, a literal with cased chars still needs a
|
|
23384
|
+
// Matcher, unless nocaseMagicOnly is set.
|
|
23385
|
+
if (lit !== undefined &&
|
|
23386
|
+
!(nocase &&
|
|
23387
|
+
!nocaseMagicOnly &&
|
|
23388
|
+
pattern.toUpperCase() !== pattern.toLowerCase())) {
|
|
23389
|
+
return this.#norm(lit);
|
|
22951
23390
|
}
|
|
22952
|
-
|
|
22953
|
-
|
|
22954
|
-
|
|
23391
|
+
if (this.#pending)
|
|
23392
|
+
return PENDING;
|
|
23393
|
+
let m = this.#matchers.get(pattern);
|
|
23394
|
+
if (!m) {
|
|
23395
|
+
m = new Matcher(pattern, { nocase, noext, dot, normalize });
|
|
23396
|
+
this.#matchers.set(pattern, m);
|
|
22955
23397
|
}
|
|
22956
|
-
|
|
22957
|
-
return this.regexp;
|
|
23398
|
+
return m;
|
|
22958
23399
|
}
|
|
22959
|
-
slashSplit(p) {
|
|
23400
|
+
#slashSplit(p) {
|
|
22960
23401
|
// if p starts with // on windows, we preserve that
|
|
22961
23402
|
// so that UNC paths aren't broken. Otherwise, any number of
|
|
22962
23403
|
// / characters are coalesced into one, unless
|
|
@@ -22973,7 +23414,6 @@ class Minimatch {
|
|
|
22973
23414
|
}
|
|
22974
23415
|
}
|
|
22975
23416
|
match(f, partial = this.partial) {
|
|
22976
|
-
this.debug('match', f, this.pattern);
|
|
22977
23417
|
// short-circuit in the case of busted things.
|
|
22978
23418
|
// comments, etc.
|
|
22979
23419
|
if (this.comment) {
|
|
@@ -22986,19 +23426,36 @@ class Minimatch {
|
|
|
22986
23426
|
return true;
|
|
22987
23427
|
}
|
|
22988
23428
|
const options = this.options;
|
|
22989
|
-
//
|
|
22990
|
-
|
|
22991
|
-
|
|
23429
|
+
// treat the test path as a set of pathparts. If it was not just
|
|
23430
|
+
// split or checked, check that it can match before splitting it.
|
|
23431
|
+
let split = this.#cachedSplit(f);
|
|
23432
|
+
if (!split) {
|
|
23433
|
+
// the checks look at the path as given, so not if it is
|
|
23434
|
+
// normalized
|
|
23435
|
+
if (!partial &&
|
|
23436
|
+
!this.#form &&
|
|
23437
|
+
(this.#endCheck || this.#literalCheck) &&
|
|
23438
|
+
lastChecked !== f) {
|
|
23439
|
+
lastChecked = f;
|
|
23440
|
+
const can = this.#canMatch(f);
|
|
23441
|
+
if (can === 'no')
|
|
23442
|
+
return options.flipNegate ? false : this.negate;
|
|
23443
|
+
if (can === 'yes')
|
|
23444
|
+
return options.flipNegate ? true : !this.negate;
|
|
23445
|
+
}
|
|
23446
|
+
split = this.#split(f);
|
|
22992
23447
|
}
|
|
22993
|
-
|
|
22994
|
-
|
|
22995
|
-
|
|
23448
|
+
const ff = split.parts;
|
|
23449
|
+
// the parts after level 2 resolves them, kept for the next pattern
|
|
23450
|
+
// that tests the same path
|
|
23451
|
+
const resolved = this.#level2 ?
|
|
23452
|
+
(split.resolved ??= this.#levelTwoFileOptimize(ff))
|
|
23453
|
+
: ff;
|
|
22996
23454
|
// just ONE of the pattern sets in this.set needs to match
|
|
22997
23455
|
// in order for it to be valid. If negating, then just one
|
|
22998
23456
|
// match means that we have failed.
|
|
22999
23457
|
// Either way, return on the first hit.
|
|
23000
23458
|
const set = this.set;
|
|
23001
|
-
this.debug(this.pattern, 'set', set);
|
|
23002
23459
|
// Find the basename of the path by looking for the last non-empty segment
|
|
23003
23460
|
let filename = ff[ff.length - 1];
|
|
23004
23461
|
if (!filename) {
|
|
@@ -23006,12 +23463,16 @@ class Minimatch {
|
|
|
23006
23463
|
filename = ff[i];
|
|
23007
23464
|
}
|
|
23008
23465
|
}
|
|
23009
|
-
for (
|
|
23010
|
-
|
|
23011
|
-
|
|
23012
|
-
|
|
23013
|
-
|
|
23014
|
-
|
|
23466
|
+
for (let r = 0; r < set.length; r++) {
|
|
23467
|
+
const pattern = set[r];
|
|
23468
|
+
const shape = partial ? undefined : this.#shapes[r];
|
|
23469
|
+
// level 2 does not change a path of one portion
|
|
23470
|
+
const hit = shape === 'base' ?
|
|
23471
|
+
portionMatch(pattern[0], filename)
|
|
23472
|
+
: shape ? this.#matchShape(resolved, pattern, shape)
|
|
23473
|
+
: options.matchBase && pattern.length === 1 ?
|
|
23474
|
+
this.#matchRow([filename], [filename], pattern, partial)
|
|
23475
|
+
: this.#matchRow(ff, resolved, pattern, partial);
|
|
23015
23476
|
if (hit) {
|
|
23016
23477
|
if (options.flipNegate) {
|
|
23017
23478
|
return true;
|
|
@@ -23031,7 +23492,6 @@ class Minimatch {
|
|
|
23031
23492
|
}
|
|
23032
23493
|
}
|
|
23033
23494
|
/* c8 ignore stop */
|
|
23034
|
-
minimatch.AST = AST;
|
|
23035
23495
|
minimatch.Minimatch = Minimatch;
|
|
23036
23496
|
minimatch.escape = escape;
|
|
23037
23497
|
minimatch.unescape = unescape;
|
|
@@ -23832,7 +24292,10 @@ function resolveWithTS(containingFile, source, ts2, fs) {
|
|
|
23832
24292
|
}
|
|
23833
24293
|
}
|
|
23834
24294
|
function loadTSConfig(configPath, ts2, fs, visited = /* @__PURE__ */ new Set()) {
|
|
23835
|
-
const parseConfigHost =
|
|
24295
|
+
const parseConfigHost = {
|
|
24296
|
+
...ts2.sys,
|
|
24297
|
+
readDirectory: () => []
|
|
24298
|
+
};
|
|
23836
24299
|
const config = ts2.parseJsonConfigFileContent(
|
|
23837
24300
|
ts2.readConfigFile(configPath, fs.readFile).config,
|
|
23838
24301
|
parseConfigHost,
|
|
@@ -25109,11 +25572,18 @@ function transformDestructuredProps(ctx, vueImportAliases) {
|
|
|
25109
25572
|
const excludedIds = /* @__PURE__ */ new WeakSet();
|
|
25110
25573
|
const parentStack = [];
|
|
25111
25574
|
const propsLocalToPublicMap = /* @__PURE__ */ Object.create(null);
|
|
25575
|
+
const modelOptionNodes = /* @__PURE__ */ new Set();
|
|
25576
|
+
let currentModelOption = null;
|
|
25112
25577
|
for (const key in ctx.propsDestructuredBindings) {
|
|
25113
25578
|
const { local } = ctx.propsDestructuredBindings[key];
|
|
25114
25579
|
rootScope[local] = true;
|
|
25115
25580
|
propsLocalToPublicMap[local] = key;
|
|
25116
25581
|
}
|
|
25582
|
+
for (const { runtimeOptionNodes } of Object.values(ctx.modelDecls)) {
|
|
25583
|
+
for (const node of runtimeOptionNodes) {
|
|
25584
|
+
modelOptionNodes.add(node);
|
|
25585
|
+
}
|
|
25586
|
+
}
|
|
25117
25587
|
function pushScope(isFunctionScope = false) {
|
|
25118
25588
|
const scope = currentScope = Object.create(currentScope);
|
|
25119
25589
|
scopeStack.push(scope);
|
|
@@ -25140,7 +25610,8 @@ function transformDestructuredProps(ctx, vueImportAliases) {
|
|
|
25140
25610
|
}
|
|
25141
25611
|
}
|
|
25142
25612
|
function walkScope(node, isRoot = false) {
|
|
25143
|
-
|
|
25613
|
+
const body = node.type === "SwitchCase" ? node.consequent : node.body;
|
|
25614
|
+
for (const stmt of body) {
|
|
25144
25615
|
if (stmt.type === "VariableDeclaration") {
|
|
25145
25616
|
walkVariableDeclaration(stmt, isRoot);
|
|
25146
25617
|
} else if (stmt.type === "FunctionDeclaration" || stmt.type === "ClassDeclaration") {
|
|
@@ -25185,6 +25656,18 @@ function transformDestructuredProps(ctx, vueImportAliases) {
|
|
|
25185
25656
|
});
|
|
25186
25657
|
}
|
|
25187
25658
|
function rewriteId(id, parent, parentStack2) {
|
|
25659
|
+
if (currentModelOption) {
|
|
25660
|
+
const isDefault = (currentModelOption.type === "ObjectProperty" || currentModelOption.type === "ObjectMethod") && resolveObjectKey(
|
|
25661
|
+
currentModelOption.key,
|
|
25662
|
+
currentModelOption.computed
|
|
25663
|
+
) === "default";
|
|
25664
|
+
ctx.error(
|
|
25665
|
+
`\`${DEFINE_MODEL}()\` prop options cannot reference destructured props because they are hoisted outside of the setup() function.` + (isDefault ? ` Use the props argument of the default factory instead, e.g. default: props => props${shared.genPropsAccessExp(
|
|
25666
|
+
propsLocalToPublicMap[id.name]
|
|
25667
|
+
).slice(`__props`.length)}` : ``),
|
|
25668
|
+
id
|
|
25669
|
+
);
|
|
25670
|
+
}
|
|
25188
25671
|
if (parent.type === "AssignmentExpression" && id === parent.left || parent.type === "UpdateExpression") {
|
|
25189
25672
|
ctx.error(`Cannot assign to destructured props as they are readonly.`, id);
|
|
25190
25673
|
}
|
|
@@ -25223,6 +25706,9 @@ function transformDestructuredProps(ctx, vueImportAliases) {
|
|
|
25223
25706
|
if (parent && parent.type.startsWith("TS") && !CompilerDOM.TS_NODE_TYPES.includes(parent.type)) {
|
|
25224
25707
|
return this.skip();
|
|
25225
25708
|
}
|
|
25709
|
+
if (modelOptionNodes.has(node)) {
|
|
25710
|
+
currentModelOption = node;
|
|
25711
|
+
}
|
|
25226
25712
|
checkUsage(node, "watch", vueImportAliases.watch);
|
|
25227
25713
|
checkUsage(node, "toRef", vueImportAliases.toRef);
|
|
25228
25714
|
if (CompilerDOM.isFunctionType(node)) {
|
|
@@ -25234,12 +25720,19 @@ function transformDestructuredProps(ctx, vueImportAliases) {
|
|
|
25234
25720
|
}
|
|
25235
25721
|
return;
|
|
25236
25722
|
}
|
|
25723
|
+
if (node.type === "StaticBlock") {
|
|
25724
|
+
pushScope(true);
|
|
25725
|
+
walkFunctionScopeVarDeclarations(node);
|
|
25726
|
+
walkScope(node);
|
|
25727
|
+
return;
|
|
25728
|
+
}
|
|
25237
25729
|
if (node.type === "CatchClause") {
|
|
25238
25730
|
pushScope();
|
|
25239
|
-
if (node.param
|
|
25240
|
-
|
|
25731
|
+
if (node.param) {
|
|
25732
|
+
for (const id of CompilerDOM.extractIdentifiers(node.param)) {
|
|
25733
|
+
registerLocalBinding(id);
|
|
25734
|
+
}
|
|
25241
25735
|
}
|
|
25242
|
-
walkScope(node.body);
|
|
25243
25736
|
return;
|
|
25244
25737
|
}
|
|
25245
25738
|
if (node.type === "ForOfStatement" || node.type === "ForInStatement" || node.type === "ForStatement") {
|
|
@@ -25268,13 +25761,22 @@ function transformDestructuredProps(ctx, vueImportAliases) {
|
|
|
25268
25761
|
},
|
|
25269
25762
|
leave(node, parent) {
|
|
25270
25763
|
parent && parentStack.pop();
|
|
25271
|
-
if (
|
|
25764
|
+
if (node === currentModelOption) {
|
|
25765
|
+
currentModelOption = null;
|
|
25766
|
+
}
|
|
25767
|
+
if (CompilerDOM.isFunctionType(node) || node.type === "StaticBlock") {
|
|
25272
25768
|
popScope(true);
|
|
25273
25769
|
} else if (node.type === "BlockStatement" && !CompilerDOM.isFunctionType(parent)) {
|
|
25274
25770
|
popScope();
|
|
25275
|
-
} else if (node.type === "CatchClause" || node.type === "ForOfStatement" || node.type === "ForInStatement" || node.type === "ForStatement") {
|
|
25771
|
+
} else if (node.type === "CatchClause" || node.type === "SwitchStatement" || node.type === "ForOfStatement" || node.type === "ForInStatement" || node.type === "ForStatement") {
|
|
25276
25772
|
popScope();
|
|
25277
25773
|
}
|
|
25774
|
+
if (parent && parent.type === "SwitchStatement" && node === parent.discriminant) {
|
|
25775
|
+
pushScope();
|
|
25776
|
+
for (const switchCase of parent.cases) {
|
|
25777
|
+
walkScope(switchCase);
|
|
25778
|
+
}
|
|
25779
|
+
}
|
|
25278
25780
|
}
|
|
25279
25781
|
});
|
|
25280
25782
|
}
|
|
@@ -26371,7 +26873,7 @@ function mergeSourceMaps(scriptMap, templateMap, templateLineOffset) {
|
|
|
26371
26873
|
return generator.toJSON();
|
|
26372
26874
|
}
|
|
26373
26875
|
|
|
26374
|
-
const version = "3.5.
|
|
26876
|
+
const version = "3.5.45";
|
|
26375
26877
|
const parseCache = parseCache$1;
|
|
26376
26878
|
const errorMessages = {
|
|
26377
26879
|
...CompilerDOM.errorMessages,
|