glob.js 6.2 KB

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