index.js 39 KB

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