source: node_modules/minimatch/dist/commonjs/index.js@ 06ebe74

finki-main main
Last change on this file since 06ebe74 was 33517cc, checked in by Klimentina Efremova <klimentina08642@…>, 10 days ago

Turned database from SQLite to PostgressSQL, updated database changes from Phase 1 and 2

  • Property mode set to 100644
File size: 44.1 KB
Line 
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.unescape = exports.escape = exports.AST = exports.Minimatch = exports.match = exports.makeRe = exports.braceExpand = exports.defaults = exports.filter = exports.GLOBSTAR = exports.sep = exports.minimatch = void 0;
4const brace_expansion_1 = require("brace-expansion");
5const assert_valid_pattern_js_1 = require("./assert-valid-pattern.js");
6const ast_js_1 = require("./ast.js");
7const escape_js_1 = require("./escape.js");
8const unescape_js_1 = require("./unescape.js");
9const minimatch = (p, pattern, options = {}) => {
10 (0, assert_valid_pattern_js_1.assertValidPattern)(pattern);
11 // shortcut: comments match nothing.
12 if (!options.nocomment && pattern.charAt(0) === '#') {
13 return false;
14 }
15 return new Minimatch(pattern, options).match(p);
16};
17exports.minimatch = minimatch;
18// Optimized checking for the most common glob patterns.
19const starDotExtRE = /^\*+([^+@!?*[(]*)$/;
20const starDotExtTest = (ext) => (f) => !f.startsWith('.') && f.endsWith(ext);
21const starDotExtTestDot = (ext) => (f) => f.endsWith(ext);
22const starDotExtTestNocase = (ext) => {
23 ext = ext.toLowerCase();
24 return (f) => !f.startsWith('.') && f.toLowerCase().endsWith(ext);
25};
26const starDotExtTestNocaseDot = (ext) => {
27 ext = ext.toLowerCase();
28 return (f) => f.toLowerCase().endsWith(ext);
29};
30const starDotStarRE = /^\*+\.\*+$/;
31const starDotStarTest = (f) => !f.startsWith('.') && f.includes('.');
32const starDotStarTestDot = (f) => f !== '.' && f !== '..' && f.includes('.');
33const dotStarRE = /^\.\*+$/;
34const dotStarTest = (f) => f !== '.' && f !== '..' && f.startsWith('.');
35const starRE = /^\*+$/;
36const starTest = (f) => f.length !== 0 && !f.startsWith('.');
37const starTestDot = (f) => f.length !== 0 && f !== '.' && f !== '..';
38const qmarksRE = /^\?+([^+@!?*[(]*)?$/;
39const qmarksTestNocase = ([$0, ext = '']) => {
40 const noext = qmarksTestNoExt([$0]);
41 if (!ext)
42 return noext;
43 ext = ext.toLowerCase();
44 return (f) => noext(f) && f.toLowerCase().endsWith(ext);
45};
46const qmarksTestNocaseDot = ([$0, ext = '']) => {
47 const noext = qmarksTestNoExtDot([$0]);
48 if (!ext)
49 return noext;
50 ext = ext.toLowerCase();
51 return (f) => noext(f) && f.toLowerCase().endsWith(ext);
52};
53const qmarksTestDot = ([$0, ext = '']) => {
54 const noext = qmarksTestNoExtDot([$0]);
55 return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
56};
57const qmarksTest = ([$0, ext = '']) => {
58 const noext = qmarksTestNoExt([$0]);
59 return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
60};
61const qmarksTestNoExt = ([$0]) => {
62 const len = $0.length;
63 return (f) => f.length === len && !f.startsWith('.');
64};
65const qmarksTestNoExtDot = ([$0]) => {
66 const len = $0.length;
67 return (f) => f.length === len && f !== '.' && f !== '..';
68};
69/* c8 ignore start */
70const defaultPlatform = (typeof process === 'object' && process ?
71 (typeof process.env === 'object' &&
72 process.env &&
73 process.env.__MINIMATCH_TESTING_PLATFORM__) ||
74 process.platform
75 : 'posix');
76const path = {
77 win32: { sep: '\\' },
78 posix: { sep: '/' },
79};
80/* c8 ignore stop */
81exports.sep = defaultPlatform === 'win32' ? path.win32.sep : path.posix.sep;
82exports.minimatch.sep = exports.sep;
83exports.GLOBSTAR = Symbol('globstar **');
84exports.minimatch.GLOBSTAR = exports.GLOBSTAR;
85// any single thing other than /
86// don't need to escape / when using new RegExp()
87const qmark = '[^/]';
88// * => any number of characters
89const star = qmark + '*?';
90// ** when dots are allowed. Anything goes, except .. and .
91// not (^ or / followed by one or two dots followed by $ or /),
92// followed by anything, any number of times.
93const twoStarDot = '(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?';
94// not a ^ or / followed by a dot,
95// followed by anything, any number of times.
96const twoStarNoDot = '(?:(?!(?:\\/|^)\\.).)*?';
97const filter = (pattern, options = {}) => (p) => (0, exports.minimatch)(p, pattern, options);
98exports.filter = filter;
99exports.minimatch.filter = exports.filter;
100const ext = (a, b = {}) => Object.assign({}, a, b);
101const defaults = (def) => {
102 if (!def || typeof def !== 'object' || !Object.keys(def).length) {
103 return exports.minimatch;
104 }
105 const orig = exports.minimatch;
106 const m = (p, pattern, options = {}) => orig(p, pattern, ext(def, options));
107 return Object.assign(m, {
108 Minimatch: class Minimatch extends orig.Minimatch {
109 constructor(pattern, options = {}) {
110 super(pattern, ext(def, options));
111 }
112 static defaults(options) {
113 return orig.defaults(ext(def, options)).Minimatch;
114 }
115 },
116 AST: class AST extends orig.AST {
117 /* c8 ignore start */
118 constructor(type, parent, options = {}) {
119 super(type, parent, ext(def, options));
120 }
121 /* c8 ignore stop */
122 static fromGlob(pattern, options = {}) {
123 return orig.AST.fromGlob(pattern, ext(def, options));
124 }
125 },
126 unescape: (s, options = {}) => orig.unescape(s, ext(def, options)),
127 escape: (s, options = {}) => orig.escape(s, ext(def, options)),
128 filter: (pattern, options = {}) => orig.filter(pattern, ext(def, options)),
129 defaults: (options) => orig.defaults(ext(def, options)),
130 makeRe: (pattern, options = {}) => orig.makeRe(pattern, ext(def, options)),
131 braceExpand: (pattern, options = {}) => orig.braceExpand(pattern, ext(def, options)),
132 match: (list, pattern, options = {}) => orig.match(list, pattern, ext(def, options)),
133 sep: orig.sep,
134 GLOBSTAR: exports.GLOBSTAR,
135 });
136};
137exports.defaults = defaults;
138exports.minimatch.defaults = exports.defaults;
139// Brace expansion:
140// a{b,c}d -> abd acd
141// a{b,}c -> abc ac
142// a{0..3}d -> a0d a1d a2d a3d
143// a{b,c{d,e}f}g -> abg acdfg acefg
144// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg
145//
146// Invalid sets are not expanded.
147// a{2..}b -> a{2..}b
148// a{b}c -> a{b}c
149const braceExpand = (pattern, options = {}) => {
150 (0, assert_valid_pattern_js_1.assertValidPattern)(pattern);
151 // Thanks to Yeting Li <https://github.com/yetingli> for
152 // improving this regexp to avoid a ReDOS vulnerability.
153 if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
154 // shortcut. no need to expand.
155 return [pattern];
156 }
157 return (0, brace_expansion_1.expand)(pattern, { max: options.braceExpandMax });
158};
159exports.braceExpand = braceExpand;
160exports.minimatch.braceExpand = exports.braceExpand;
161// parse a component of the expanded set.
162// At this point, no pattern may contain "/" in it
163// so we're going to return a 2d array, where each entry is the full
164// pattern, split on '/', and then turned into a regular expression.
165// A regexp is made at the end which joins each array with an
166// escaped /, and another full one which joins each regexp with |.
167//
168// Following the lead of Bash 4.1, note that "**" only has special meaning
169// when it is the *only* thing in a path portion. Otherwise, any series
170// of * is equivalent to a single *. Globstar behavior is enabled by
171// default, and can be disabled by setting options.noglobstar.
172const makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe();
173exports.makeRe = makeRe;
174exports.minimatch.makeRe = exports.makeRe;
175const match = (list, pattern, options = {}) => {
176 const mm = new Minimatch(pattern, options);
177 list = list.filter(f => mm.match(f));
178 if (mm.options.nonull && !list.length) {
179 list.push(pattern);
180 }
181 return list;
182};
183exports.match = match;
184exports.minimatch.match = exports.match;
185// replace stuff like \* with *
186const globMagic = /[?*]|[+@!]\(.*?\)|\[|\]/;
187const regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
188class Minimatch {
189 options;
190 set;
191 pattern;
192 windowsPathsNoEscape;
193 nonegate;
194 negate;
195 comment;
196 empty;
197 preserveMultipleSlashes;
198 partial;
199 globSet;
200 globParts;
201 nocase;
202 isWindows;
203 platform;
204 windowsNoMagicRoot;
205 maxGlobstarRecursion;
206 regexp;
207 constructor(pattern, options = {}) {
208 (0, assert_valid_pattern_js_1.assertValidPattern)(pattern);
209 options = options || {};
210 this.options = options;
211 this.maxGlobstarRecursion = options.maxGlobstarRecursion ?? 200;
212 this.pattern = pattern;
213 this.platform = options.platform || defaultPlatform;
214 this.isWindows = this.platform === 'win32';
215 // avoid the annoying deprecation flag lol
216 const awe = ('allowWindow' + 'sEscape');
217 this.windowsPathsNoEscape =
218 !!options.windowsPathsNoEscape || options[awe] === false;
219 if (this.windowsPathsNoEscape) {
220 this.pattern = this.pattern.replace(/\\/g, '/');
221 }
222 this.preserveMultipleSlashes = !!options.preserveMultipleSlashes;
223 this.regexp = null;
224 this.negate = false;
225 this.nonegate = !!options.nonegate;
226 this.comment = false;
227 this.empty = false;
228 this.partial = !!options.partial;
229 this.nocase = !!this.options.nocase;
230 this.windowsNoMagicRoot =
231 options.windowsNoMagicRoot !== undefined ?
232 options.windowsNoMagicRoot
233 : !!(this.isWindows && this.nocase);
234 this.globSet = [];
235 this.globParts = [];
236 this.set = [];
237 // make the set of regexps etc.
238 this.make();
239 }
240 hasMagic() {
241 if (this.options.magicalBraces && this.set.length > 1) {
242 return true;
243 }
244 for (const pattern of this.set) {
245 for (const part of pattern) {
246 if (typeof part !== 'string')
247 return true;
248 }
249 }
250 return false;
251 }
252 debug(..._) { }
253 make() {
254 const pattern = this.pattern;
255 const options = this.options;
256 // empty patterns and comments match nothing.
257 if (!options.nocomment && pattern.charAt(0) === '#') {
258 this.comment = true;
259 return;
260 }
261 if (!pattern) {
262 this.empty = true;
263 return;
264 }
265 // step 1: figure out negation, etc.
266 this.parseNegate();
267 // step 2: expand braces
268 this.globSet = [...new Set(this.braceExpand())];
269 if (options.debug) {
270 //oxlint-disable-next-line no-console
271 this.debug = (...args) => console.error(...args);
272 }
273 this.debug(this.pattern, this.globSet);
274 // step 3: now we have a set, so turn each one into a series of
275 // path-portion matching patterns.
276 // These will be regexps, except in the case of "**", which is
277 // set to the GLOBSTAR object for globstar behavior,
278 // and will not contain any / characters
279 //
280 // First, we preprocess to make the glob pattern sets a bit simpler
281 // and deduped. There are some perf-killing patterns that can cause
282 // problems with a glob walk, but we can simplify them down a bit.
283 const rawGlobParts = this.globSet.map(s => this.slashSplit(s));
284 this.globParts = this.preprocess(rawGlobParts);
285 this.debug(this.pattern, this.globParts);
286 // glob --> regexps
287 let set = this.globParts.map((s, _, __) => {
288 if (this.isWindows && this.windowsNoMagicRoot) {
289 // check if it's a drive or unc path.
290 const isUNC = s[0] === '' &&
291 s[1] === '' &&
292 (s[2] === '?' || !globMagic.test(s[2])) &&
293 !globMagic.test(s[3]);
294 const isDrive = /^[a-z]:/i.test(s[0]);
295 if (isUNC) {
296 return [
297 ...s.slice(0, 4),
298 ...s.slice(4).map(ss => this.parse(ss)),
299 ];
300 }
301 else if (isDrive) {
302 return [s[0], ...s.slice(1).map(ss => this.parse(ss))];
303 }
304 }
305 return s.map(ss => this.parse(ss));
306 });
307 this.debug(this.pattern, set);
308 // filter out everything that didn't compile properly.
309 this.set = set.filter(s => s.indexOf(false) === -1);
310 // do not treat the ? in UNC paths as magic
311 if (this.isWindows) {
312 for (let i = 0; i < this.set.length; i++) {
313 const p = this.set[i];
314 if (p[0] === '' &&
315 p[1] === '' &&
316 this.globParts[i][2] === '?' &&
317 typeof p[3] === 'string' &&
318 /^[a-z]:$/i.test(p[3])) {
319 p[2] = '?';
320 }
321 }
322 }
323 this.debug(this.pattern, this.set);
324 }
325 // various transforms to equivalent pattern sets that are
326 // faster to process in a filesystem walk. The goal is to
327 // eliminate what we can, and push all ** patterns as far
328 // to the right as possible, even if it increases the number
329 // of patterns that we have to process.
330 preprocess(globParts) {
331 // if we're not in globstar mode, then turn ** into *
332 if (this.options.noglobstar) {
333 for (const partset of globParts) {
334 for (let j = 0; j < partset.length; j++) {
335 if (partset[j] === '**') {
336 partset[j] = '*';
337 }
338 }
339 }
340 }
341 const { optimizationLevel = 1 } = this.options;
342 if (optimizationLevel >= 2) {
343 // aggressive optimization for the purpose of fs walking
344 globParts = this.firstPhasePreProcess(globParts);
345 globParts = this.secondPhasePreProcess(globParts);
346 }
347 else if (optimizationLevel >= 1) {
348 // just basic optimizations to remove some .. parts
349 globParts = this.levelOneOptimize(globParts);
350 }
351 else {
352 // just collapse multiple ** portions into one
353 globParts = this.adjascentGlobstarOptimize(globParts);
354 }
355 return globParts;
356 }
357 // just get rid of adjascent ** portions
358 adjascentGlobstarOptimize(globParts) {
359 return globParts.map(parts => {
360 let gs = -1;
361 while (-1 !== (gs = parts.indexOf('**', gs + 1))) {
362 let i = gs;
363 while (parts[i + 1] === '**') {
364 i++;
365 }
366 if (i !== gs) {
367 parts.splice(gs, i - gs);
368 }
369 }
370 return parts;
371 });
372 }
373 // get rid of adjascent ** and resolve .. portions
374 levelOneOptimize(globParts) {
375 return globParts.map(parts => {
376 parts = parts.reduce((set, part) => {
377 const prev = set[set.length - 1];
378 if (part === '**' && prev === '**') {
379 return set;
380 }
381 if (part === '..') {
382 if (prev && prev !== '..' && prev !== '.' && prev !== '**') {
383 set.pop();
384 return set;
385 }
386 }
387 set.push(part);
388 return set;
389 }, []);
390 return parts.length === 0 ? [''] : parts;
391 });
392 }
393 levelTwoFileOptimize(parts) {
394 if (!Array.isArray(parts)) {
395 parts = this.slashSplit(parts);
396 }
397 let didSomething = false;
398 do {
399 didSomething = false;
400 // <pre>/<e>/<rest> -> <pre>/<rest>
401 if (!this.preserveMultipleSlashes) {
402 for (let i = 1; i < parts.length - 1; i++) {
403 const p = parts[i];
404 // don't squeeze out UNC patterns
405 if (i === 1 && p === '' && parts[0] === '')
406 continue;
407 if (p === '.' || p === '') {
408 didSomething = true;
409 parts.splice(i, 1);
410 i--;
411 }
412 }
413 if (parts[0] === '.' &&
414 parts.length === 2 &&
415 (parts[1] === '.' || parts[1] === '')) {
416 didSomething = true;
417 parts.pop();
418 }
419 }
420 // <pre>/<p>/../<rest> -> <pre>/<rest>
421 let dd = 0;
422 while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
423 const p = parts[dd - 1];
424 if (p &&
425 p !== '.' &&
426 p !== '..' &&
427 p !== '**' &&
428 !(this.isWindows && /^[a-z]:$/i.test(p))) {
429 didSomething = true;
430 parts.splice(dd - 1, 2);
431 dd -= 2;
432 }
433 }
434 } while (didSomething);
435 return parts.length === 0 ? [''] : parts;
436 }
437 // First phase: single-pattern processing
438 // <pre> is 1 or more portions
439 // <rest> is 1 or more portions
440 // <p> is any portion other than ., .., '', or **
441 // <e> is . or ''
442 //
443 // **/.. is *brutal* for filesystem walking performance, because
444 // it effectively resets the recursive walk each time it occurs,
445 // and ** cannot be reduced out by a .. pattern part like a regexp
446 // or most strings (other than .., ., and '') can be.
447 //
448 // <pre>/**/../<p>/<p>/<rest> -> {<pre>/../<p>/<p>/<rest>,<pre>/**/<p>/<p>/<rest>}
449 // <pre>/<e>/<rest> -> <pre>/<rest>
450 // <pre>/<p>/../<rest> -> <pre>/<rest>
451 // **/**/<rest> -> **/<rest>
452 //
453 // **/*/<rest> -> */**/<rest> <== not valid because ** doesn't follow
454 // this WOULD be allowed if ** did follow symlinks, or * didn't
455 firstPhasePreProcess(globParts) {
456 let didSomething = false;
457 do {
458 didSomething = false;
459 // <pre>/**/../<p>/<p>/<rest> -> {<pre>/../<p>/<p>/<rest>,<pre>/**/<p>/<p>/<rest>}
460 for (let parts of globParts) {
461 let gs = -1;
462 while (-1 !== (gs = parts.indexOf('**', gs + 1))) {
463 let gss = gs;
464 while (parts[gss + 1] === '**') {
465 // <pre>/**/**/<rest> -> <pre>/**/<rest>
466 gss++;
467 }
468 // eg, if gs is 2 and gss is 4, that means we have 3 **
469 // parts, and can remove 2 of them.
470 if (gss > gs) {
471 parts.splice(gs + 1, gss - gs);
472 }
473 let next = parts[gs + 1];
474 const p = parts[gs + 2];
475 const p2 = parts[gs + 3];
476 if (next !== '..')
477 continue;
478 if (!p ||
479 p === '.' ||
480 p === '..' ||
481 !p2 ||
482 p2 === '.' ||
483 p2 === '..') {
484 continue;
485 }
486 didSomething = true;
487 // edit parts in place, and push the new one
488 parts.splice(gs, 1);
489 const other = parts.slice(0);
490 other[gs] = '**';
491 globParts.push(other);
492 gs--;
493 }
494 // <pre>/<e>/<rest> -> <pre>/<rest>
495 if (!this.preserveMultipleSlashes) {
496 for (let i = 1; i < parts.length - 1; i++) {
497 const p = parts[i];
498 // don't squeeze out UNC patterns
499 if (i === 1 && p === '' && parts[0] === '')
500 continue;
501 if (p === '.' || p === '') {
502 didSomething = true;
503 parts.splice(i, 1);
504 i--;
505 }
506 }
507 if (parts[0] === '.' &&
508 parts.length === 2 &&
509 (parts[1] === '.' || parts[1] === '')) {
510 didSomething = true;
511 parts.pop();
512 }
513 }
514 // <pre>/<p>/../<rest> -> <pre>/<rest>
515 let dd = 0;
516 while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
517 const p = parts[dd - 1];
518 if (p && p !== '.' && p !== '..' && p !== '**') {
519 didSomething = true;
520 const needDot = dd === 1 && parts[dd + 1] === '**';
521 const splin = needDot ? ['.'] : [];
522 parts.splice(dd - 1, 2, ...splin);
523 if (parts.length === 0)
524 parts.push('');
525 dd -= 2;
526 }
527 }
528 }
529 } while (didSomething);
530 return globParts;
531 }
532 // second phase: multi-pattern dedupes
533 // {<pre>/*/<rest>,<pre>/<p>/<rest>} -> <pre>/*/<rest>
534 // {<pre>/<rest>,<pre>/<rest>} -> <pre>/<rest>
535 // {<pre>/**/<rest>,<pre>/<rest>} -> <pre>/**/<rest>
536 //
537 // {<pre>/**/<rest>,<pre>/**/<p>/<rest>} -> <pre>/**/<rest>
538 // ^-- not valid because ** doens't follow symlinks
539 secondPhasePreProcess(globParts) {
540 for (let i = 0; i < globParts.length - 1; i++) {
541 for (let j = i + 1; j < globParts.length; j++) {
542 const matched = this.partsMatch(globParts[i], globParts[j], !this.preserveMultipleSlashes);
543 if (matched) {
544 globParts[i] = [];
545 globParts[j] = matched;
546 break;
547 }
548 }
549 }
550 return globParts.filter(gs => gs.length);
551 }
552 partsMatch(a, b, emptyGSMatch = false) {
553 let ai = 0;
554 let bi = 0;
555 let result = [];
556 let which = '';
557 while (ai < a.length && bi < b.length) {
558 if (a[ai] === b[bi]) {
559 result.push(which === 'b' ? b[bi] : a[ai]);
560 ai++;
561 bi++;
562 }
563 else if (emptyGSMatch && a[ai] === '**' && b[bi] === a[ai + 1]) {
564 result.push(a[ai]);
565 ai++;
566 }
567 else if (emptyGSMatch && b[bi] === '**' && a[ai] === b[bi + 1]) {
568 result.push(b[bi]);
569 bi++;
570 }
571 else if (a[ai] === '*' &&
572 b[bi] &&
573 (this.options.dot || !b[bi].startsWith('.')) &&
574 b[bi] !== '**') {
575 if (which === 'b')
576 return false;
577 which = 'a';
578 result.push(a[ai]);
579 ai++;
580 bi++;
581 }
582 else if (b[bi] === '*' &&
583 a[ai] &&
584 (this.options.dot || !a[ai].startsWith('.')) &&
585 a[ai] !== '**') {
586 if (which === 'a')
587 return false;
588 which = 'b';
589 result.push(b[bi]);
590 ai++;
591 bi++;
592 }
593 else {
594 return false;
595 }
596 }
597 // if we fall out of the loop, it means they two are identical
598 // as long as their lengths match
599 return a.length === b.length && result;
600 }
601 parseNegate() {
602 if (this.nonegate)
603 return;
604 const pattern = this.pattern;
605 let negate = false;
606 let negateOffset = 0;
607 for (let i = 0; i < pattern.length && pattern.charAt(i) === '!'; i++) {
608 negate = !negate;
609 negateOffset++;
610 }
611 if (negateOffset)
612 this.pattern = pattern.slice(negateOffset);
613 this.negate = negate;
614 }
615 // set partial to true to test if, for example,
616 // "/a/b" matches the start of "/*/b/*/d"
617 // Partial means, if you run out of file before you run
618 // out of pattern, then that's fine, as long as all
619 // the parts match.
620 matchOne(file, pattern, partial = false) {
621 let fileStartIndex = 0;
622 let patternStartIndex = 0;
623 // UNC paths like //?/X:/... can match X:/... and vice versa
624 // Drive letters in absolute drive or unc paths are always compared
625 // case-insensitively.
626 if (this.isWindows) {
627 const fileDrive = typeof file[0] === 'string' && /^[a-z]:$/i.test(file[0]);
628 const fileUNC = !fileDrive &&
629 file[0] === '' &&
630 file[1] === '' &&
631 file[2] === '?' &&
632 /^[a-z]:$/i.test(file[3]);
633 const patternDrive = typeof pattern[0] === 'string' && /^[a-z]:$/i.test(pattern[0]);
634 const patternUNC = !patternDrive &&
635 pattern[0] === '' &&
636 pattern[1] === '' &&
637 pattern[2] === '?' &&
638 typeof pattern[3] === 'string' &&
639 /^[a-z]:$/i.test(pattern[3]);
640 const fdi = fileUNC ? 3
641 : fileDrive ? 0
642 : undefined;
643 const pdi = patternUNC ? 3
644 : patternDrive ? 0
645 : undefined;
646 if (typeof fdi === 'number' && typeof pdi === 'number') {
647 const [fd, pd] = [
648 file[fdi],
649 pattern[pdi],
650 ];
651 // start matching at the drive letter index of each
652 if (fd.toLowerCase() === pd.toLowerCase()) {
653 pattern[pdi] = fd;
654 patternStartIndex = pdi;
655 fileStartIndex = fdi;
656 }
657 }
658 }
659 // resolve and reduce . and .. portions in the file as well.
660 // don't need to do the second phase, because it's only one string[]
661 const { optimizationLevel = 1 } = this.options;
662 if (optimizationLevel >= 2) {
663 file = this.levelTwoFileOptimize(file);
664 }
665 if (pattern.includes(exports.GLOBSTAR)) {
666 return this.#matchGlobstar(file, pattern, partial, fileStartIndex, patternStartIndex);
667 }
668 return this.#matchOne(file, pattern, partial, fileStartIndex, patternStartIndex);
669 }
670 #matchGlobstar(file, pattern, partial, fileIndex, patternIndex) {
671 // split the pattern into head, tail, and middle of ** delimited parts
672 const firstgs = pattern.indexOf(exports.GLOBSTAR, patternIndex);
673 const lastgs = pattern.lastIndexOf(exports.GLOBSTAR);
674 // split the pattern up into globstar-delimited sections
675 // the tail has to be at the end, and the others just have
676 // to be found in order from the head.
677 const [head, body, tail] = partial ?
678 [
679 pattern.slice(patternIndex, firstgs),
680 pattern.slice(firstgs + 1),
681 [],
682 ]
683 : [
684 pattern.slice(patternIndex, firstgs),
685 pattern.slice(firstgs + 1, lastgs),
686 pattern.slice(lastgs + 1),
687 ];
688 // check the head, from the current file/pattern index.
689 if (head.length) {
690 const fileHead = file.slice(fileIndex, fileIndex + head.length);
691 if (!this.#matchOne(fileHead, head, partial, 0, 0)) {
692 return false;
693 }
694 fileIndex += head.length;
695 patternIndex += head.length;
696 }
697 // now we know the head matches!
698 // if the last portion is not empty, it MUST match the end
699 // check the tail
700 let fileTailMatch = 0;
701 if (tail.length) {
702 // if head + tail > file, then we cannot possibly match
703 if (tail.length + fileIndex > file.length)
704 return false;
705 // try to match the tail
706 let tailStart = file.length - tail.length;
707 if (this.#matchOne(file, tail, partial, tailStart, 0)) {
708 fileTailMatch = tail.length;
709 }
710 else {
711 // affordance for stuff like a/**/* matching a/b/
712 // if the last file portion is '', and there's more to the pattern
713 // then try without the '' bit.
714 if (file[file.length - 1] !== '' ||
715 fileIndex + tail.length === file.length) {
716 return false;
717 }
718 tailStart--;
719 if (!this.#matchOne(file, tail, partial, tailStart, 0)) {
720 return false;
721 }
722 fileTailMatch = tail.length + 1;
723 }
724 }
725 // now we know the tail matches!
726 // the middle is zero or more portions wrapped in **, possibly
727 // containing more ** sections.
728 // so a/**/b/**/c/**/d has become **/b/**/c/**
729 // if it's empty, it means a/**/b, just verify we have no bad dots
730 // if there's no tail, so it ends on /**, then we must have *something*
731 // after the head, or it's not a matc
732 if (!body.length) {
733 let sawSome = !!fileTailMatch;
734 for (let i = fileIndex; i < file.length - fileTailMatch; i++) {
735 const f = String(file[i]);
736 sawSome = true;
737 if (f === '.' ||
738 f === '..' ||
739 (!this.options.dot && f.startsWith('.'))) {
740 return false;
741 }
742 }
743 // in partial mode, we just need to get past all file parts
744 return partial || sawSome;
745 }
746 // now we know that there's one or more body sections, which can
747 // be matched anywhere from the 0 index (because the head was pruned)
748 // through to the length-fileTailMatch index.
749 // split the body up into sections, and note the minimum index it can
750 // be found at (start with the length of all previous segments)
751 // [section, before, after]
752 const bodySegments = [[[], 0]];
753 let currentBody = bodySegments[0];
754 let nonGsParts = 0;
755 const nonGsPartsSums = [0];
756 for (const b of body) {
757 if (b === exports.GLOBSTAR) {
758 nonGsPartsSums.push(nonGsParts);
759 currentBody = [[], 0];
760 bodySegments.push(currentBody);
761 }
762 else {
763 currentBody[0].push(b);
764 nonGsParts++;
765 }
766 }
767 let i = bodySegments.length - 1;
768 const fileLength = file.length - fileTailMatch;
769 for (const b of bodySegments) {
770 b[1] = fileLength - (nonGsPartsSums[i--] + b[0].length);
771 }
772 return !!this.#matchGlobStarBodySections(file, bodySegments, fileIndex, 0, partial, 0, !!fileTailMatch);
773 }
774 // return false for "nope, not matching"
775 // return null for "not matching, cannot keep trying"
776 #matchGlobStarBodySections(file,
777 // pattern section, last possible position for it
778 bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail) {
779 // take the first body segment, and walk from fileIndex to its "after"
780 // value at the end
781 // If it doesn't match at that position, we increment, until we hit
782 // that final possible position, and give up.
783 // If it does match, then advance and try to rest.
784 // If any of them fail we keep walking forward.
785 // this is still a bit recursively painful, but it's more constrained
786 // than previous implementations, because we never test something that
787 // can't possibly be a valid matching condition.
788 const bs = bodySegments[bodyIndex];
789 if (!bs) {
790 // just make sure that there's no bad dots
791 for (let i = fileIndex; i < file.length; i++) {
792 sawTail = true;
793 const f = file[i];
794 if (f === '.' ||
795 f === '..' ||
796 (!this.options.dot && f.startsWith('.'))) {
797 return false;
798 }
799 }
800 return sawTail;
801 }
802 // have a non-globstar body section to test
803 const [body, after] = bs;
804 while (fileIndex <= after) {
805 const m = this.#matchOne(file.slice(0, fileIndex + body.length), body, partial, fileIndex, 0);
806 // if limit exceeded, no match. intentional false negative,
807 // acceptable break in correctness for security.
808 if (m && globStarDepth < this.maxGlobstarRecursion) {
809 // match! see if the rest match. if so, we're done!
810 const sub = this.#matchGlobStarBodySections(file, bodySegments, fileIndex + body.length, bodyIndex + 1, partial, globStarDepth + 1, sawTail);
811 if (sub !== false) {
812 return sub;
813 }
814 }
815 const f = file[fileIndex];
816 if (f === '.' ||
817 f === '..' ||
818 (!this.options.dot && f.startsWith('.'))) {
819 return false;
820 }
821 fileIndex++;
822 }
823 // walked off. no point continuing
824 return partial || null;
825 }
826 #matchOne(file, pattern, partial, fileIndex, patternIndex) {
827 let fi;
828 let pi;
829 let pl;
830 let fl;
831 for (fi = fileIndex,
832 pi = patternIndex,
833 fl = file.length,
834 pl = pattern.length; fi < fl && pi < pl; fi++, pi++) {
835 this.debug('matchOne loop');
836 let p = pattern[pi];
837 let f = file[fi];
838 this.debug(pattern, p, f);
839 // should be impossible.
840 // some invalid regexp stuff in the set.
841 /* c8 ignore start */
842 if (p === false || p === exports.GLOBSTAR) {
843 return false;
844 }
845 /* c8 ignore stop */
846 // something other than **
847 // non-magic patterns just have to match exactly
848 // patterns with magic have been turned into regexps.
849 let hit;
850 if (typeof p === 'string') {
851 hit = f === p;
852 this.debug('string match', p, f, hit);
853 }
854 else {
855 hit = p.test(f);
856 this.debug('pattern match', p, f, hit);
857 }
858 if (!hit)
859 return false;
860 }
861 // Note: ending in / means that we'll get a final ""
862 // at the end of the pattern. This can only match a
863 // corresponding "" at the end of the file.
864 // If the file ends in /, then it can only match a
865 // a pattern that ends in /, unless the pattern just
866 // doesn't have any more for it. But, a/b/ should *not*
867 // match "a/b/*", even though "" matches against the
868 // [^/]*? pattern, except in partial mode, where it might
869 // simply not be reached yet.
870 // However, a/b/ should still satisfy a/*
871 // now either we fell off the end of the pattern, or we're done.
872 if (fi === fl && pi === pl) {
873 // ran out of pattern and filename at the same time.
874 // an exact hit!
875 return true;
876 }
877 else if (fi === fl) {
878 // ran out of file, but still had pattern left.
879 // this is ok if we're doing the match as part of
880 // a glob fs traversal.
881 return partial;
882 }
883 else if (pi === pl) {
884 // ran out of pattern, still have file left.
885 // this is only acceptable if we're on the very last
886 // empty segment of a file with a trailing slash.
887 // a/* should match a/b/
888 return fi === fl - 1 && file[fi] === '';
889 /* c8 ignore start */
890 }
891 else {
892 // should be unreachable.
893 throw new Error('wtf?');
894 }
895 /* c8 ignore stop */
896 }
897 braceExpand() {
898 return (0, exports.braceExpand)(this.pattern, this.options);
899 }
900 parse(pattern) {
901 (0, assert_valid_pattern_js_1.assertValidPattern)(pattern);
902 const options = this.options;
903 // shortcuts
904 if (pattern === '**')
905 return exports.GLOBSTAR;
906 if (pattern === '')
907 return '';
908 // far and away, the most common glob pattern parts are
909 // *, *.*, and *.<ext> Add a fast check method for those.
910 let m;
911 let fastTest = null;
912 if ((m = pattern.match(starRE))) {
913 fastTest = options.dot ? starTestDot : starTest;
914 }
915 else if ((m = pattern.match(starDotExtRE))) {
916 fastTest = (options.nocase ?
917 options.dot ?
918 starDotExtTestNocaseDot
919 : starDotExtTestNocase
920 : options.dot ? starDotExtTestDot
921 : starDotExtTest)(m[1]);
922 }
923 else if ((m = pattern.match(qmarksRE))) {
924 fastTest = (options.nocase ?
925 options.dot ?
926 qmarksTestNocaseDot
927 : qmarksTestNocase
928 : options.dot ? qmarksTestDot
929 : qmarksTest)(m);
930 }
931 else if ((m = pattern.match(starDotStarRE))) {
932 fastTest = options.dot ? starDotStarTestDot : starDotStarTest;
933 }
934 else if ((m = pattern.match(dotStarRE))) {
935 fastTest = dotStarTest;
936 }
937 const re = ast_js_1.AST.fromGlob(pattern, this.options).toMMPattern();
938 if (fastTest && typeof re === 'object') {
939 // Avoids overriding in frozen environments
940 Reflect.defineProperty(re, 'test', { value: fastTest });
941 }
942 return re;
943 }
944 makeRe() {
945 if (this.regexp || this.regexp === false)
946 return this.regexp;
947 // at this point, this.set is a 2d array of partial
948 // pattern strings, or "**".
949 //
950 // It's better to use .match(). This function shouldn't
951 // be used, really, but it's pretty convenient sometimes,
952 // when you just want to work with a regex.
953 const set = this.set;
954 if (!set.length) {
955 this.regexp = false;
956 return this.regexp;
957 }
958 const options = this.options;
959 const twoStar = options.noglobstar ? star
960 : options.dot ? twoStarDot
961 : twoStarNoDot;
962 const flags = new Set(options.nocase ? ['i'] : []);
963 // regexpify non-globstar patterns
964 // if ** is only item, then we just do one twoStar
965 // if ** is first, and there are more, prepend (\/|twoStar\/)? to next
966 // if ** is last, append (\/twoStar|) to previous
967 // if ** is in the middle, append (\/|\/twoStar\/) to previous
968 // then filter out GLOBSTAR symbols
969 let re = set
970 .map(pattern => {
971 const pp = pattern.map(p => {
972 if (p instanceof RegExp) {
973 for (const f of p.flags.split(''))
974 flags.add(f);
975 }
976 return (typeof p === 'string' ? regExpEscape(p)
977 : p === exports.GLOBSTAR ? exports.GLOBSTAR
978 : p._src);
979 });
980 pp.forEach((p, i) => {
981 const next = pp[i + 1];
982 const prev = pp[i - 1];
983 if (p !== exports.GLOBSTAR || prev === exports.GLOBSTAR) {
984 return;
985 }
986 if (prev === undefined) {
987 if (next !== undefined && next !== exports.GLOBSTAR) {
988 pp[i + 1] = '(?:\\/|' + twoStar + '\\/)?' + next;
989 }
990 else {
991 pp[i] = twoStar;
992 }
993 }
994 else if (next === undefined) {
995 pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + ')?';
996 }
997 else if (next !== exports.GLOBSTAR) {
998 pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + '\\/)' + next;
999 pp[i + 1] = exports.GLOBSTAR;
1000 }
1001 });
1002 const filtered = pp.filter(p => p !== exports.GLOBSTAR);
1003 // For partial matches, we need to make the pattern match
1004 // any prefix of the full path. We do this by generating
1005 // alternative patterns that match progressively longer prefixes.
1006 if (this.partial && filtered.length >= 1) {
1007 const prefixes = [];
1008 for (let i = 1; i <= filtered.length; i++) {
1009 prefixes.push(filtered.slice(0, i).join('/'));
1010 }
1011 return '(?:' + prefixes.join('|') + ')';
1012 }
1013 return filtered.join('/');
1014 })
1015 .join('|');
1016 // need to wrap in parens if we had more than one thing with |,
1017 // otherwise only the first will be anchored to ^ and the last to $
1018 const [open, close] = set.length > 1 ? ['(?:', ')'] : ['', ''];
1019 // must match entire pattern
1020 // ending in a * or ** will make it less strict.
1021 re = '^' + open + re + close + '$';
1022 // In partial mode, '/' should always match as it's a valid prefix for any pattern
1023 if (this.partial) {
1024 re = '^(?:\\/|' + open + re.slice(1, -1) + close + ')$';
1025 }
1026 // can match anything, as long as it's not this.
1027 if (this.negate)
1028 re = '^(?!' + re + ').+$';
1029 try {
1030 this.regexp = new RegExp(re, [...flags].join(''));
1031 /* c8 ignore start */
1032 }
1033 catch {
1034 // should be impossible
1035 this.regexp = false;
1036 }
1037 /* c8 ignore stop */
1038 return this.regexp;
1039 }
1040 slashSplit(p) {
1041 // if p starts with // on windows, we preserve that
1042 // so that UNC paths aren't broken. Otherwise, any number of
1043 // / characters are coalesced into one, unless
1044 // preserveMultipleSlashes is set to true.
1045 if (this.preserveMultipleSlashes) {
1046 return p.split('/');
1047 }
1048 else if (this.isWindows && /^\/\/[^/]+/.test(p)) {
1049 // add an extra '' for the one we lose
1050 return ['', ...p.split(/\/+/)];
1051 }
1052 else {
1053 return p.split(/\/+/);
1054 }
1055 }
1056 match(f, partial = this.partial) {
1057 this.debug('match', f, this.pattern);
1058 // short-circuit in the case of busted things.
1059 // comments, etc.
1060 if (this.comment) {
1061 return false;
1062 }
1063 if (this.empty) {
1064 return f === '';
1065 }
1066 if (f === '/' && partial) {
1067 return true;
1068 }
1069 const options = this.options;
1070 // windows: need to use /, not \
1071 if (this.isWindows) {
1072 f = f.split('\\').join('/');
1073 }
1074 // treat the test path as a set of pathparts.
1075 const ff = this.slashSplit(f);
1076 this.debug(this.pattern, 'split', ff);
1077 // just ONE of the pattern sets in this.set needs to match
1078 // in order for it to be valid. If negating, then just one
1079 // match means that we have failed.
1080 // Either way, return on the first hit.
1081 const set = this.set;
1082 this.debug(this.pattern, 'set', set);
1083 // Find the basename of the path by looking for the last non-empty segment
1084 let filename = ff[ff.length - 1];
1085 if (!filename) {
1086 for (let i = ff.length - 2; !filename && i >= 0; i--) {
1087 filename = ff[i];
1088 }
1089 }
1090 for (const pattern of set) {
1091 let file = ff;
1092 if (options.matchBase && pattern.length === 1) {
1093 file = [filename];
1094 }
1095 const hit = this.matchOne(file, pattern, partial);
1096 if (hit) {
1097 if (options.flipNegate) {
1098 return true;
1099 }
1100 return !this.negate;
1101 }
1102 }
1103 // didn't get any hits. this is success if it's a negative
1104 // pattern, failure otherwise.
1105 if (options.flipNegate) {
1106 return false;
1107 }
1108 return this.negate;
1109 }
1110 static defaults(def) {
1111 return exports.minimatch.defaults(def).Minimatch;
1112 }
1113}
1114exports.Minimatch = Minimatch;
1115/* c8 ignore start */
1116var ast_js_2 = require("./ast.js");
1117Object.defineProperty(exports, "AST", { enumerable: true, get: function () { return ast_js_2.AST; } });
1118var escape_js_2 = require("./escape.js");
1119Object.defineProperty(exports, "escape", { enumerable: true, get: function () { return escape_js_2.escape; } });
1120var unescape_js_2 = require("./unescape.js");
1121Object.defineProperty(exports, "unescape", { enumerable: true, get: function () { return unescape_js_2.unescape; } });
1122/* c8 ignore stop */
1123exports.minimatch.AST = ast_js_1.AST;
1124exports.minimatch.Minimatch = Minimatch;
1125exports.minimatch.escape = escape_js_1.escape;
1126exports.minimatch.unescape = unescape_js_1.unescape;
1127//# sourceMappingURL=index.js.map
Note: See TracBrowser for help on using the repository browser.