index.js 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289
  1. import expand from 'brace-expansion';
  2. import { parseClass } from './brace-expressions.js';
  3. import { escape } from './escape.js';
  4. import { unescape } from './unescape.js';
  5. export const minimatch = (p, pattern, options = {}) => {
  6. assertValidPattern(pattern);
  7. // shortcut: comments match nothing.
  8. if (!options.nocomment && pattern.charAt(0) === '#') {
  9. return false;
  10. }
  11. return new Minimatch(pattern, options).match(p);
  12. };
  13. export default minimatch;
  14. // Optimized checking for the most common glob patterns.
  15. const starDotExtRE = /^\*+([^+@!?\*\[\(]*)$/;
  16. const starDotExtTest = (ext) => (f) => !f.startsWith('.') && f.endsWith(ext);
  17. const starDotExtTestDot = (ext) => (f) => f.endsWith(ext);
  18. const starDotExtTestNocase = (ext) => {
  19. ext = ext.toLowerCase();
  20. return (f) => !f.startsWith('.') && f.toLowerCase().endsWith(ext);
  21. };
  22. const starDotExtTestNocaseDot = (ext) => {
  23. ext = ext.toLowerCase();
  24. return (f) => f.toLowerCase().endsWith(ext);
  25. };
  26. const starDotStarRE = /^\*+\.\*+$/;
  27. const starDotStarTest = (f) => !f.startsWith('.') && f.includes('.');
  28. const starDotStarTestDot = (f) => f !== '.' && f !== '..' && f.includes('.');
  29. const dotStarRE = /^\.\*+$/;
  30. const dotStarTest = (f) => f !== '.' && f !== '..' && f.startsWith('.');
  31. const starRE = /^\*+$/;
  32. const starTest = (f) => f.length !== 0 && !f.startsWith('.');
  33. const starTestDot = (f) => f.length !== 0 && f !== '.' && f !== '..';
  34. const qmarksRE = /^\?+([^+@!?\*\[\(]*)?$/;
  35. const 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. };
  42. const 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. };
  49. const qmarksTestDot = ([$0, ext = '']) => {
  50. const noext = qmarksTestNoExtDot([$0]);
  51. return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
  52. };
  53. const qmarksTest = ([$0, ext = '']) => {
  54. const noext = qmarksTestNoExt([$0]);
  55. return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
  56. };
  57. const qmarksTestNoExt = ([$0]) => {
  58. const len = $0.length;
  59. return (f) => f.length === len && !f.startsWith('.');
  60. };
  61. const qmarksTestNoExtDot = ([$0]) => {
  62. const len = $0.length;
  63. return (f) => f.length === len && f !== '.' && f !== '..';
  64. };
  65. /* c8 ignore start */
  66. const defaultPlatform = (typeof process === 'object' && process
  67. ? (typeof process.env === 'object' &&
  68. process.env &&
  69. process.env.__MINIMATCH_TESTING_PLATFORM__) ||
  70. process.platform
  71. : 'posix');
  72. const path = {
  73. win32: { sep: '\\' },
  74. posix: { sep: '/' },
  75. };
  76. /* c8 ignore stop */
  77. export const sep = defaultPlatform === 'win32' ? path.win32.sep : path.posix.sep;
  78. minimatch.sep = sep;
  79. export const GLOBSTAR = Symbol('globstar **');
  80. minimatch.GLOBSTAR = GLOBSTAR;
  81. const plTypes = {
  82. '!': { open: '(?:(?!(?:', close: '))[^/]*?)' },
  83. '?': { open: '(?:', close: ')?' },
  84. '+': { open: '(?:', close: ')+' },
  85. '*': { open: '(?:', close: ')*' },
  86. '@': { open: '(?:', close: ')' },
  87. };
  88. // any single thing other than /
  89. // don't need to escape / when using new RegExp()
  90. const qmark = '[^/]';
  91. // * => any number of characters
  92. const star = qmark + '*?';
  93. // ** when dots are allowed. Anything goes, except .. and .
  94. // not (^ or / followed by one or two dots followed by $ or /),
  95. // followed by anything, any number of times.
  96. const twoStarDot = '(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?';
  97. // not a ^ or / followed by a dot,
  98. // followed by anything, any number of times.
  99. const twoStarNoDot = '(?:(?!(?:\\/|^)\\.).)*?';
  100. // "abc" -> { a:true, b:true, c:true }
  101. const charSet = (s) => s.split('').reduce((set, c) => {
  102. set[c] = true;
  103. return set;
  104. }, {});
  105. // characters that need to be escaped in RegExp.
  106. const reSpecials = charSet('().*{}+?[]^$\\!');
  107. // characters that indicate we have to add the pattern start
  108. const addPatternStartSet = charSet('[.(');
  109. export const filter = (pattern, options = {}) => (p) => minimatch(p, pattern, options);
  110. minimatch.filter = filter;
  111. const ext = (a, b = {}) => Object.assign({}, a, b);
  112. export const defaults = (def) => {
  113. if (!def || typeof def !== 'object' || !Object.keys(def).length) {
  114. return minimatch;
  115. }
  116. const orig = minimatch;
  117. const m = (p, pattern, options = {}) => orig(p, pattern, ext(def, options));
  118. return Object.assign(m, {
  119. Minimatch: class Minimatch extends orig.Minimatch {
  120. constructor(pattern, options = {}) {
  121. super(pattern, ext(def, options));
  122. }
  123. static defaults(options) {
  124. return orig.defaults(ext(def, options)).Minimatch;
  125. }
  126. },
  127. unescape: (s, options = {}) => orig.unescape(s, ext(def, options)),
  128. escape: (s, options = {}) => orig.escape(s, ext(def, options)),
  129. filter: (pattern, options = {}) => orig.filter(pattern, ext(def, options)),
  130. defaults: (options) => orig.defaults(ext(def, options)),
  131. makeRe: (pattern, options = {}) => orig.makeRe(pattern, ext(def, options)),
  132. braceExpand: (pattern, options = {}) => orig.braceExpand(pattern, ext(def, options)),
  133. match: (list, pattern, options = {}) => orig.match(list, pattern, ext(def, options)),
  134. sep: orig.sep,
  135. GLOBSTAR: GLOBSTAR,
  136. });
  137. };
  138. minimatch.defaults = 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
  149. export const braceExpand = (pattern, options = {}) => {
  150. 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 expand(pattern);
  158. };
  159. minimatch.braceExpand = braceExpand;
  160. const MAX_PATTERN_LENGTH = 1024 * 64;
  161. const assertValidPattern = (pattern) => {
  162. if (typeof pattern !== 'string') {
  163. throw new TypeError('invalid pattern');
  164. }
  165. if (pattern.length > MAX_PATTERN_LENGTH) {
  166. throw new TypeError('pattern is too long');
  167. }
  168. };
  169. // parse a component of the expanded set.
  170. // At this point, no pattern may contain "/" in it
  171. // so we're going to return a 2d array, where each entry is the full
  172. // pattern, split on '/', and then turned into a regular expression.
  173. // A regexp is made at the end which joins each array with an
  174. // escaped /, and another full one which joins each regexp with |.
  175. //
  176. // Following the lead of Bash 4.1, note that "**" only has special meaning
  177. // when it is the *only* thing in a path portion. Otherwise, any series
  178. // of * is equivalent to a single *. Globstar behavior is enabled by
  179. // default, and can be disabled by setting options.noglobstar.
  180. export const makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe();
  181. minimatch.makeRe = makeRe;
  182. export const match = (list, pattern, options = {}) => {
  183. const mm = new Minimatch(pattern, options);
  184. list = list.filter(f => mm.match(f));
  185. if (mm.options.nonull && !list.length) {
  186. list.push(pattern);
  187. }
  188. return list;
  189. };
  190. minimatch.match = match;
  191. // replace stuff like \* with *
  192. const globUnescape = (s) => s.replace(/\\(.)/g, '$1');
  193. const globMagic = /[?*]|[+@!]\(.*?\)|\[|\]/;
  194. const regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
  195. export class Minimatch {
  196. options;
  197. set;
  198. pattern;
  199. windowsPathsNoEscape;
  200. nonegate;
  201. negate;
  202. comment;
  203. empty;
  204. preserveMultipleSlashes;
  205. partial;
  206. globSet;
  207. globParts;
  208. nocase;
  209. isWindows;
  210. platform;
  211. windowsNoMagicRoot;
  212. regexp;
  213. constructor(pattern, options = {}) {
  214. assertValidPattern(pattern);
  215. options = options || {};
  216. this.options = options;
  217. this.pattern = pattern;
  218. this.platform = options.platform || defaultPlatform;
  219. this.isWindows = this.platform === 'win32';
  220. this.windowsPathsNoEscape =
  221. !!options.windowsPathsNoEscape || options.allowWindowsEscape === false;
  222. if (this.windowsPathsNoEscape) {
  223. this.pattern = this.pattern.replace(/\\/g, '/');
  224. }
  225. this.preserveMultipleSlashes = !!options.preserveMultipleSlashes;
  226. this.regexp = null;
  227. this.negate = false;
  228. this.nonegate = !!options.nonegate;
  229. this.comment = false;
  230. this.empty = false;
  231. this.partial = !!options.partial;
  232. this.nocase = !!this.options.nocase;
  233. this.windowsNoMagicRoot =
  234. options.windowsNoMagicRoot !== undefined
  235. ? options.windowsNoMagicRoot
  236. : !!(this.isWindows && this.nocase);
  237. this.globSet = [];
  238. this.globParts = [];
  239. this.set = [];
  240. // make the set of regexps etc.
  241. this.make();
  242. }
  243. hasMagic() {
  244. if (this.options.magicalBraces && this.set.length > 1) {
  245. return true;
  246. }
  247. for (const pattern of this.set) {
  248. for (const part of pattern) {
  249. if (typeof part !== 'string')
  250. return true;
  251. }
  252. }
  253. return false;
  254. }
  255. debug(..._) { }
  256. make() {
  257. const pattern = this.pattern;
  258. const options = this.options;
  259. // empty patterns and comments match nothing.
  260. if (!options.nocomment && pattern.charAt(0) === '#') {
  261. this.comment = true;
  262. return;
  263. }
  264. if (!pattern) {
  265. this.empty = true;
  266. return;
  267. }
  268. // step 1: figure out negation, etc.
  269. this.parseNegate();
  270. // step 2: expand braces
  271. this.globSet = [...new Set(this.braceExpand())];
  272. if (options.debug) {
  273. this.debug = (...args) => console.error(...args);
  274. }
  275. this.debug(this.pattern, this.globSet);
  276. // step 3: now we have a set, so turn each one into a series of
  277. // path-portion matching patterns.
  278. // These will be regexps, except in the case of "**", which is
  279. // set to the GLOBSTAR object for globstar behavior,
  280. // and will not contain any / characters
  281. //
  282. // First, we preprocess to make the glob pattern sets a bit simpler
  283. // and deduped. There are some perf-killing patterns that can cause
  284. // problems with a glob walk, but we can simplify them down a bit.
  285. const rawGlobParts = this.globSet.map(s => this.slashSplit(s));
  286. this.globParts = this.preprocess(rawGlobParts);
  287. this.debug(this.pattern, this.globParts);
  288. // glob --> regexps
  289. let set = this.globParts.map((s, _, __) => {
  290. if (this.isWindows && this.windowsNoMagicRoot) {
  291. // check if it's a drive or unc path.
  292. const isUNC = s[0] === '' &&
  293. s[1] === '' &&
  294. (s[2] === '?' || !globMagic.test(s[2])) &&
  295. !globMagic.test(s[3]);
  296. const isDrive = /^[a-z]:/i.test(s[0]);
  297. if (isUNC) {
  298. return [...s.slice(0, 4), ...s.slice(4).map(ss => this.parse(ss))];
  299. }
  300. else if (isDrive) {
  301. return [s[0], ...s.slice(1).map(ss => this.parse(ss))];
  302. }
  303. }
  304. return s.map(ss => this.parse(ss));
  305. });
  306. this.debug(this.pattern, set);
  307. // filter out everything that didn't compile properly.
  308. this.set = set.filter(s => s.indexOf(false) === -1);
  309. // do not treat the ? in UNC paths as magic
  310. if (this.isWindows) {
  311. for (let i = 0; i < this.set.length; i++) {
  312. const p = this.set[i];
  313. if (p[0] === '' &&
  314. p[1] === '' &&
  315. this.globParts[i][2] === '?' &&
  316. typeof p[3] === 'string' &&
  317. /^[a-z]:$/i.test(p[3])) {
  318. p[2] = '?';
  319. }
  320. }
  321. }
  322. this.debug(this.pattern, this.set);
  323. }
  324. // various transforms to equivalent pattern sets that are
  325. // faster to process in a filesystem walk. The goal is to
  326. // eliminate what we can, and push all ** patterns as far
  327. // to the right as possible, even if it increases the number
  328. // of patterns that we have to process.
  329. preprocess(globParts) {
  330. // if we're not in globstar mode, then turn all ** into *
  331. if (this.options.noglobstar) {
  332. for (let i = 0; i < globParts.length; i++) {
  333. for (let j = 0; j < globParts[i].length; j++) {
  334. if (globParts[i][j] === '**') {
  335. globParts[i][j] = '*';
  336. }
  337. }
  338. }
  339. }
  340. const { optimizationLevel = 1 } = this.options;
  341. if (optimizationLevel >= 2) {
  342. // aggressive optimization for the purpose of fs walking
  343. globParts = this.firstPhasePreProcess(globParts);
  344. globParts = this.secondPhasePreProcess(globParts);
  345. }
  346. else if (optimizationLevel >= 1) {
  347. // just basic optimizations to remove some .. parts
  348. globParts = this.levelOneOptimize(globParts);
  349. }
  350. else {
  351. globParts = this.adjascentGlobstarOptimize(globParts);
  352. }
  353. return globParts;
  354. }
  355. // just get rid of adjascent ** portions
  356. adjascentGlobstarOptimize(globParts) {
  357. return globParts.map(parts => {
  358. let gs = -1;
  359. while (-1 !== (gs = parts.indexOf('**', gs + 1))) {
  360. let i = gs;
  361. while (parts[i + 1] === '**') {
  362. i++;
  363. }
  364. if (i !== gs) {
  365. parts.splice(gs, i - gs);
  366. }
  367. }
  368. return parts;
  369. });
  370. }
  371. // get rid of adjascent ** and resolve .. portions
  372. levelOneOptimize(globParts) {
  373. return globParts.map(parts => {
  374. parts = parts.reduce((set, part) => {
  375. const prev = set[set.length - 1];
  376. if (part === '**' && prev === '**') {
  377. return set;
  378. }
  379. if (part === '..') {
  380. if (prev && prev !== '..' && prev !== '.' && prev !== '**') {
  381. set.pop();
  382. return set;
  383. }
  384. }
  385. set.push(part);
  386. return set;
  387. }, []);
  388. return parts.length === 0 ? [''] : parts;
  389. });
  390. }
  391. levelTwoFileOptimize(parts) {
  392. if (!Array.isArray(parts)) {
  393. parts = this.slashSplit(parts);
  394. }
  395. let didSomething = false;
  396. do {
  397. didSomething = false;
  398. // <pre>/<e>/<rest> -> <pre>/<rest>
  399. if (!this.preserveMultipleSlashes) {
  400. for (let i = 1; i < parts.length - 1; i++) {
  401. const p = parts[i];
  402. // don't squeeze out UNC patterns
  403. if (i === 1 && p === '' && parts[0] === '')
  404. continue;
  405. if (p === '.' || p === '') {
  406. didSomething = true;
  407. parts.splice(i, 1);
  408. i--;
  409. }
  410. }
  411. if (parts[0] === '.' &&
  412. parts.length === 2 &&
  413. (parts[1] === '.' || parts[1] === '')) {
  414. didSomething = true;
  415. parts.pop();
  416. }
  417. }
  418. // <pre>/<p>/../<rest> -> <pre>/<rest>
  419. let dd = 0;
  420. while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
  421. const p = parts[dd - 1];
  422. if (p && p !== '.' && p !== '..' && p !== '**') {
  423. didSomething = true;
  424. parts.splice(dd - 1, 2);
  425. dd -= 2;
  426. }
  427. }
  428. } while (didSomething);
  429. return parts.length === 0 ? [''] : parts;
  430. }
  431. // First phase: single-pattern processing
  432. // <pre> is 1 or more portions
  433. // <rest> is 1 or more portions
  434. // <p> is any portion other than ., .., '', or **
  435. // <e> is . or ''
  436. //
  437. // **/.. is *brutal* for filesystem walking performance, because
  438. // it effectively resets the recursive walk each time it occurs,
  439. // and ** cannot be reduced out by a .. pattern part like a regexp
  440. // or most strings (other than .., ., and '') can be.
  441. //
  442. // <pre>/**/../<p>/<p>/<rest> -> {<pre>/../<p>/<p>/<rest>,<pre>/**/<p>/<p>/<rest>}
  443. // <pre>/<e>/<rest> -> <pre>/<rest>
  444. // <pre>/<p>/../<rest> -> <pre>/<rest>
  445. // **/**/<rest> -> **/<rest>
  446. //
  447. // **/*/<rest> -> */**/<rest> <== not valid because ** doesn't follow
  448. // this WOULD be allowed if ** did follow symlinks, or * didn't
  449. firstPhasePreProcess(globParts) {
  450. let didSomething = false;
  451. do {
  452. didSomething = false;
  453. // <pre>/**/../<p>/<p>/<rest> -> {<pre>/../<p>/<p>/<rest>,<pre>/**/<p>/<p>/<rest>}
  454. for (let parts of globParts) {
  455. let gs = -1;
  456. while (-1 !== (gs = parts.indexOf('**', gs + 1))) {
  457. let gss = gs;
  458. while (parts[gss + 1] === '**') {
  459. // <pre>/**/**/<rest> -> <pre>/**/<rest>
  460. gss++;
  461. }
  462. // eg, if gs is 2 and gss is 4, that means we have 3 **
  463. // parts, and can remove 2 of them.
  464. if (gss > gs) {
  465. parts.splice(gs + 1, gss - gs);
  466. }
  467. let next = parts[gs + 1];
  468. const p = parts[gs + 2];
  469. const p2 = parts[gs + 3];
  470. if (next !== '..')
  471. continue;
  472. if (!p ||
  473. p === '.' ||
  474. p === '..' ||
  475. !p2 ||
  476. p2 === '.' ||
  477. p2 === '..') {
  478. continue;
  479. }
  480. didSomething = true;
  481. // edit parts in place, and push the new one
  482. parts.splice(gs, 1);
  483. const other = parts.slice(0);
  484. other[gs] = '**';
  485. globParts.push(other);
  486. gs--;
  487. }
  488. // <pre>/<e>/<rest> -> <pre>/<rest>
  489. if (!this.preserveMultipleSlashes) {
  490. for (let i = 1; i < parts.length - 1; i++) {
  491. const p = parts[i];
  492. // don't squeeze out UNC patterns
  493. if (i === 1 && p === '' && parts[0] === '')
  494. continue;
  495. if (p === '.' || p === '') {
  496. didSomething = true;
  497. parts.splice(i, 1);
  498. i--;
  499. }
  500. }
  501. if (parts[0] === '.' &&
  502. parts.length === 2 &&
  503. (parts[1] === '.' || parts[1] === '')) {
  504. didSomething = true;
  505. parts.pop();
  506. }
  507. }
  508. // <pre>/<p>/../<rest> -> <pre>/<rest>
  509. let dd = 0;
  510. while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
  511. const p = parts[dd - 1];
  512. if (p && p !== '.' && p !== '..' && p !== '**') {
  513. didSomething = true;
  514. const needDot = dd === 1 && parts[dd + 1] === '**';
  515. const splin = needDot ? ['.'] : [];
  516. parts.splice(dd - 1, 2, ...splin);
  517. if (parts.length === 0)
  518. parts.push('');
  519. dd -= 2;
  520. }
  521. }
  522. }
  523. } while (didSomething);
  524. return globParts;
  525. }
  526. // second phase: multi-pattern dedupes
  527. // {<pre>/*/<rest>,<pre>/<p>/<rest>} -> <pre>/*/<rest>
  528. // {<pre>/<rest>,<pre>/<rest>} -> <pre>/<rest>
  529. // {<pre>/**/<rest>,<pre>/<rest>} -> <pre>/**/<rest>
  530. //
  531. // {<pre>/**/<rest>,<pre>/**/<p>/<rest>} -> <pre>/**/<rest>
  532. // ^-- not valid because ** doens't follow symlinks
  533. secondPhasePreProcess(globParts) {
  534. for (let i = 0; i < globParts.length - 1; i++) {
  535. for (let j = i + 1; j < globParts.length; j++) {
  536. const matched = this.partsMatch(globParts[i], globParts[j], !this.preserveMultipleSlashes);
  537. if (!matched)
  538. continue;
  539. globParts[i] = matched;
  540. globParts[j] = [];
  541. }
  542. }
  543. return globParts.filter(gs => gs.length);
  544. }
  545. partsMatch(a, b, emptyGSMatch = false) {
  546. let ai = 0;
  547. let bi = 0;
  548. let result = [];
  549. let which = '';
  550. while (ai < a.length && bi < b.length) {
  551. if (a[ai] === b[bi]) {
  552. result.push(which === 'b' ? b[bi] : a[ai]);
  553. ai++;
  554. bi++;
  555. }
  556. else if (emptyGSMatch && a[ai] === '**' && b[bi] === a[ai + 1]) {
  557. result.push(a[ai]);
  558. ai++;
  559. }
  560. else if (emptyGSMatch && b[bi] === '**' && a[ai] === b[bi + 1]) {
  561. result.push(b[bi]);
  562. bi++;
  563. }
  564. else if (a[ai] === '*' &&
  565. b[bi] &&
  566. (this.options.dot || !b[bi].startsWith('.')) &&
  567. b[bi] !== '**') {
  568. if (which === 'b')
  569. return false;
  570. which = 'a';
  571. result.push(a[ai]);
  572. ai++;
  573. bi++;
  574. }
  575. else if (b[bi] === '*' &&
  576. a[ai] &&
  577. (this.options.dot || !a[ai].startsWith('.')) &&
  578. a[ai] !== '**') {
  579. if (which === 'a')
  580. return false;
  581. which = 'b';
  582. result.push(b[bi]);
  583. ai++;
  584. bi++;
  585. }
  586. else {
  587. return false;
  588. }
  589. }
  590. // if we fall out of the loop, it means they two are identical
  591. // as long as their lengths match
  592. return a.length === b.length && result;
  593. }
  594. parseNegate() {
  595. if (this.nonegate)
  596. return;
  597. const pattern = this.pattern;
  598. let negate = false;
  599. let negateOffset = 0;
  600. for (let i = 0; i < pattern.length && pattern.charAt(i) === '!'; i++) {
  601. negate = !negate;
  602. negateOffset++;
  603. }
  604. if (negateOffset)
  605. this.pattern = pattern.slice(negateOffset);
  606. this.negate = negate;
  607. }
  608. // set partial to true to test if, for example,
  609. // "/a/b" matches the start of "/*/b/*/d"
  610. // Partial means, if you run out of file before you run
  611. // out of pattern, then that's fine, as long as all
  612. // the parts match.
  613. matchOne(file, pattern, partial = false) {
  614. const options = this.options;
  615. // a UNC pattern like //?/c:/* can match a path like c:/x
  616. // and vice versa
  617. if (this.isWindows) {
  618. const fileUNC = file[0] === '' &&
  619. file[1] === '' &&
  620. file[2] === '?' &&
  621. typeof file[3] === 'string' &&
  622. /^[a-z]:$/i.test(file[3]);
  623. const patternUNC = pattern[0] === '' &&
  624. pattern[1] === '' &&
  625. pattern[2] === '?' &&
  626. typeof pattern[3] === 'string' &&
  627. /^[a-z]:$/i.test(pattern[3]);
  628. if (fileUNC && patternUNC) {
  629. const fd = file[3];
  630. const pd = pattern[3];
  631. if (fd.toLowerCase() === pd.toLowerCase()) {
  632. file[3] = pd;
  633. }
  634. }
  635. else if (patternUNC && typeof file[0] === 'string') {
  636. const pd = pattern[3];
  637. const fd = file[0];
  638. if (pd.toLowerCase() === fd.toLowerCase()) {
  639. pattern[3] = fd;
  640. pattern = pattern.slice(3);
  641. }
  642. }
  643. else if (fileUNC && typeof pattern[0] === 'string') {
  644. const fd = file[3];
  645. if (fd.toLowerCase() === pattern[0].toLowerCase()) {
  646. pattern[0] = fd;
  647. file = file.slice(3);
  648. }
  649. }
  650. }
  651. // resolve and reduce . and .. portions in the file as well.
  652. // dont' need to do the second phase, because it's only one string[]
  653. const { optimizationLevel = 1 } = this.options;
  654. if (optimizationLevel >= 2) {
  655. file = this.levelTwoFileOptimize(file);
  656. }
  657. this.debug('matchOne', this, { file, pattern });
  658. this.debug('matchOne', file.length, pattern.length);
  659. for (var fi = 0, pi = 0, fl = file.length, pl = pattern.length; fi < fl && pi < pl; fi++, pi++) {
  660. this.debug('matchOne loop');
  661. var p = pattern[pi];
  662. var f = file[fi];
  663. this.debug(pattern, p, f);
  664. // should be impossible.
  665. // some invalid regexp stuff in the set.
  666. /* c8 ignore start */
  667. if (p === false) {
  668. return false;
  669. }
  670. /* c8 ignore stop */
  671. if (p === GLOBSTAR) {
  672. this.debug('GLOBSTAR', [pattern, p, f]);
  673. // "**"
  674. // a/**/b/**/c would match the following:
  675. // a/b/x/y/z/c
  676. // a/x/y/z/b/c
  677. // a/b/x/b/x/c
  678. // a/b/c
  679. // To do this, take the rest of the pattern after
  680. // the **, and see if it would match the file remainder.
  681. // If so, return success.
  682. // If not, the ** "swallows" a segment, and try again.
  683. // This is recursively awful.
  684. //
  685. // a/**/b/**/c matching a/b/x/y/z/c
  686. // - a matches a
  687. // - doublestar
  688. // - matchOne(b/x/y/z/c, b/**/c)
  689. // - b matches b
  690. // - doublestar
  691. // - matchOne(x/y/z/c, c) -> no
  692. // - matchOne(y/z/c, c) -> no
  693. // - matchOne(z/c, c) -> no
  694. // - matchOne(c, c) yes, hit
  695. var fr = fi;
  696. var pr = pi + 1;
  697. if (pr === pl) {
  698. this.debug('** at the end');
  699. // a ** at the end will just swallow the rest.
  700. // We have found a match.
  701. // however, it will not swallow /.x, unless
  702. // options.dot is set.
  703. // . and .. are *never* matched by **, for explosively
  704. // exponential reasons.
  705. for (; fi < fl; fi++) {
  706. if (file[fi] === '.' ||
  707. file[fi] === '..' ||
  708. (!options.dot && file[fi].charAt(0) === '.'))
  709. return false;
  710. }
  711. return true;
  712. }
  713. // ok, let's see if we can swallow whatever we can.
  714. while (fr < fl) {
  715. var swallowee = file[fr];
  716. this.debug('\nglobstar while', file, fr, pattern, pr, swallowee);
  717. // XXX remove this slice. Just pass the start index.
  718. if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
  719. this.debug('globstar found match!', fr, fl, swallowee);
  720. // found a match.
  721. return true;
  722. }
  723. else {
  724. // can't swallow "." or ".." ever.
  725. // can only swallow ".foo" when explicitly asked.
  726. if (swallowee === '.' ||
  727. swallowee === '..' ||
  728. (!options.dot && swallowee.charAt(0) === '.')) {
  729. this.debug('dot detected!', file, fr, pattern, pr);
  730. break;
  731. }
  732. // ** swallows a segment, and continue.
  733. this.debug('globstar swallow a segment, and continue');
  734. fr++;
  735. }
  736. }
  737. // no match was found.
  738. // However, in partial mode, we can't say this is necessarily over.
  739. /* c8 ignore start */
  740. if (partial) {
  741. // ran out of file
  742. this.debug('\n>>> no match, partial?', file, fr, pattern, pr);
  743. if (fr === fl) {
  744. return true;
  745. }
  746. }
  747. /* c8 ignore stop */
  748. return false;
  749. }
  750. // something other than **
  751. // non-magic patterns just have to match exactly
  752. // patterns with magic have been turned into regexps.
  753. let hit;
  754. if (typeof p === 'string') {
  755. hit = f === p;
  756. this.debug('string match', p, f, hit);
  757. }
  758. else {
  759. hit = p.test(f);
  760. this.debug('pattern match', p, f, hit);
  761. }
  762. if (!hit)
  763. return false;
  764. }
  765. // Note: ending in / means that we'll get a final ""
  766. // at the end of the pattern. This can only match a
  767. // corresponding "" at the end of the file.
  768. // If the file ends in /, then it can only match a
  769. // a pattern that ends in /, unless the pattern just
  770. // doesn't have any more for it. But, a/b/ should *not*
  771. // match "a/b/*", even though "" matches against the
  772. // [^/]*? pattern, except in partial mode, where it might
  773. // simply not be reached yet.
  774. // However, a/b/ should still satisfy a/*
  775. // now either we fell off the end of the pattern, or we're done.
  776. if (fi === fl && pi === pl) {
  777. // ran out of pattern and filename at the same time.
  778. // an exact hit!
  779. return true;
  780. }
  781. else if (fi === fl) {
  782. // ran out of file, but still had pattern left.
  783. // this is ok if we're doing the match as part of
  784. // a glob fs traversal.
  785. return partial;
  786. }
  787. else if (pi === pl) {
  788. // ran out of pattern, still have file left.
  789. // this is only acceptable if we're on the very last
  790. // empty segment of a file with a trailing slash.
  791. // a/* should match a/b/
  792. return fi === fl - 1 && file[fi] === '';
  793. /* c8 ignore start */
  794. }
  795. else {
  796. // should be unreachable.
  797. throw new Error('wtf?');
  798. }
  799. /* c8 ignore stop */
  800. }
  801. braceExpand() {
  802. return braceExpand(this.pattern, this.options);
  803. }
  804. parse(pattern) {
  805. assertValidPattern(pattern);
  806. const options = this.options;
  807. // shortcuts
  808. if (pattern === '**')
  809. return GLOBSTAR;
  810. if (pattern === '')
  811. return '';
  812. // far and away, the most common glob pattern parts are
  813. // *, *.*, and *.<ext> Add a fast check method for those.
  814. let m;
  815. let fastTest = null;
  816. if ((m = pattern.match(starRE))) {
  817. fastTest = options.dot ? starTestDot : starTest;
  818. }
  819. else if ((m = pattern.match(starDotExtRE))) {
  820. fastTest = (options.nocase
  821. ? options.dot
  822. ? starDotExtTestNocaseDot
  823. : starDotExtTestNocase
  824. : options.dot
  825. ? starDotExtTestDot
  826. : starDotExtTest)(m[1]);
  827. }
  828. else if ((m = pattern.match(qmarksRE))) {
  829. fastTest = (options.nocase
  830. ? options.dot
  831. ? qmarksTestNocaseDot
  832. : qmarksTestNocase
  833. : options.dot
  834. ? qmarksTestDot
  835. : qmarksTest)(m);
  836. }
  837. else if ((m = pattern.match(starDotStarRE))) {
  838. fastTest = options.dot ? starDotStarTestDot : starDotStarTest;
  839. }
  840. else if ((m = pattern.match(dotStarRE))) {
  841. fastTest = dotStarTest;
  842. }
  843. let re = '';
  844. let hasMagic = false;
  845. let escaping = false;
  846. // ? => one single character
  847. const patternListStack = [];
  848. const negativeLists = [];
  849. let stateChar = false;
  850. let uflag = false;
  851. let pl;
  852. // . and .. never match anything that doesn't start with .,
  853. // even when options.dot is set. However, if the pattern
  854. // starts with ., then traversal patterns can match.
  855. let dotTravAllowed = pattern.charAt(0) === '.';
  856. let dotFileAllowed = options.dot || dotTravAllowed;
  857. const patternStart = () => dotTravAllowed
  858. ? ''
  859. : dotFileAllowed
  860. ? '(?!(?:^|\\/)\\.{1,2}(?:$|\\/))'
  861. : '(?!\\.)';
  862. const subPatternStart = (p) => p.charAt(0) === '.'
  863. ? ''
  864. : options.dot
  865. ? '(?!(?:^|\\/)\\.{1,2}(?:$|\\/))'
  866. : '(?!\\.)';
  867. const clearStateChar = () => {
  868. if (stateChar) {
  869. // we had some state-tracking character
  870. // that wasn't consumed by this pass.
  871. switch (stateChar) {
  872. case '*':
  873. re += star;
  874. hasMagic = true;
  875. break;
  876. case '?':
  877. re += qmark;
  878. hasMagic = true;
  879. break;
  880. default:
  881. re += '\\' + stateChar;
  882. break;
  883. }
  884. this.debug('clearStateChar %j %j', stateChar, re);
  885. stateChar = false;
  886. }
  887. };
  888. for (let i = 0, c; i < pattern.length && (c = pattern.charAt(i)); i++) {
  889. this.debug('%s\t%s %s %j', pattern, i, re, c);
  890. // skip over any that are escaped.
  891. if (escaping) {
  892. // completely not allowed, even escaped.
  893. // should be impossible.
  894. /* c8 ignore start */
  895. if (c === '/') {
  896. return false;
  897. }
  898. /* c8 ignore stop */
  899. if (reSpecials[c]) {
  900. re += '\\';
  901. }
  902. re += c;
  903. escaping = false;
  904. continue;
  905. }
  906. switch (c) {
  907. // Should already be path-split by now.
  908. /* c8 ignore start */
  909. case '/': {
  910. return false;
  911. }
  912. /* c8 ignore stop */
  913. case '\\':
  914. clearStateChar();
  915. escaping = true;
  916. continue;
  917. // the various stateChar values
  918. // for the "extglob" stuff.
  919. case '?':
  920. case '*':
  921. case '+':
  922. case '@':
  923. case '!':
  924. this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c);
  925. // if we already have a stateChar, then it means
  926. // that there was something like ** or +? in there.
  927. // Handle the stateChar, then proceed with this one.
  928. this.debug('call clearStateChar %j', stateChar);
  929. clearStateChar();
  930. stateChar = c;
  931. // if extglob is disabled, then +(asdf|foo) isn't a thing.
  932. // just clear the statechar *now*, rather than even diving into
  933. // the patternList stuff.
  934. if (options.noext)
  935. clearStateChar();
  936. continue;
  937. case '(': {
  938. if (!stateChar) {
  939. re += '\\(';
  940. continue;
  941. }
  942. const plEntry = {
  943. type: stateChar,
  944. start: i - 1,
  945. reStart: re.length,
  946. open: plTypes[stateChar].open,
  947. close: plTypes[stateChar].close,
  948. };
  949. this.debug(this.pattern, '\t', plEntry);
  950. patternListStack.push(plEntry);
  951. // negation is (?:(?!(?:js)(?:<rest>))[^/]*)
  952. re += plEntry.open;
  953. // next entry starts with a dot maybe?
  954. if (plEntry.start === 0 && plEntry.type !== '!') {
  955. dotTravAllowed = true;
  956. re += subPatternStart(pattern.slice(i + 1));
  957. }
  958. this.debug('plType %j %j', stateChar, re);
  959. stateChar = false;
  960. continue;
  961. }
  962. case ')': {
  963. const plEntry = patternListStack[patternListStack.length - 1];
  964. if (!plEntry) {
  965. re += '\\)';
  966. continue;
  967. }
  968. patternListStack.pop();
  969. // closing an extglob
  970. clearStateChar();
  971. hasMagic = true;
  972. pl = plEntry;
  973. // negation is (?:(?!js)[^/]*)
  974. // The others are (?:<pattern>)<type>
  975. re += pl.close;
  976. if (pl.type === '!') {
  977. negativeLists.push(Object.assign(pl, { reEnd: re.length }));
  978. }
  979. continue;
  980. }
  981. case '|': {
  982. const plEntry = patternListStack[patternListStack.length - 1];
  983. if (!plEntry) {
  984. re += '\\|';
  985. continue;
  986. }
  987. clearStateChar();
  988. re += '|';
  989. // next subpattern can start with a dot?
  990. if (plEntry.start === 0 && plEntry.type !== '!') {
  991. dotTravAllowed = true;
  992. re += subPatternStart(pattern.slice(i + 1));
  993. }
  994. continue;
  995. }
  996. // these are mostly the same in regexp and glob
  997. case '[':
  998. // swallow any state-tracking char before the [
  999. clearStateChar();
  1000. const [src, needUflag, consumed, magic] = parseClass(pattern, i);
  1001. if (consumed) {
  1002. re += src;
  1003. uflag = uflag || needUflag;
  1004. i += consumed - 1;
  1005. hasMagic = hasMagic || magic;
  1006. }
  1007. else {
  1008. re += '\\[';
  1009. }
  1010. continue;
  1011. case ']':
  1012. re += '\\' + c;
  1013. continue;
  1014. default:
  1015. // swallow any state char that wasn't consumed
  1016. clearStateChar();
  1017. re += regExpEscape(c);
  1018. break;
  1019. } // switch
  1020. } // for
  1021. // handle the case where we had a +( thing at the *end*
  1022. // of the pattern.
  1023. // each pattern list stack adds 3 chars, and we need to go through
  1024. // and escape any | chars that were passed through as-is for the regexp.
  1025. // Go through and escape them, taking care not to double-escape any
  1026. // | chars that were already escaped.
  1027. for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) {
  1028. let tail;
  1029. tail = re.slice(pl.reStart + pl.open.length);
  1030. this.debug(this.pattern, 'setting tail', re, pl);
  1031. // maybe some even number of \, then maybe 1 \, followed by a |
  1032. tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, (_, $1, $2) => {
  1033. if (!$2) {
  1034. // the | isn't already escaped, so escape it.
  1035. $2 = '\\';
  1036. // should already be done
  1037. /* c8 ignore start */
  1038. }
  1039. /* c8 ignore stop */
  1040. // need to escape all those slashes *again*, without escaping the
  1041. // one that we need for escaping the | character. As it works out,
  1042. // escaping an even number of slashes can be done by simply repeating
  1043. // it exactly after itself. That's why this trick works.
  1044. //
  1045. // I am sorry that you have to see this.
  1046. return $1 + $1 + $2 + '|';
  1047. });
  1048. this.debug('tail=%j\n %s', tail, tail, pl, re);
  1049. const t = pl.type === '*' ? star : pl.type === '?' ? qmark : '\\' + pl.type;
  1050. hasMagic = true;
  1051. re = re.slice(0, pl.reStart) + t + '\\(' + tail;
  1052. }
  1053. // handle trailing things that only matter at the very end.
  1054. clearStateChar();
  1055. if (escaping) {
  1056. // trailing \\
  1057. re += '\\\\';
  1058. }
  1059. // only need to apply the nodot start if the re starts with
  1060. // something that could conceivably capture a dot
  1061. const addPatternStart = addPatternStartSet[re.charAt(0)];
  1062. // Hack to work around lack of negative lookbehind in JS
  1063. // A pattern like: *.!(x).!(y|z) needs to ensure that a name
  1064. // like 'a.xyz.yz' doesn't match. So, the first negative
  1065. // lookahead, has to look ALL the way ahead, to the end of
  1066. // the pattern.
  1067. for (let n = negativeLists.length - 1; n > -1; n--) {
  1068. const nl = negativeLists[n];
  1069. const nlBefore = re.slice(0, nl.reStart);
  1070. const nlFirst = re.slice(nl.reStart, nl.reEnd - 8);
  1071. let nlAfter = re.slice(nl.reEnd);
  1072. const nlLast = re.slice(nl.reEnd - 8, nl.reEnd) + nlAfter;
  1073. // Handle nested stuff like *(*.js|!(*.json)), where open parens
  1074. // mean that we should *not* include the ) in the bit that is considered
  1075. // "after" the negated section.
  1076. const closeParensBefore = nlBefore.split(')').length;
  1077. const openParensBefore = nlBefore.split('(').length - closeParensBefore;
  1078. let cleanAfter = nlAfter;
  1079. for (let i = 0; i < openParensBefore; i++) {
  1080. cleanAfter = cleanAfter.replace(/\)[+*?]?/, '');
  1081. }
  1082. nlAfter = cleanAfter;
  1083. const dollar = nlAfter === '' ? '(?:$|\\/)' : '';
  1084. re = nlBefore + nlFirst + nlAfter + dollar + nlLast;
  1085. }
  1086. // if the re is not "" at this point, then we need to make sure
  1087. // it doesn't match against an empty path part.
  1088. // Otherwise a/* will match a/, which it should not.
  1089. if (re !== '' && hasMagic) {
  1090. re = '(?=.)' + re;
  1091. }
  1092. if (addPatternStart) {
  1093. re = patternStart() + re;
  1094. }
  1095. // if it's nocase, and the lcase/uppercase don't match, it's magic
  1096. if (options.nocase && !hasMagic && !options.nocaseMagicOnly) {
  1097. hasMagic = pattern.toUpperCase() !== pattern.toLowerCase();
  1098. }
  1099. // skip the regexp for non-magical patterns
  1100. // unescape anything in it, though, so that it'll be
  1101. // an exact match against a file etc.
  1102. if (!hasMagic) {
  1103. return globUnescape(re);
  1104. }
  1105. const flags = (options.nocase ? 'i' : '') + (uflag ? 'u' : '');
  1106. try {
  1107. const ext = fastTest
  1108. ? {
  1109. _glob: pattern,
  1110. _src: re,
  1111. test: fastTest,
  1112. }
  1113. : {
  1114. _glob: pattern,
  1115. _src: re,
  1116. };
  1117. return Object.assign(new RegExp('^' + re + '$', flags), ext);
  1118. /* c8 ignore start */
  1119. }
  1120. catch (er) {
  1121. // should be impossible
  1122. // If it was an invalid regular expression, then it can't match
  1123. // anything. This trick looks for a character after the end of
  1124. // the string, which is of course impossible, except in multi-line
  1125. // mode, but it's not a /m regex.
  1126. this.debug('invalid regexp', er);
  1127. return new RegExp('$.');
  1128. }
  1129. /* c8 ignore stop */
  1130. }
  1131. makeRe() {
  1132. if (this.regexp || this.regexp === false)
  1133. return this.regexp;
  1134. // at this point, this.set is a 2d array of partial
  1135. // pattern strings, or "**".
  1136. //
  1137. // It's better to use .match(). This function shouldn't
  1138. // be used, really, but it's pretty convenient sometimes,
  1139. // when you just want to work with a regex.
  1140. const set = this.set;
  1141. if (!set.length) {
  1142. this.regexp = false;
  1143. return this.regexp;
  1144. }
  1145. const options = this.options;
  1146. const twoStar = options.noglobstar
  1147. ? star
  1148. : options.dot
  1149. ? twoStarDot
  1150. : twoStarNoDot;
  1151. const flags = options.nocase ? 'i' : '';
  1152. // regexpify non-globstar patterns
  1153. // if ** is only item, then we just do one twoStar
  1154. // if ** is first, and there are more, prepend (\/|twoStar\/)? to next
  1155. // if ** is last, append (\/twoStar|) to previous
  1156. // if ** is in the middle, append (\/|\/twoStar\/) to previous
  1157. // then filter out GLOBSTAR symbols
  1158. let re = set
  1159. .map(pattern => {
  1160. const pp = pattern.map(p => typeof p === 'string'
  1161. ? regExpEscape(p)
  1162. : p === GLOBSTAR
  1163. ? GLOBSTAR
  1164. : p._src);
  1165. pp.forEach((p, i) => {
  1166. const next = pp[i + 1];
  1167. const prev = pp[i - 1];
  1168. if (p !== GLOBSTAR || prev === GLOBSTAR) {
  1169. return;
  1170. }
  1171. if (prev === undefined) {
  1172. if (next !== undefined && next !== GLOBSTAR) {
  1173. pp[i + 1] = '(?:\\/|' + twoStar + '\\/)?' + next;
  1174. }
  1175. else {
  1176. pp[i] = twoStar;
  1177. }
  1178. }
  1179. else if (next === undefined) {
  1180. pp[i - 1] = prev + '(?:\\/|' + twoStar + ')?';
  1181. }
  1182. else if (next !== GLOBSTAR) {
  1183. pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + '\\/)' + next;
  1184. pp[i + 1] = GLOBSTAR;
  1185. }
  1186. });
  1187. return pp.filter(p => p !== GLOBSTAR).join('/');
  1188. })
  1189. .join('|');
  1190. // must match entire pattern
  1191. // ending in a * or ** will make it less strict.
  1192. re = '^(?:' + re + ')$';
  1193. // can match anything, as long as it's not this.
  1194. if (this.negate)
  1195. re = '^(?!' + re + ').*$';
  1196. try {
  1197. this.regexp = new RegExp(re, flags);
  1198. /* c8 ignore start */
  1199. }
  1200. catch (ex) {
  1201. // should be impossible
  1202. this.regexp = false;
  1203. }
  1204. /* c8 ignore stop */
  1205. return this.regexp;
  1206. }
  1207. slashSplit(p) {
  1208. // if p starts with // on windows, we preserve that
  1209. // so that UNC paths aren't broken. Otherwise, any number of
  1210. // / characters are coalesced into one, unless
  1211. // preserveMultipleSlashes is set to true.
  1212. if (this.preserveMultipleSlashes) {
  1213. return p.split('/');
  1214. }
  1215. else if (this.isWindows && /^\/\/[^\/]+/.test(p)) {
  1216. // add an extra '' for the one we lose
  1217. return ['', ...p.split(/\/+/)];
  1218. }
  1219. else {
  1220. return p.split(/\/+/);
  1221. }
  1222. }
  1223. match(f, partial = this.partial) {
  1224. this.debug('match', f, this.pattern);
  1225. // short-circuit in the case of busted things.
  1226. // comments, etc.
  1227. if (this.comment) {
  1228. return false;
  1229. }
  1230. if (this.empty) {
  1231. return f === '';
  1232. }
  1233. if (f === '/' && partial) {
  1234. return true;
  1235. }
  1236. const options = this.options;
  1237. // windows: need to use /, not \
  1238. if (this.isWindows) {
  1239. f = f.split('\\').join('/');
  1240. }
  1241. // treat the test path as a set of pathparts.
  1242. const ff = this.slashSplit(f);
  1243. this.debug(this.pattern, 'split', ff);
  1244. // just ONE of the pattern sets in this.set needs to match
  1245. // in order for it to be valid. If negating, then just one
  1246. // match means that we have failed.
  1247. // Either way, return on the first hit.
  1248. const set = this.set;
  1249. this.debug(this.pattern, 'set', set);
  1250. // Find the basename of the path by looking for the last non-empty segment
  1251. let filename = ff[ff.length - 1];
  1252. if (!filename) {
  1253. for (let i = ff.length - 2; !filename && i >= 0; i--) {
  1254. filename = ff[i];
  1255. }
  1256. }
  1257. for (let i = 0; i < set.length; i++) {
  1258. const pattern = set[i];
  1259. let file = ff;
  1260. if (options.matchBase && pattern.length === 1) {
  1261. file = [filename];
  1262. }
  1263. const hit = this.matchOne(file, pattern, partial);
  1264. if (hit) {
  1265. if (options.flipNegate) {
  1266. return true;
  1267. }
  1268. return !this.negate;
  1269. }
  1270. }
  1271. // didn't get any hits. this is success if it's a negative
  1272. // pattern, failure otherwise.
  1273. if (options.flipNegate) {
  1274. return false;
  1275. }
  1276. return this.negate;
  1277. }
  1278. static defaults(def) {
  1279. return minimatch.defaults(def).Minimatch;
  1280. }
  1281. }
  1282. /* c8 ignore start */
  1283. export { escape } from './escape.js';
  1284. export { unescape } from './unescape.js';
  1285. /* c8 ignore stop */
  1286. minimatch.Minimatch = Minimatch;
  1287. minimatch.escape = escape;
  1288. minimatch.unescape = unescape;
  1289. //# sourceMappingURL=index.js.map