source: node_modules/minimatch/dist/esm/index.js@ 81bc7da

finki-main main
Last change on this file since 81bc7da was 81bc7da, checked in by Klimentina Efremova <klimentina08642@…>, 3 months ago

Initial commit

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