glob.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.Glob = void 0;
  4. const minimatch_1 = require("minimatch");
  5. const node_url_1 = require("node:url");
  6. const path_scurry_1 = require("path-scurry");
  7. const pattern_js_1 = require("./pattern.js");
  8. const walker_js_1 = require("./walker.js");
  9. // if no process global, just call it linux.
  10. // so we default to case-sensitive, / separators
  11. const defaultPlatform = (typeof process === 'object' &&
  12. process &&
  13. typeof process.platform === 'string') ?
  14. process.platform
  15. : 'linux';
  16. /**
  17. * An object that can perform glob pattern traversals.
  18. */
  19. class Glob {
  20. absolute;
  21. cwd;
  22. root;
  23. dot;
  24. dotRelative;
  25. follow;
  26. ignore;
  27. magicalBraces;
  28. mark;
  29. matchBase;
  30. maxDepth;
  31. nobrace;
  32. nocase;
  33. nodir;
  34. noext;
  35. noglobstar;
  36. pattern;
  37. platform;
  38. realpath;
  39. scurry;
  40. stat;
  41. signal;
  42. windowsPathsNoEscape;
  43. withFileTypes;
  44. includeChildMatches;
  45. /**
  46. * The options provided to the constructor.
  47. */
  48. opts;
  49. /**
  50. * An array of parsed immutable {@link Pattern} objects.
  51. */
  52. patterns;
  53. /**
  54. * All options are stored as properties on the `Glob` object.
  55. *
  56. * See {@link GlobOptions} for full options descriptions.
  57. *
  58. * Note that a previous `Glob` object can be passed as the
  59. * `GlobOptions` to another `Glob` instantiation to re-use settings
  60. * and caches with a new pattern.
  61. *
  62. * Traversal functions can be called multiple times to run the walk
  63. * again.
  64. */
  65. constructor(pattern, opts) {
  66. /* c8 ignore start */
  67. if (!opts)
  68. throw new TypeError('glob options required');
  69. /* c8 ignore stop */
  70. this.withFileTypes = !!opts.withFileTypes;
  71. this.signal = opts.signal;
  72. this.follow = !!opts.follow;
  73. this.dot = !!opts.dot;
  74. this.dotRelative = !!opts.dotRelative;
  75. this.nodir = !!opts.nodir;
  76. this.mark = !!opts.mark;
  77. if (!opts.cwd) {
  78. this.cwd = '';
  79. }
  80. else if (opts.cwd instanceof URL || opts.cwd.startsWith('file://')) {
  81. opts.cwd = (0, node_url_1.fileURLToPath)(opts.cwd);
  82. }
  83. this.cwd = opts.cwd || '';
  84. this.root = opts.root;
  85. this.magicalBraces = !!opts.magicalBraces;
  86. this.nobrace = !!opts.nobrace;
  87. this.noext = !!opts.noext;
  88. this.realpath = !!opts.realpath;
  89. this.absolute = opts.absolute;
  90. this.includeChildMatches = opts.includeChildMatches !== false;
  91. this.noglobstar = !!opts.noglobstar;
  92. this.matchBase = !!opts.matchBase;
  93. this.maxDepth =
  94. typeof opts.maxDepth === 'number' ? opts.maxDepth : Infinity;
  95. this.stat = !!opts.stat;
  96. this.ignore = opts.ignore;
  97. if (this.withFileTypes && this.absolute !== undefined) {
  98. throw new Error('cannot set absolute and withFileTypes:true');
  99. }
  100. if (typeof pattern === 'string') {
  101. pattern = [pattern];
  102. }
  103. this.windowsPathsNoEscape =
  104. !!opts.windowsPathsNoEscape ||
  105. opts.allowWindowsEscape ===
  106. false;
  107. if (this.windowsPathsNoEscape) {
  108. pattern = pattern.map(p => p.replace(/\\/g, '/'));
  109. }
  110. if (this.matchBase) {
  111. if (opts.noglobstar) {
  112. throw new TypeError('base matching requires globstar');
  113. }
  114. pattern = pattern.map(p => (p.includes('/') ? p : `./**/${p}`));
  115. }
  116. this.pattern = pattern;
  117. this.platform = opts.platform || defaultPlatform;
  118. this.opts = { ...opts, platform: this.platform };
  119. if (opts.scurry) {
  120. this.scurry = opts.scurry;
  121. if (opts.nocase !== undefined &&
  122. opts.nocase !== opts.scurry.nocase) {
  123. throw new Error('nocase option contradicts provided scurry option');
  124. }
  125. }
  126. else {
  127. const Scurry = opts.platform === 'win32' ? path_scurry_1.PathScurryWin32
  128. : opts.platform === 'darwin' ? path_scurry_1.PathScurryDarwin
  129. : opts.platform ? path_scurry_1.PathScurryPosix
  130. : path_scurry_1.PathScurry;
  131. this.scurry = new Scurry(this.cwd, {
  132. nocase: opts.nocase,
  133. fs: opts.fs,
  134. });
  135. }
  136. this.nocase = this.scurry.nocase;
  137. // If you do nocase:true on a case-sensitive file system, then
  138. // we need to use regexps instead of strings for non-magic
  139. // path portions, because statting `aBc` won't return results
  140. // for the file `AbC` for example.
  141. const nocaseMagicOnly = this.platform === 'darwin' || this.platform === 'win32';
  142. const mmo = {
  143. // default nocase based on platform
  144. ...opts,
  145. dot: this.dot,
  146. matchBase: this.matchBase,
  147. nobrace: this.nobrace,
  148. nocase: this.nocase,
  149. nocaseMagicOnly,
  150. nocomment: true,
  151. noext: this.noext,
  152. nonegate: true,
  153. optimizationLevel: 2,
  154. platform: this.platform,
  155. windowsPathsNoEscape: this.windowsPathsNoEscape,
  156. debug: !!this.opts.debug,
  157. };
  158. const mms = this.pattern.map(p => new minimatch_1.Minimatch(p, mmo));
  159. const [matchSet, globParts] = mms.reduce((set, m) => {
  160. set[0].push(...m.set);
  161. set[1].push(...m.globParts);
  162. return set;
  163. }, [[], []]);
  164. this.patterns = matchSet.map((set, i) => {
  165. const g = globParts[i];
  166. /* c8 ignore start */
  167. if (!g)
  168. throw new Error('invalid pattern object');
  169. /* c8 ignore stop */
  170. return new pattern_js_1.Pattern(set, g, 0, this.platform);
  171. });
  172. }
  173. async walk() {
  174. // Walkers always return array of Path objects, so we just have to
  175. // coerce them into the right shape. It will have already called
  176. // realpath() if the option was set to do so, so we know that's cached.
  177. // start out knowing the cwd, at least
  178. return [
  179. ...(await new walker_js_1.GlobWalker(this.patterns, this.scurry.cwd, {
  180. ...this.opts,
  181. maxDepth: this.maxDepth !== Infinity ?
  182. this.maxDepth + this.scurry.cwd.depth()
  183. : Infinity,
  184. platform: this.platform,
  185. nocase: this.nocase,
  186. includeChildMatches: this.includeChildMatches,
  187. }).walk()),
  188. ];
  189. }
  190. walkSync() {
  191. return [
  192. ...new walker_js_1.GlobWalker(this.patterns, this.scurry.cwd, {
  193. ...this.opts,
  194. maxDepth: this.maxDepth !== Infinity ?
  195. this.maxDepth + this.scurry.cwd.depth()
  196. : Infinity,
  197. platform: this.platform,
  198. nocase: this.nocase,
  199. includeChildMatches: this.includeChildMatches,
  200. }).walkSync(),
  201. ];
  202. }
  203. stream() {
  204. return new walker_js_1.GlobStream(this.patterns, this.scurry.cwd, {
  205. ...this.opts,
  206. maxDepth: this.maxDepth !== Infinity ?
  207. this.maxDepth + this.scurry.cwd.depth()
  208. : Infinity,
  209. platform: this.platform,
  210. nocase: this.nocase,
  211. includeChildMatches: this.includeChildMatches,
  212. }).stream();
  213. }
  214. streamSync() {
  215. return new walker_js_1.GlobStream(this.patterns, this.scurry.cwd, {
  216. ...this.opts,
  217. maxDepth: this.maxDepth !== Infinity ?
  218. this.maxDepth + this.scurry.cwd.depth()
  219. : Infinity,
  220. platform: this.platform,
  221. nocase: this.nocase,
  222. includeChildMatches: this.includeChildMatches,
  223. }).streamSync();
  224. }
  225. /**
  226. * Default sync iteration function. Returns a Generator that
  227. * iterates over the results.
  228. */
  229. iterateSync() {
  230. return this.streamSync()[Symbol.iterator]();
  231. }
  232. [Symbol.iterator]() {
  233. return this.iterateSync();
  234. }
  235. /**
  236. * Default async iteration function. Returns an AsyncGenerator that
  237. * iterates over the results.
  238. */
  239. iterate() {
  240. return this.stream()[Symbol.asyncIterator]();
  241. }
  242. [Symbol.asyncIterator]() {
  243. return this.iterate();
  244. }
  245. }
  246. exports.Glob = Glob;
  247. //# sourceMappingURL=glob.js.map