index.js 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995
  1. "use strict";
  2. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  3. if (k2 === undefined) k2 = k;
  4. var desc = Object.getOwnPropertyDescriptor(m, k);
  5. if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
  6. desc = { enumerable: true, get: function() { return m[k]; } };
  7. }
  8. Object.defineProperty(o, k2, desc);
  9. }) : (function(o, m, k, k2) {
  10. if (k2 === undefined) k2 = k;
  11. o[k2] = m[k];
  12. }));
  13. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  14. Object.defineProperty(o, "default", { enumerable: true, value: v });
  15. }) : function(o, v) {
  16. o["default"] = v;
  17. });
  18. var __importStar = (this && this.__importStar) || function (mod) {
  19. if (mod && mod.__esModule) return mod;
  20. var result = {};
  21. if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  22. __setModuleDefault(result, mod);
  23. return result;
  24. };
  25. Object.defineProperty(exports, "__esModule", { value: true });
  26. exports.PathScurry = exports.Path = exports.PathScurryDarwin = exports.PathScurryPosix = exports.PathScurryWin32 = exports.PathScurryBase = exports.PathPosix = exports.PathWin32 = exports.PathBase = exports.ChildrenCache = exports.ResolveCache = void 0;
  27. const lru_cache_1 = require("lru-cache");
  28. const path_1 = require("path");
  29. const url_1 = require("url");
  30. const actualFS = __importStar(require("fs"));
  31. const fs_1 = require("fs");
  32. const realpathSync = fs_1.realpathSync.native;
  33. // TODO: test perf of fs/promises realpath vs realpathCB,
  34. // since the promises one uses realpath.native
  35. const promises_1 = require("fs/promises");
  36. const minipass_1 = require("minipass");
  37. const defaultFS = {
  38. lstatSync: fs_1.lstatSync,
  39. readdir: fs_1.readdir,
  40. readdirSync: fs_1.readdirSync,
  41. readlinkSync: fs_1.readlinkSync,
  42. realpathSync,
  43. promises: {
  44. lstat: promises_1.lstat,
  45. readdir: promises_1.readdir,
  46. readlink: promises_1.readlink,
  47. realpath: promises_1.realpath,
  48. },
  49. };
  50. // if they just gave us require('fs') then use our default
  51. const fsFromOption = (fsOption) => !fsOption || fsOption === defaultFS || fsOption === actualFS
  52. ? defaultFS
  53. : {
  54. ...defaultFS,
  55. ...fsOption,
  56. promises: {
  57. ...defaultFS.promises,
  58. ...(fsOption.promises || {}),
  59. },
  60. };
  61. // turn something like //?/c:/ into c:\
  62. const uncDriveRegexp = /^\\\\\?\\([a-z]:)\\?$/i;
  63. const uncToDrive = (rootPath) => rootPath.replace(/\//g, '\\').replace(uncDriveRegexp, '$1\\');
  64. // windows paths are separated by either / or \
  65. const eitherSep = /[\\\/]/;
  66. const UNKNOWN = 0; // may not even exist, for all we know
  67. const IFIFO = 0b0001;
  68. const IFCHR = 0b0010;
  69. const IFDIR = 0b0100;
  70. const IFBLK = 0b0110;
  71. const IFREG = 0b1000;
  72. const IFLNK = 0b1010;
  73. const IFSOCK = 0b1100;
  74. const IFMT = 0b1111;
  75. // mask to unset low 4 bits
  76. const IFMT_UNKNOWN = ~IFMT;
  77. // set after successfully calling readdir() and getting entries.
  78. const READDIR_CALLED = 16;
  79. // set after a successful lstat()
  80. const LSTAT_CALLED = 32;
  81. // set if an entry (or one of its parents) is definitely not a dir
  82. const ENOTDIR = 64;
  83. // set if an entry (or one of its parents) does not exist
  84. // (can also be set on lstat errors like EACCES or ENAMETOOLONG)
  85. const ENOENT = 128;
  86. // cannot have child entries -- also verify &IFMT is either IFDIR or IFLNK
  87. // set if we fail to readlink
  88. const ENOREADLINK = 256;
  89. // set if we know realpath() will fail
  90. const ENOREALPATH = 512;
  91. const ENOCHILD = ENOTDIR | ENOENT | ENOREALPATH;
  92. const TYPEMASK = 1023;
  93. const entToType = (s) => s.isFile()
  94. ? IFREG
  95. : s.isDirectory()
  96. ? IFDIR
  97. : s.isSymbolicLink()
  98. ? IFLNK
  99. : s.isCharacterDevice()
  100. ? IFCHR
  101. : s.isBlockDevice()
  102. ? IFBLK
  103. : s.isSocket()
  104. ? IFSOCK
  105. : s.isFIFO()
  106. ? IFIFO
  107. : UNKNOWN;
  108. // normalize unicode path names
  109. const normalizeCache = new Map();
  110. const normalize = (s) => {
  111. const c = normalizeCache.get(s);
  112. if (c)
  113. return c;
  114. const n = s.normalize('NFKD');
  115. normalizeCache.set(s, n);
  116. return n;
  117. };
  118. const normalizeNocaseCache = new Map();
  119. const normalizeNocase = (s) => {
  120. const c = normalizeNocaseCache.get(s);
  121. if (c)
  122. return c;
  123. const n = normalize(s.toLowerCase());
  124. normalizeNocaseCache.set(s, n);
  125. return n;
  126. };
  127. /**
  128. * An LRUCache for storing resolved path strings or Path objects.
  129. * @internal
  130. */
  131. class ResolveCache extends lru_cache_1.LRUCache {
  132. constructor() {
  133. super({ max: 256 });
  134. }
  135. }
  136. exports.ResolveCache = ResolveCache;
  137. // In order to prevent blowing out the js heap by allocating hundreds of
  138. // thousands of Path entries when walking extremely large trees, the "children"
  139. // in this tree are represented by storing an array of Path entries in an
  140. // LRUCache, indexed by the parent. At any time, Path.children() may return an
  141. // empty array, indicating that it doesn't know about any of its children, and
  142. // thus has to rebuild that cache. This is fine, it just means that we don't
  143. // benefit as much from having the cached entries, but huge directory walks
  144. // don't blow out the stack, and smaller ones are still as fast as possible.
  145. //
  146. //It does impose some complexity when building up the readdir data, because we
  147. //need to pass a reference to the children array that we started with.
  148. /**
  149. * an LRUCache for storing child entries.
  150. * @internal
  151. */
  152. class ChildrenCache extends lru_cache_1.LRUCache {
  153. constructor(maxSize = 16 * 1024) {
  154. super({
  155. maxSize,
  156. // parent + children
  157. sizeCalculation: a => a.length + 1,
  158. });
  159. }
  160. }
  161. exports.ChildrenCache = ChildrenCache;
  162. const setAsCwd = Symbol('PathScurry setAsCwd');
  163. /**
  164. * Path objects are sort of like a super-powered
  165. * {@link https://nodejs.org/docs/latest/api/fs.html#class-fsdirent fs.Dirent}
  166. *
  167. * Each one represents a single filesystem entry on disk, which may or may not
  168. * exist. It includes methods for reading various types of information via
  169. * lstat, readlink, and readdir, and caches all information to the greatest
  170. * degree possible.
  171. *
  172. * Note that fs operations that would normally throw will instead return an
  173. * "empty" value. This is in order to prevent excessive overhead from error
  174. * stack traces.
  175. */
  176. class PathBase {
  177. /**
  178. * the basename of this path
  179. *
  180. * **Important**: *always* test the path name against any test string
  181. * usingthe {@link isNamed} method, and not by directly comparing this
  182. * string. Otherwise, unicode path strings that the system sees as identical
  183. * will not be properly treated as the same path, leading to incorrect
  184. * behavior and possible security issues.
  185. */
  186. name;
  187. /**
  188. * the Path entry corresponding to the path root.
  189. *
  190. * @internal
  191. */
  192. root;
  193. /**
  194. * All roots found within the current PathScurry family
  195. *
  196. * @internal
  197. */
  198. roots;
  199. /**
  200. * a reference to the parent path, or undefined in the case of root entries
  201. *
  202. * @internal
  203. */
  204. parent;
  205. /**
  206. * boolean indicating whether paths are compared case-insensitively
  207. * @internal
  208. */
  209. nocase;
  210. // potential default fs override
  211. #fs;
  212. // Stats fields
  213. #dev;
  214. get dev() {
  215. return this.#dev;
  216. }
  217. #mode;
  218. get mode() {
  219. return this.#mode;
  220. }
  221. #nlink;
  222. get nlink() {
  223. return this.#nlink;
  224. }
  225. #uid;
  226. get uid() {
  227. return this.#uid;
  228. }
  229. #gid;
  230. get gid() {
  231. return this.#gid;
  232. }
  233. #rdev;
  234. get rdev() {
  235. return this.#rdev;
  236. }
  237. #blksize;
  238. get blksize() {
  239. return this.#blksize;
  240. }
  241. #ino;
  242. get ino() {
  243. return this.#ino;
  244. }
  245. #size;
  246. get size() {
  247. return this.#size;
  248. }
  249. #blocks;
  250. get blocks() {
  251. return this.#blocks;
  252. }
  253. #atimeMs;
  254. get atimeMs() {
  255. return this.#atimeMs;
  256. }
  257. #mtimeMs;
  258. get mtimeMs() {
  259. return this.#mtimeMs;
  260. }
  261. #ctimeMs;
  262. get ctimeMs() {
  263. return this.#ctimeMs;
  264. }
  265. #birthtimeMs;
  266. get birthtimeMs() {
  267. return this.#birthtimeMs;
  268. }
  269. #atime;
  270. get atime() {
  271. return this.#atime;
  272. }
  273. #mtime;
  274. get mtime() {
  275. return this.#mtime;
  276. }
  277. #ctime;
  278. get ctime() {
  279. return this.#ctime;
  280. }
  281. #birthtime;
  282. get birthtime() {
  283. return this.#birthtime;
  284. }
  285. #matchName;
  286. #depth;
  287. #fullpath;
  288. #fullpathPosix;
  289. #relative;
  290. #relativePosix;
  291. #type;
  292. #children;
  293. #linkTarget;
  294. #realpath;
  295. /**
  296. * This property is for compatibility with the Dirent class as of
  297. * Node v20, where Dirent['path'] refers to the path of the directory
  298. * that was passed to readdir. So, somewhat counterintuitively, this
  299. * property refers to the *parent* path, not the path object itself.
  300. * For root entries, it's the path to the entry itself.
  301. */
  302. get path() {
  303. return (this.parent || this).fullpath();
  304. }
  305. /**
  306. * Do not create new Path objects directly. They should always be accessed
  307. * via the PathScurry class or other methods on the Path class.
  308. *
  309. * @internal
  310. */
  311. constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
  312. this.name = name;
  313. this.#matchName = nocase ? normalizeNocase(name) : normalize(name);
  314. this.#type = type & TYPEMASK;
  315. this.nocase = nocase;
  316. this.roots = roots;
  317. this.root = root || this;
  318. this.#children = children;
  319. this.#fullpath = opts.fullpath;
  320. this.#relative = opts.relative;
  321. this.#relativePosix = opts.relativePosix;
  322. this.parent = opts.parent;
  323. if (this.parent) {
  324. this.#fs = this.parent.#fs;
  325. }
  326. else {
  327. this.#fs = fsFromOption(opts.fs);
  328. }
  329. }
  330. /**
  331. * Returns the depth of the Path object from its root.
  332. *
  333. * For example, a path at `/foo/bar` would have a depth of 2.
  334. */
  335. depth() {
  336. if (this.#depth !== undefined)
  337. return this.#depth;
  338. if (!this.parent)
  339. return (this.#depth = 0);
  340. return (this.#depth = this.parent.depth() + 1);
  341. }
  342. /**
  343. * @internal
  344. */
  345. childrenCache() {
  346. return this.#children;
  347. }
  348. /**
  349. * Get the Path object referenced by the string path, resolved from this Path
  350. */
  351. resolve(path) {
  352. if (!path) {
  353. return this;
  354. }
  355. const rootPath = this.getRootString(path);
  356. const dir = path.substring(rootPath.length);
  357. const dirParts = dir.split(this.splitSep);
  358. const result = rootPath
  359. ? this.getRoot(rootPath).#resolveParts(dirParts)
  360. : this.#resolveParts(dirParts);
  361. return result;
  362. }
  363. #resolveParts(dirParts) {
  364. let p = this;
  365. for (const part of dirParts) {
  366. p = p.child(part);
  367. }
  368. return p;
  369. }
  370. /**
  371. * Returns the cached children Path objects, if still available. If they
  372. * have fallen out of the cache, then returns an empty array, and resets the
  373. * READDIR_CALLED bit, so that future calls to readdir() will require an fs
  374. * lookup.
  375. *
  376. * @internal
  377. */
  378. children() {
  379. const cached = this.#children.get(this);
  380. if (cached) {
  381. return cached;
  382. }
  383. const children = Object.assign([], { provisional: 0 });
  384. this.#children.set(this, children);
  385. this.#type &= ~READDIR_CALLED;
  386. return children;
  387. }
  388. /**
  389. * Resolves a path portion and returns or creates the child Path.
  390. *
  391. * Returns `this` if pathPart is `''` or `'.'`, or `parent` if pathPart is
  392. * `'..'`.
  393. *
  394. * This should not be called directly. If `pathPart` contains any path
  395. * separators, it will lead to unsafe undefined behavior.
  396. *
  397. * Use `Path.resolve()` instead.
  398. *
  399. * @internal
  400. */
  401. child(pathPart, opts) {
  402. if (pathPart === '' || pathPart === '.') {
  403. return this;
  404. }
  405. if (pathPart === '..') {
  406. return this.parent || this;
  407. }
  408. // find the child
  409. const children = this.children();
  410. const name = this.nocase
  411. ? normalizeNocase(pathPart)
  412. : normalize(pathPart);
  413. for (const p of children) {
  414. if (p.#matchName === name) {
  415. return p;
  416. }
  417. }
  418. // didn't find it, create provisional child, since it might not
  419. // actually exist. If we know the parent isn't a dir, then
  420. // in fact it CAN'T exist.
  421. const s = this.parent ? this.sep : '';
  422. const fullpath = this.#fullpath
  423. ? this.#fullpath + s + pathPart
  424. : undefined;
  425. const pchild = this.newChild(pathPart, UNKNOWN, {
  426. ...opts,
  427. parent: this,
  428. fullpath,
  429. });
  430. if (!this.canReaddir()) {
  431. pchild.#type |= ENOENT;
  432. }
  433. // don't have to update provisional, because if we have real children,
  434. // then provisional is set to children.length, otherwise a lower number
  435. children.push(pchild);
  436. return pchild;
  437. }
  438. /**
  439. * The relative path from the cwd. If it does not share an ancestor with
  440. * the cwd, then this ends up being equivalent to the fullpath()
  441. */
  442. relative() {
  443. if (this.#relative !== undefined) {
  444. return this.#relative;
  445. }
  446. const name = this.name;
  447. const p = this.parent;
  448. if (!p) {
  449. return (this.#relative = this.name);
  450. }
  451. const pv = p.relative();
  452. return pv + (!pv || !p.parent ? '' : this.sep) + name;
  453. }
  454. /**
  455. * The relative path from the cwd, using / as the path separator.
  456. * If it does not share an ancestor with
  457. * the cwd, then this ends up being equivalent to the fullpathPosix()
  458. * On posix systems, this is identical to relative().
  459. */
  460. relativePosix() {
  461. if (this.sep === '/')
  462. return this.relative();
  463. if (this.#relativePosix !== undefined)
  464. return this.#relativePosix;
  465. const name = this.name;
  466. const p = this.parent;
  467. if (!p) {
  468. return (this.#relativePosix = this.fullpathPosix());
  469. }
  470. const pv = p.relativePosix();
  471. return pv + (!pv || !p.parent ? '' : '/') + name;
  472. }
  473. /**
  474. * The fully resolved path string for this Path entry
  475. */
  476. fullpath() {
  477. if (this.#fullpath !== undefined) {
  478. return this.#fullpath;
  479. }
  480. const name = this.name;
  481. const p = this.parent;
  482. if (!p) {
  483. return (this.#fullpath = this.name);
  484. }
  485. const pv = p.fullpath();
  486. const fp = pv + (!p.parent ? '' : this.sep) + name;
  487. return (this.#fullpath = fp);
  488. }
  489. /**
  490. * On platforms other than windows, this is identical to fullpath.
  491. *
  492. * On windows, this is overridden to return the forward-slash form of the
  493. * full UNC path.
  494. */
  495. fullpathPosix() {
  496. if (this.#fullpathPosix !== undefined)
  497. return this.#fullpathPosix;
  498. if (this.sep === '/')
  499. return (this.#fullpathPosix = this.fullpath());
  500. if (!this.parent) {
  501. const p = this.fullpath().replace(/\\/g, '/');
  502. if (/^[a-z]:\//i.test(p)) {
  503. return (this.#fullpathPosix = `//?/${p}`);
  504. }
  505. else {
  506. return (this.#fullpathPosix = p);
  507. }
  508. }
  509. const p = this.parent;
  510. const pfpp = p.fullpathPosix();
  511. const fpp = pfpp + (!pfpp || !p.parent ? '' : '/') + this.name;
  512. return (this.#fullpathPosix = fpp);
  513. }
  514. /**
  515. * Is the Path of an unknown type?
  516. *
  517. * Note that we might know *something* about it if there has been a previous
  518. * filesystem operation, for example that it does not exist, or is not a
  519. * link, or whether it has child entries.
  520. */
  521. isUnknown() {
  522. return (this.#type & IFMT) === UNKNOWN;
  523. }
  524. /**
  525. * Is the Path a regular file?
  526. */
  527. isFile() {
  528. return (this.#type & IFMT) === IFREG;
  529. }
  530. /**
  531. * Is the Path a directory?
  532. */
  533. isDirectory() {
  534. return (this.#type & IFMT) === IFDIR;
  535. }
  536. /**
  537. * Is the path a character device?
  538. */
  539. isCharacterDevice() {
  540. return (this.#type & IFMT) === IFCHR;
  541. }
  542. /**
  543. * Is the path a block device?
  544. */
  545. isBlockDevice() {
  546. return (this.#type & IFMT) === IFBLK;
  547. }
  548. /**
  549. * Is the path a FIFO pipe?
  550. */
  551. isFIFO() {
  552. return (this.#type & IFMT) === IFIFO;
  553. }
  554. /**
  555. * Is the path a socket?
  556. */
  557. isSocket() {
  558. return (this.#type & IFMT) === IFSOCK;
  559. }
  560. /**
  561. * Is the path a symbolic link?
  562. */
  563. isSymbolicLink() {
  564. return (this.#type & IFLNK) === IFLNK;
  565. }
  566. /**
  567. * Return the entry if it has been subject of a successful lstat, or
  568. * undefined otherwise.
  569. *
  570. * Does not read the filesystem, so an undefined result *could* simply
  571. * mean that we haven't called lstat on it.
  572. */
  573. lstatCached() {
  574. return this.#type & LSTAT_CALLED ? this : undefined;
  575. }
  576. /**
  577. * Return the cached link target if the entry has been the subject of a
  578. * successful readlink, or undefined otherwise.
  579. *
  580. * Does not read the filesystem, so an undefined result *could* just mean we
  581. * don't have any cached data. Only use it if you are very sure that a
  582. * readlink() has been called at some point.
  583. */
  584. readlinkCached() {
  585. return this.#linkTarget;
  586. }
  587. /**
  588. * Returns the cached realpath target if the entry has been the subject
  589. * of a successful realpath, or undefined otherwise.
  590. *
  591. * Does not read the filesystem, so an undefined result *could* just mean we
  592. * don't have any cached data. Only use it if you are very sure that a
  593. * realpath() has been called at some point.
  594. */
  595. realpathCached() {
  596. return this.#realpath;
  597. }
  598. /**
  599. * Returns the cached child Path entries array if the entry has been the
  600. * subject of a successful readdir(), or [] otherwise.
  601. *
  602. * Does not read the filesystem, so an empty array *could* just mean we
  603. * don't have any cached data. Only use it if you are very sure that a
  604. * readdir() has been called recently enough to still be valid.
  605. */
  606. readdirCached() {
  607. const children = this.children();
  608. return children.slice(0, children.provisional);
  609. }
  610. /**
  611. * Return true if it's worth trying to readlink. Ie, we don't (yet) have
  612. * any indication that readlink will definitely fail.
  613. *
  614. * Returns false if the path is known to not be a symlink, if a previous
  615. * readlink failed, or if the entry does not exist.
  616. */
  617. canReadlink() {
  618. if (this.#linkTarget)
  619. return true;
  620. if (!this.parent)
  621. return false;
  622. // cases where it cannot possibly succeed
  623. const ifmt = this.#type & IFMT;
  624. return !((ifmt !== UNKNOWN && ifmt !== IFLNK) ||
  625. this.#type & ENOREADLINK ||
  626. this.#type & ENOENT);
  627. }
  628. /**
  629. * Return true if readdir has previously been successfully called on this
  630. * path, indicating that cachedReaddir() is likely valid.
  631. */
  632. calledReaddir() {
  633. return !!(this.#type & READDIR_CALLED);
  634. }
  635. /**
  636. * Returns true if the path is known to not exist. That is, a previous lstat
  637. * or readdir failed to verify its existence when that would have been
  638. * expected, or a parent entry was marked either enoent or enotdir.
  639. */
  640. isENOENT() {
  641. return !!(this.#type & ENOENT);
  642. }
  643. /**
  644. * Return true if the path is a match for the given path name. This handles
  645. * case sensitivity and unicode normalization.
  646. *
  647. * Note: even on case-sensitive systems, it is **not** safe to test the
  648. * equality of the `.name` property to determine whether a given pathname
  649. * matches, due to unicode normalization mismatches.
  650. *
  651. * Always use this method instead of testing the `path.name` property
  652. * directly.
  653. */
  654. isNamed(n) {
  655. return !this.nocase
  656. ? this.#matchName === normalize(n)
  657. : this.#matchName === normalizeNocase(n);
  658. }
  659. /**
  660. * Return the Path object corresponding to the target of a symbolic link.
  661. *
  662. * If the Path is not a symbolic link, or if the readlink call fails for any
  663. * reason, `undefined` is returned.
  664. *
  665. * Result is cached, and thus may be outdated if the filesystem is mutated.
  666. */
  667. async readlink() {
  668. const target = this.#linkTarget;
  669. if (target) {
  670. return target;
  671. }
  672. if (!this.canReadlink()) {
  673. return undefined;
  674. }
  675. /* c8 ignore start */
  676. // already covered by the canReadlink test, here for ts grumples
  677. if (!this.parent) {
  678. return undefined;
  679. }
  680. /* c8 ignore stop */
  681. try {
  682. const read = await this.#fs.promises.readlink(this.fullpath());
  683. const linkTarget = this.parent.resolve(read);
  684. if (linkTarget) {
  685. return (this.#linkTarget = linkTarget);
  686. }
  687. }
  688. catch (er) {
  689. this.#readlinkFail(er.code);
  690. return undefined;
  691. }
  692. }
  693. /**
  694. * Synchronous {@link PathBase.readlink}
  695. */
  696. readlinkSync() {
  697. const target = this.#linkTarget;
  698. if (target) {
  699. return target;
  700. }
  701. if (!this.canReadlink()) {
  702. return undefined;
  703. }
  704. /* c8 ignore start */
  705. // already covered by the canReadlink test, here for ts grumples
  706. if (!this.parent) {
  707. return undefined;
  708. }
  709. /* c8 ignore stop */
  710. try {
  711. const read = this.#fs.readlinkSync(this.fullpath());
  712. const linkTarget = this.parent.resolve(read);
  713. if (linkTarget) {
  714. return (this.#linkTarget = linkTarget);
  715. }
  716. }
  717. catch (er) {
  718. this.#readlinkFail(er.code);
  719. return undefined;
  720. }
  721. }
  722. #readdirSuccess(children) {
  723. // succeeded, mark readdir called bit
  724. this.#type |= READDIR_CALLED;
  725. // mark all remaining provisional children as ENOENT
  726. for (let p = children.provisional; p < children.length; p++) {
  727. children[p].#markENOENT();
  728. }
  729. }
  730. #markENOENT() {
  731. // mark as UNKNOWN and ENOENT
  732. if (this.#type & ENOENT)
  733. return;
  734. this.#type = (this.#type | ENOENT) & IFMT_UNKNOWN;
  735. this.#markChildrenENOENT();
  736. }
  737. #markChildrenENOENT() {
  738. // all children are provisional and do not exist
  739. const children = this.children();
  740. children.provisional = 0;
  741. for (const p of children) {
  742. p.#markENOENT();
  743. }
  744. }
  745. #markENOREALPATH() {
  746. this.#type |= ENOREALPATH;
  747. this.#markENOTDIR();
  748. }
  749. // save the information when we know the entry is not a dir
  750. #markENOTDIR() {
  751. // entry is not a directory, so any children can't exist.
  752. // this *should* be impossible, since any children created
  753. // after it's been marked ENOTDIR should be marked ENOENT,
  754. // so it won't even get to this point.
  755. /* c8 ignore start */
  756. if (this.#type & ENOTDIR)
  757. return;
  758. /* c8 ignore stop */
  759. let t = this.#type;
  760. // this could happen if we stat a dir, then delete it,
  761. // then try to read it or one of its children.
  762. if ((t & IFMT) === IFDIR)
  763. t &= IFMT_UNKNOWN;
  764. this.#type = t | ENOTDIR;
  765. this.#markChildrenENOENT();
  766. }
  767. #readdirFail(code = '') {
  768. // markENOTDIR and markENOENT also set provisional=0
  769. if (code === 'ENOTDIR' || code === 'EPERM') {
  770. this.#markENOTDIR();
  771. }
  772. else if (code === 'ENOENT') {
  773. this.#markENOENT();
  774. }
  775. else {
  776. this.children().provisional = 0;
  777. }
  778. }
  779. #lstatFail(code = '') {
  780. // Windows just raises ENOENT in this case, disable for win CI
  781. /* c8 ignore start */
  782. if (code === 'ENOTDIR') {
  783. // already know it has a parent by this point
  784. const p = this.parent;
  785. p.#markENOTDIR();
  786. }
  787. else if (code === 'ENOENT') {
  788. /* c8 ignore stop */
  789. this.#markENOENT();
  790. }
  791. }
  792. #readlinkFail(code = '') {
  793. let ter = this.#type;
  794. ter |= ENOREADLINK;
  795. if (code === 'ENOENT')
  796. ter |= ENOENT;
  797. // windows gets a weird error when you try to readlink a file
  798. if (code === 'EINVAL' || code === 'UNKNOWN') {
  799. // exists, but not a symlink, we don't know WHAT it is, so remove
  800. // all IFMT bits.
  801. ter &= IFMT_UNKNOWN;
  802. }
  803. this.#type = ter;
  804. // windows just gets ENOENT in this case. We do cover the case,
  805. // just disabled because it's impossible on Windows CI
  806. /* c8 ignore start */
  807. if (code === 'ENOTDIR' && this.parent) {
  808. this.parent.#markENOTDIR();
  809. }
  810. /* c8 ignore stop */
  811. }
  812. #readdirAddChild(e, c) {
  813. return (this.#readdirMaybePromoteChild(e, c) ||
  814. this.#readdirAddNewChild(e, c));
  815. }
  816. #readdirAddNewChild(e, c) {
  817. // alloc new entry at head, so it's never provisional
  818. const type = entToType(e);
  819. const child = this.newChild(e.name, type, { parent: this });
  820. const ifmt = child.#type & IFMT;
  821. if (ifmt !== IFDIR && ifmt !== IFLNK && ifmt !== UNKNOWN) {
  822. child.#type |= ENOTDIR;
  823. }
  824. c.unshift(child);
  825. c.provisional++;
  826. return child;
  827. }
  828. #readdirMaybePromoteChild(e, c) {
  829. for (let p = c.provisional; p < c.length; p++) {
  830. const pchild = c[p];
  831. const name = this.nocase
  832. ? normalizeNocase(e.name)
  833. : normalize(e.name);
  834. if (name !== pchild.#matchName) {
  835. continue;
  836. }
  837. return this.#readdirPromoteChild(e, pchild, p, c);
  838. }
  839. }
  840. #readdirPromoteChild(e, p, index, c) {
  841. const v = p.name;
  842. // retain any other flags, but set ifmt from dirent
  843. p.#type = (p.#type & IFMT_UNKNOWN) | entToType(e);
  844. // case sensitivity fixing when we learn the true name.
  845. if (v !== e.name)
  846. p.name = e.name;
  847. // just advance provisional index (potentially off the list),
  848. // otherwise we have to splice/pop it out and re-insert at head
  849. if (index !== c.provisional) {
  850. if (index === c.length - 1)
  851. c.pop();
  852. else
  853. c.splice(index, 1);
  854. c.unshift(p);
  855. }
  856. c.provisional++;
  857. return p;
  858. }
  859. /**
  860. * Call lstat() on this Path, and update all known information that can be
  861. * determined.
  862. *
  863. * Note that unlike `fs.lstat()`, the returned value does not contain some
  864. * information, such as `mode`, `dev`, `nlink`, and `ino`. If that
  865. * information is required, you will need to call `fs.lstat` yourself.
  866. *
  867. * If the Path refers to a nonexistent file, or if the lstat call fails for
  868. * any reason, `undefined` is returned. Otherwise the updated Path object is
  869. * returned.
  870. *
  871. * Results are cached, and thus may be out of date if the filesystem is
  872. * mutated.
  873. */
  874. async lstat() {
  875. if ((this.#type & ENOENT) === 0) {
  876. try {
  877. this.#applyStat(await this.#fs.promises.lstat(this.fullpath()));
  878. return this;
  879. }
  880. catch (er) {
  881. this.#lstatFail(er.code);
  882. }
  883. }
  884. }
  885. /**
  886. * synchronous {@link PathBase.lstat}
  887. */
  888. lstatSync() {
  889. if ((this.#type & ENOENT) === 0) {
  890. try {
  891. this.#applyStat(this.#fs.lstatSync(this.fullpath()));
  892. return this;
  893. }
  894. catch (er) {
  895. this.#lstatFail(er.code);
  896. }
  897. }
  898. }
  899. #applyStat(st) {
  900. const { atime, atimeMs, birthtime, birthtimeMs, blksize, blocks, ctime, ctimeMs, dev, gid, ino, mode, mtime, mtimeMs, nlink, rdev, size, uid, } = st;
  901. this.#atime = atime;
  902. this.#atimeMs = atimeMs;
  903. this.#birthtime = birthtime;
  904. this.#birthtimeMs = birthtimeMs;
  905. this.#blksize = blksize;
  906. this.#blocks = blocks;
  907. this.#ctime = ctime;
  908. this.#ctimeMs = ctimeMs;
  909. this.#dev = dev;
  910. this.#gid = gid;
  911. this.#ino = ino;
  912. this.#mode = mode;
  913. this.#mtime = mtime;
  914. this.#mtimeMs = mtimeMs;
  915. this.#nlink = nlink;
  916. this.#rdev = rdev;
  917. this.#size = size;
  918. this.#uid = uid;
  919. const ifmt = entToType(st);
  920. // retain any other flags, but set the ifmt
  921. this.#type = (this.#type & IFMT_UNKNOWN) | ifmt | LSTAT_CALLED;
  922. if (ifmt !== UNKNOWN && ifmt !== IFDIR && ifmt !== IFLNK) {
  923. this.#type |= ENOTDIR;
  924. }
  925. }
  926. #onReaddirCB = [];
  927. #readdirCBInFlight = false;
  928. #callOnReaddirCB(children) {
  929. this.#readdirCBInFlight = false;
  930. const cbs = this.#onReaddirCB.slice();
  931. this.#onReaddirCB.length = 0;
  932. cbs.forEach(cb => cb(null, children));
  933. }
  934. /**
  935. * Standard node-style callback interface to get list of directory entries.
  936. *
  937. * If the Path cannot or does not contain any children, then an empty array
  938. * is returned.
  939. *
  940. * Results are cached, and thus may be out of date if the filesystem is
  941. * mutated.
  942. *
  943. * @param cb The callback called with (er, entries). Note that the `er`
  944. * param is somewhat extraneous, as all readdir() errors are handled and
  945. * simply result in an empty set of entries being returned.
  946. * @param allowZalgo Boolean indicating that immediately known results should
  947. * *not* be deferred with `queueMicrotask`. Defaults to `false`. Release
  948. * zalgo at your peril, the dark pony lord is devious and unforgiving.
  949. */
  950. readdirCB(cb, allowZalgo = false) {
  951. if (!this.canReaddir()) {
  952. if (allowZalgo)
  953. cb(null, []);
  954. else
  955. queueMicrotask(() => cb(null, []));
  956. return;
  957. }
  958. const children = this.children();
  959. if (this.calledReaddir()) {
  960. const c = children.slice(0, children.provisional);
  961. if (allowZalgo)
  962. cb(null, c);
  963. else
  964. queueMicrotask(() => cb(null, c));
  965. return;
  966. }
  967. // don't have to worry about zalgo at this point.
  968. this.#onReaddirCB.push(cb);
  969. if (this.#readdirCBInFlight) {
  970. return;
  971. }
  972. this.#readdirCBInFlight = true;
  973. // else read the directory, fill up children
  974. // de-provisionalize any provisional children.
  975. const fullpath = this.fullpath();
  976. this.#fs.readdir(fullpath, { withFileTypes: true }, (er, entries) => {
  977. if (er) {
  978. this.#readdirFail(er.code);
  979. children.provisional = 0;
  980. }
  981. else {
  982. // if we didn't get an error, we always get entries.
  983. //@ts-ignore
  984. for (const e of entries) {
  985. this.#readdirAddChild(e, children);
  986. }
  987. this.#readdirSuccess(children);
  988. }
  989. this.#callOnReaddirCB(children.slice(0, children.provisional));
  990. return;
  991. });
  992. }
  993. #asyncReaddirInFlight;
  994. /**
  995. * Return an array of known child entries.
  996. *
  997. * If the Path cannot or does not contain any children, then an empty array
  998. * is returned.
  999. *
  1000. * Results are cached, and thus may be out of date if the filesystem is
  1001. * mutated.
  1002. */
  1003. async readdir() {
  1004. if (!this.canReaddir()) {
  1005. return [];
  1006. }
  1007. const children = this.children();
  1008. if (this.calledReaddir()) {
  1009. return children.slice(0, children.provisional);
  1010. }
  1011. // else read the directory, fill up children
  1012. // de-provisionalize any provisional children.
  1013. const fullpath = this.fullpath();
  1014. if (this.#asyncReaddirInFlight) {
  1015. await this.#asyncReaddirInFlight;
  1016. }
  1017. else {
  1018. /* c8 ignore start */
  1019. let resolve = () => { };
  1020. /* c8 ignore stop */
  1021. this.#asyncReaddirInFlight = new Promise(res => (resolve = res));
  1022. try {
  1023. for (const e of await this.#fs.promises.readdir(fullpath, {
  1024. withFileTypes: true,
  1025. })) {
  1026. this.#readdirAddChild(e, children);
  1027. }
  1028. this.#readdirSuccess(children);
  1029. }
  1030. catch (er) {
  1031. this.#readdirFail(er.code);
  1032. children.provisional = 0;
  1033. }
  1034. this.#asyncReaddirInFlight = undefined;
  1035. resolve();
  1036. }
  1037. return children.slice(0, children.provisional);
  1038. }
  1039. /**
  1040. * synchronous {@link PathBase.readdir}
  1041. */
  1042. readdirSync() {
  1043. if (!this.canReaddir()) {
  1044. return [];
  1045. }
  1046. const children = this.children();
  1047. if (this.calledReaddir()) {
  1048. return children.slice(0, children.provisional);
  1049. }
  1050. // else read the directory, fill up children
  1051. // de-provisionalize any provisional children.
  1052. const fullpath = this.fullpath();
  1053. try {
  1054. for (const e of this.#fs.readdirSync(fullpath, {
  1055. withFileTypes: true,
  1056. })) {
  1057. this.#readdirAddChild(e, children);
  1058. }
  1059. this.#readdirSuccess(children);
  1060. }
  1061. catch (er) {
  1062. this.#readdirFail(er.code);
  1063. children.provisional = 0;
  1064. }
  1065. return children.slice(0, children.provisional);
  1066. }
  1067. canReaddir() {
  1068. if (this.#type & ENOCHILD)
  1069. return false;
  1070. const ifmt = IFMT & this.#type;
  1071. // we always set ENOTDIR when setting IFMT, so should be impossible
  1072. /* c8 ignore start */
  1073. if (!(ifmt === UNKNOWN || ifmt === IFDIR || ifmt === IFLNK)) {
  1074. return false;
  1075. }
  1076. /* c8 ignore stop */
  1077. return true;
  1078. }
  1079. shouldWalk(dirs, walkFilter) {
  1080. return ((this.#type & IFDIR) === IFDIR &&
  1081. !(this.#type & ENOCHILD) &&
  1082. !dirs.has(this) &&
  1083. (!walkFilter || walkFilter(this)));
  1084. }
  1085. /**
  1086. * Return the Path object corresponding to path as resolved
  1087. * by realpath(3).
  1088. *
  1089. * If the realpath call fails for any reason, `undefined` is returned.
  1090. *
  1091. * Result is cached, and thus may be outdated if the filesystem is mutated.
  1092. * On success, returns a Path object.
  1093. */
  1094. async realpath() {
  1095. if (this.#realpath)
  1096. return this.#realpath;
  1097. if ((ENOREALPATH | ENOREADLINK | ENOENT) & this.#type)
  1098. return undefined;
  1099. try {
  1100. const rp = await this.#fs.promises.realpath(this.fullpath());
  1101. return (this.#realpath = this.resolve(rp));
  1102. }
  1103. catch (_) {
  1104. this.#markENOREALPATH();
  1105. }
  1106. }
  1107. /**
  1108. * Synchronous {@link realpath}
  1109. */
  1110. realpathSync() {
  1111. if (this.#realpath)
  1112. return this.#realpath;
  1113. if ((ENOREALPATH | ENOREADLINK | ENOENT) & this.#type)
  1114. return undefined;
  1115. try {
  1116. const rp = this.#fs.realpathSync(this.fullpath());
  1117. return (this.#realpath = this.resolve(rp));
  1118. }
  1119. catch (_) {
  1120. this.#markENOREALPATH();
  1121. }
  1122. }
  1123. /**
  1124. * Internal method to mark this Path object as the scurry cwd,
  1125. * called by {@link PathScurry#chdir}
  1126. *
  1127. * @internal
  1128. */
  1129. [setAsCwd](oldCwd) {
  1130. if (oldCwd === this)
  1131. return;
  1132. const changed = new Set([]);
  1133. let rp = [];
  1134. let p = this;
  1135. while (p && p.parent) {
  1136. changed.add(p);
  1137. p.#relative = rp.join(this.sep);
  1138. p.#relativePosix = rp.join('/');
  1139. p = p.parent;
  1140. rp.push('..');
  1141. }
  1142. // now un-memoize parents of old cwd
  1143. p = oldCwd;
  1144. while (p && p.parent && !changed.has(p)) {
  1145. p.#relative = undefined;
  1146. p.#relativePosix = undefined;
  1147. p = p.parent;
  1148. }
  1149. }
  1150. }
  1151. exports.PathBase = PathBase;
  1152. /**
  1153. * Path class used on win32 systems
  1154. *
  1155. * Uses `'\\'` as the path separator for returned paths, either `'\\'` or `'/'`
  1156. * as the path separator for parsing paths.
  1157. */
  1158. class PathWin32 extends PathBase {
  1159. /**
  1160. * Separator for generating path strings.
  1161. */
  1162. sep = '\\';
  1163. /**
  1164. * Separator for parsing path strings.
  1165. */
  1166. splitSep = eitherSep;
  1167. /**
  1168. * Do not create new Path objects directly. They should always be accessed
  1169. * via the PathScurry class or other methods on the Path class.
  1170. *
  1171. * @internal
  1172. */
  1173. constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
  1174. super(name, type, root, roots, nocase, children, opts);
  1175. }
  1176. /**
  1177. * @internal
  1178. */
  1179. newChild(name, type = UNKNOWN, opts = {}) {
  1180. return new PathWin32(name, type, this.root, this.roots, this.nocase, this.childrenCache(), opts);
  1181. }
  1182. /**
  1183. * @internal
  1184. */
  1185. getRootString(path) {
  1186. return path_1.win32.parse(path).root;
  1187. }
  1188. /**
  1189. * @internal
  1190. */
  1191. getRoot(rootPath) {
  1192. rootPath = uncToDrive(rootPath.toUpperCase());
  1193. if (rootPath === this.root.name) {
  1194. return this.root;
  1195. }
  1196. // ok, not that one, check if it matches another we know about
  1197. for (const [compare, root] of Object.entries(this.roots)) {
  1198. if (this.sameRoot(rootPath, compare)) {
  1199. return (this.roots[rootPath] = root);
  1200. }
  1201. }
  1202. // otherwise, have to create a new one.
  1203. return (this.roots[rootPath] = new PathScurryWin32(rootPath, this).root);
  1204. }
  1205. /**
  1206. * @internal
  1207. */
  1208. sameRoot(rootPath, compare = this.root.name) {
  1209. // windows can (rarely) have case-sensitive filesystem, but
  1210. // UNC and drive letters are always case-insensitive, and canonically
  1211. // represented uppercase.
  1212. rootPath = rootPath
  1213. .toUpperCase()
  1214. .replace(/\//g, '\\')
  1215. .replace(uncDriveRegexp, '$1\\');
  1216. return rootPath === compare;
  1217. }
  1218. }
  1219. exports.PathWin32 = PathWin32;
  1220. /**
  1221. * Path class used on all posix systems.
  1222. *
  1223. * Uses `'/'` as the path separator.
  1224. */
  1225. class PathPosix extends PathBase {
  1226. /**
  1227. * separator for parsing path strings
  1228. */
  1229. splitSep = '/';
  1230. /**
  1231. * separator for generating path strings
  1232. */
  1233. sep = '/';
  1234. /**
  1235. * Do not create new Path objects directly. They should always be accessed
  1236. * via the PathScurry class or other methods on the Path class.
  1237. *
  1238. * @internal
  1239. */
  1240. constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
  1241. super(name, type, root, roots, nocase, children, opts);
  1242. }
  1243. /**
  1244. * @internal
  1245. */
  1246. getRootString(path) {
  1247. return path.startsWith('/') ? '/' : '';
  1248. }
  1249. /**
  1250. * @internal
  1251. */
  1252. getRoot(_rootPath) {
  1253. return this.root;
  1254. }
  1255. /**
  1256. * @internal
  1257. */
  1258. newChild(name, type = UNKNOWN, opts = {}) {
  1259. return new PathPosix(name, type, this.root, this.roots, this.nocase, this.childrenCache(), opts);
  1260. }
  1261. }
  1262. exports.PathPosix = PathPosix;
  1263. /**
  1264. * The base class for all PathScurry classes, providing the interface for path
  1265. * resolution and filesystem operations.
  1266. *
  1267. * Typically, you should *not* instantiate this class directly, but rather one
  1268. * of the platform-specific classes, or the exported {@link PathScurry} which
  1269. * defaults to the current platform.
  1270. */
  1271. class PathScurryBase {
  1272. /**
  1273. * The root Path entry for the current working directory of this Scurry
  1274. */
  1275. root;
  1276. /**
  1277. * The string path for the root of this Scurry's current working directory
  1278. */
  1279. rootPath;
  1280. /**
  1281. * A collection of all roots encountered, referenced by rootPath
  1282. */
  1283. roots;
  1284. /**
  1285. * The Path entry corresponding to this PathScurry's current working directory.
  1286. */
  1287. cwd;
  1288. #resolveCache;
  1289. #resolvePosixCache;
  1290. #children;
  1291. /**
  1292. * Perform path comparisons case-insensitively.
  1293. *
  1294. * Defaults true on Darwin and Windows systems, false elsewhere.
  1295. */
  1296. nocase;
  1297. #fs;
  1298. /**
  1299. * This class should not be instantiated directly.
  1300. *
  1301. * Use PathScurryWin32, PathScurryDarwin, PathScurryPosix, or PathScurry
  1302. *
  1303. * @internal
  1304. */
  1305. constructor(cwd = process.cwd(), pathImpl, sep, { nocase, childrenCacheSize = 16 * 1024, fs = defaultFS, } = {}) {
  1306. this.#fs = fsFromOption(fs);
  1307. if (cwd instanceof URL || cwd.startsWith('file://')) {
  1308. cwd = (0, url_1.fileURLToPath)(cwd);
  1309. }
  1310. // resolve and split root, and then add to the store.
  1311. // this is the only time we call path.resolve()
  1312. const cwdPath = pathImpl.resolve(cwd);
  1313. this.roots = Object.create(null);
  1314. this.rootPath = this.parseRootPath(cwdPath);
  1315. this.#resolveCache = new ResolveCache();
  1316. this.#resolvePosixCache = new ResolveCache();
  1317. this.#children = new ChildrenCache(childrenCacheSize);
  1318. const split = cwdPath.substring(this.rootPath.length).split(sep);
  1319. // resolve('/') leaves '', splits to [''], we don't want that.
  1320. if (split.length === 1 && !split[0]) {
  1321. split.pop();
  1322. }
  1323. /* c8 ignore start */
  1324. if (nocase === undefined) {
  1325. throw new TypeError('must provide nocase setting to PathScurryBase ctor');
  1326. }
  1327. /* c8 ignore stop */
  1328. this.nocase = nocase;
  1329. this.root = this.newRoot(this.#fs);
  1330. this.roots[this.rootPath] = this.root;
  1331. let prev = this.root;
  1332. let len = split.length - 1;
  1333. const joinSep = pathImpl.sep;
  1334. let abs = this.rootPath;
  1335. let sawFirst = false;
  1336. for (const part of split) {
  1337. const l = len--;
  1338. prev = prev.child(part, {
  1339. relative: new Array(l).fill('..').join(joinSep),
  1340. relativePosix: new Array(l).fill('..').join('/'),
  1341. fullpath: (abs += (sawFirst ? '' : joinSep) + part),
  1342. });
  1343. sawFirst = true;
  1344. }
  1345. this.cwd = prev;
  1346. }
  1347. /**
  1348. * Get the depth of a provided path, string, or the cwd
  1349. */
  1350. depth(path = this.cwd) {
  1351. if (typeof path === 'string') {
  1352. path = this.cwd.resolve(path);
  1353. }
  1354. return path.depth();
  1355. }
  1356. /**
  1357. * Return the cache of child entries. Exposed so subclasses can create
  1358. * child Path objects in a platform-specific way.
  1359. *
  1360. * @internal
  1361. */
  1362. childrenCache() {
  1363. return this.#children;
  1364. }
  1365. /**
  1366. * Resolve one or more path strings to a resolved string
  1367. *
  1368. * Same interface as require('path').resolve.
  1369. *
  1370. * Much faster than path.resolve() when called multiple times for the same
  1371. * path, because the resolved Path objects are cached. Much slower
  1372. * otherwise.
  1373. */
  1374. resolve(...paths) {
  1375. // first figure out the minimum number of paths we have to test
  1376. // we always start at cwd, but any absolutes will bump the start
  1377. let r = '';
  1378. for (let i = paths.length - 1; i >= 0; i--) {
  1379. const p = paths[i];
  1380. if (!p || p === '.')
  1381. continue;
  1382. r = r ? `${p}/${r}` : p;
  1383. if (this.isAbsolute(p)) {
  1384. break;
  1385. }
  1386. }
  1387. const cached = this.#resolveCache.get(r);
  1388. if (cached !== undefined) {
  1389. return cached;
  1390. }
  1391. const result = this.cwd.resolve(r).fullpath();
  1392. this.#resolveCache.set(r, result);
  1393. return result;
  1394. }
  1395. /**
  1396. * Resolve one or more path strings to a resolved string, returning
  1397. * the posix path. Identical to .resolve() on posix systems, but on
  1398. * windows will return a forward-slash separated UNC path.
  1399. *
  1400. * Same interface as require('path').resolve.
  1401. *
  1402. * Much faster than path.resolve() when called multiple times for the same
  1403. * path, because the resolved Path objects are cached. Much slower
  1404. * otherwise.
  1405. */
  1406. resolvePosix(...paths) {
  1407. // first figure out the minimum number of paths we have to test
  1408. // we always start at cwd, but any absolutes will bump the start
  1409. let r = '';
  1410. for (let i = paths.length - 1; i >= 0; i--) {
  1411. const p = paths[i];
  1412. if (!p || p === '.')
  1413. continue;
  1414. r = r ? `${p}/${r}` : p;
  1415. if (this.isAbsolute(p)) {
  1416. break;
  1417. }
  1418. }
  1419. const cached = this.#resolvePosixCache.get(r);
  1420. if (cached !== undefined) {
  1421. return cached;
  1422. }
  1423. const result = this.cwd.resolve(r).fullpathPosix();
  1424. this.#resolvePosixCache.set(r, result);
  1425. return result;
  1426. }
  1427. /**
  1428. * find the relative path from the cwd to the supplied path string or entry
  1429. */
  1430. relative(entry = this.cwd) {
  1431. if (typeof entry === 'string') {
  1432. entry = this.cwd.resolve(entry);
  1433. }
  1434. return entry.relative();
  1435. }
  1436. /**
  1437. * find the relative path from the cwd to the supplied path string or
  1438. * entry, using / as the path delimiter, even on Windows.
  1439. */
  1440. relativePosix(entry = this.cwd) {
  1441. if (typeof entry === 'string') {
  1442. entry = this.cwd.resolve(entry);
  1443. }
  1444. return entry.relativePosix();
  1445. }
  1446. /**
  1447. * Return the basename for the provided string or Path object
  1448. */
  1449. basename(entry = this.cwd) {
  1450. if (typeof entry === 'string') {
  1451. entry = this.cwd.resolve(entry);
  1452. }
  1453. return entry.name;
  1454. }
  1455. /**
  1456. * Return the dirname for the provided string or Path object
  1457. */
  1458. dirname(entry = this.cwd) {
  1459. if (typeof entry === 'string') {
  1460. entry = this.cwd.resolve(entry);
  1461. }
  1462. return (entry.parent || entry).fullpath();
  1463. }
  1464. async readdir(entry = this.cwd, opts = {
  1465. withFileTypes: true,
  1466. }) {
  1467. if (typeof entry === 'string') {
  1468. entry = this.cwd.resolve(entry);
  1469. }
  1470. else if (!(entry instanceof PathBase)) {
  1471. opts = entry;
  1472. entry = this.cwd;
  1473. }
  1474. const { withFileTypes } = opts;
  1475. if (!entry.canReaddir()) {
  1476. return [];
  1477. }
  1478. else {
  1479. const p = await entry.readdir();
  1480. return withFileTypes ? p : p.map(e => e.name);
  1481. }
  1482. }
  1483. readdirSync(entry = this.cwd, opts = {
  1484. withFileTypes: true,
  1485. }) {
  1486. if (typeof entry === 'string') {
  1487. entry = this.cwd.resolve(entry);
  1488. }
  1489. else if (!(entry instanceof PathBase)) {
  1490. opts = entry;
  1491. entry = this.cwd;
  1492. }
  1493. const { withFileTypes = true } = opts;
  1494. if (!entry.canReaddir()) {
  1495. return [];
  1496. }
  1497. else if (withFileTypes) {
  1498. return entry.readdirSync();
  1499. }
  1500. else {
  1501. return entry.readdirSync().map(e => e.name);
  1502. }
  1503. }
  1504. /**
  1505. * Call lstat() on the string or Path object, and update all known
  1506. * information that can be determined.
  1507. *
  1508. * Note that unlike `fs.lstat()`, the returned value does not contain some
  1509. * information, such as `mode`, `dev`, `nlink`, and `ino`. If that
  1510. * information is required, you will need to call `fs.lstat` yourself.
  1511. *
  1512. * If the Path refers to a nonexistent file, or if the lstat call fails for
  1513. * any reason, `undefined` is returned. Otherwise the updated Path object is
  1514. * returned.
  1515. *
  1516. * Results are cached, and thus may be out of date if the filesystem is
  1517. * mutated.
  1518. */
  1519. async lstat(entry = this.cwd) {
  1520. if (typeof entry === 'string') {
  1521. entry = this.cwd.resolve(entry);
  1522. }
  1523. return entry.lstat();
  1524. }
  1525. /**
  1526. * synchronous {@link PathScurryBase.lstat}
  1527. */
  1528. lstatSync(entry = this.cwd) {
  1529. if (typeof entry === 'string') {
  1530. entry = this.cwd.resolve(entry);
  1531. }
  1532. return entry.lstatSync();
  1533. }
  1534. async readlink(entry = this.cwd, { withFileTypes } = {
  1535. withFileTypes: false,
  1536. }) {
  1537. if (typeof entry === 'string') {
  1538. entry = this.cwd.resolve(entry);
  1539. }
  1540. else if (!(entry instanceof PathBase)) {
  1541. withFileTypes = entry.withFileTypes;
  1542. entry = this.cwd;
  1543. }
  1544. const e = await entry.readlink();
  1545. return withFileTypes ? e : e?.fullpath();
  1546. }
  1547. readlinkSync(entry = this.cwd, { withFileTypes } = {
  1548. withFileTypes: false,
  1549. }) {
  1550. if (typeof entry === 'string') {
  1551. entry = this.cwd.resolve(entry);
  1552. }
  1553. else if (!(entry instanceof PathBase)) {
  1554. withFileTypes = entry.withFileTypes;
  1555. entry = this.cwd;
  1556. }
  1557. const e = entry.readlinkSync();
  1558. return withFileTypes ? e : e?.fullpath();
  1559. }
  1560. async realpath(entry = this.cwd, { withFileTypes } = {
  1561. withFileTypes: false,
  1562. }) {
  1563. if (typeof entry === 'string') {
  1564. entry = this.cwd.resolve(entry);
  1565. }
  1566. else if (!(entry instanceof PathBase)) {
  1567. withFileTypes = entry.withFileTypes;
  1568. entry = this.cwd;
  1569. }
  1570. const e = await entry.realpath();
  1571. return withFileTypes ? e : e?.fullpath();
  1572. }
  1573. realpathSync(entry = this.cwd, { withFileTypes } = {
  1574. withFileTypes: false,
  1575. }) {
  1576. if (typeof entry === 'string') {
  1577. entry = this.cwd.resolve(entry);
  1578. }
  1579. else if (!(entry instanceof PathBase)) {
  1580. withFileTypes = entry.withFileTypes;
  1581. entry = this.cwd;
  1582. }
  1583. const e = entry.realpathSync();
  1584. return withFileTypes ? e : e?.fullpath();
  1585. }
  1586. async walk(entry = this.cwd, opts = {}) {
  1587. if (typeof entry === 'string') {
  1588. entry = this.cwd.resolve(entry);
  1589. }
  1590. else if (!(entry instanceof PathBase)) {
  1591. opts = entry;
  1592. entry = this.cwd;
  1593. }
  1594. const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
  1595. const results = [];
  1596. if (!filter || filter(entry)) {
  1597. results.push(withFileTypes ? entry : entry.fullpath());
  1598. }
  1599. const dirs = new Set();
  1600. const walk = (dir, cb) => {
  1601. dirs.add(dir);
  1602. dir.readdirCB((er, entries) => {
  1603. /* c8 ignore start */
  1604. if (er) {
  1605. return cb(er);
  1606. }
  1607. /* c8 ignore stop */
  1608. let len = entries.length;
  1609. if (!len)
  1610. return cb();
  1611. const next = () => {
  1612. if (--len === 0) {
  1613. cb();
  1614. }
  1615. };
  1616. for (const e of entries) {
  1617. if (!filter || filter(e)) {
  1618. results.push(withFileTypes ? e : e.fullpath());
  1619. }
  1620. if (follow && e.isSymbolicLink()) {
  1621. e.realpath()
  1622. .then(r => (r?.isUnknown() ? r.lstat() : r))
  1623. .then(r => r?.shouldWalk(dirs, walkFilter) ? walk(r, next) : next());
  1624. }
  1625. else {
  1626. if (e.shouldWalk(dirs, walkFilter)) {
  1627. walk(e, next);
  1628. }
  1629. else {
  1630. next();
  1631. }
  1632. }
  1633. }
  1634. }, true); // zalgooooooo
  1635. };
  1636. const start = entry;
  1637. return new Promise((res, rej) => {
  1638. walk(start, er => {
  1639. /* c8 ignore start */
  1640. if (er)
  1641. return rej(er);
  1642. /* c8 ignore stop */
  1643. res(results);
  1644. });
  1645. });
  1646. }
  1647. walkSync(entry = this.cwd, opts = {}) {
  1648. if (typeof entry === 'string') {
  1649. entry = this.cwd.resolve(entry);
  1650. }
  1651. else if (!(entry instanceof PathBase)) {
  1652. opts = entry;
  1653. entry = this.cwd;
  1654. }
  1655. const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
  1656. const results = [];
  1657. if (!filter || filter(entry)) {
  1658. results.push(withFileTypes ? entry : entry.fullpath());
  1659. }
  1660. const dirs = new Set([entry]);
  1661. for (const dir of dirs) {
  1662. const entries = dir.readdirSync();
  1663. for (const e of entries) {
  1664. if (!filter || filter(e)) {
  1665. results.push(withFileTypes ? e : e.fullpath());
  1666. }
  1667. let r = e;
  1668. if (e.isSymbolicLink()) {
  1669. if (!(follow && (r = e.realpathSync())))
  1670. continue;
  1671. if (r.isUnknown())
  1672. r.lstatSync();
  1673. }
  1674. if (r.shouldWalk(dirs, walkFilter)) {
  1675. dirs.add(r);
  1676. }
  1677. }
  1678. }
  1679. return results;
  1680. }
  1681. /**
  1682. * Support for `for await`
  1683. *
  1684. * Alias for {@link PathScurryBase.iterate}
  1685. *
  1686. * Note: As of Node 19, this is very slow, compared to other methods of
  1687. * walking. Consider using {@link PathScurryBase.stream} if memory overhead
  1688. * and backpressure are concerns, or {@link PathScurryBase.walk} if not.
  1689. */
  1690. [Symbol.asyncIterator]() {
  1691. return this.iterate();
  1692. }
  1693. iterate(entry = this.cwd, options = {}) {
  1694. // iterating async over the stream is significantly more performant,
  1695. // especially in the warm-cache scenario, because it buffers up directory
  1696. // entries in the background instead of waiting for a yield for each one.
  1697. if (typeof entry === 'string') {
  1698. entry = this.cwd.resolve(entry);
  1699. }
  1700. else if (!(entry instanceof PathBase)) {
  1701. options = entry;
  1702. entry = this.cwd;
  1703. }
  1704. return this.stream(entry, options)[Symbol.asyncIterator]();
  1705. }
  1706. /**
  1707. * Iterating over a PathScurry performs a synchronous walk.
  1708. *
  1709. * Alias for {@link PathScurryBase.iterateSync}
  1710. */
  1711. [Symbol.iterator]() {
  1712. return this.iterateSync();
  1713. }
  1714. *iterateSync(entry = this.cwd, opts = {}) {
  1715. if (typeof entry === 'string') {
  1716. entry = this.cwd.resolve(entry);
  1717. }
  1718. else if (!(entry instanceof PathBase)) {
  1719. opts = entry;
  1720. entry = this.cwd;
  1721. }
  1722. const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
  1723. if (!filter || filter(entry)) {
  1724. yield withFileTypes ? entry : entry.fullpath();
  1725. }
  1726. const dirs = new Set([entry]);
  1727. for (const dir of dirs) {
  1728. const entries = dir.readdirSync();
  1729. for (const e of entries) {
  1730. if (!filter || filter(e)) {
  1731. yield withFileTypes ? e : e.fullpath();
  1732. }
  1733. let r = e;
  1734. if (e.isSymbolicLink()) {
  1735. if (!(follow && (r = e.realpathSync())))
  1736. continue;
  1737. if (r.isUnknown())
  1738. r.lstatSync();
  1739. }
  1740. if (r.shouldWalk(dirs, walkFilter)) {
  1741. dirs.add(r);
  1742. }
  1743. }
  1744. }
  1745. }
  1746. stream(entry = this.cwd, opts = {}) {
  1747. if (typeof entry === 'string') {
  1748. entry = this.cwd.resolve(entry);
  1749. }
  1750. else if (!(entry instanceof PathBase)) {
  1751. opts = entry;
  1752. entry = this.cwd;
  1753. }
  1754. const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
  1755. const results = new minipass_1.Minipass({ objectMode: true });
  1756. if (!filter || filter(entry)) {
  1757. results.write(withFileTypes ? entry : entry.fullpath());
  1758. }
  1759. const dirs = new Set();
  1760. const queue = [entry];
  1761. let processing = 0;
  1762. const process = () => {
  1763. let paused = false;
  1764. while (!paused) {
  1765. const dir = queue.shift();
  1766. if (!dir) {
  1767. if (processing === 0)
  1768. results.end();
  1769. return;
  1770. }
  1771. processing++;
  1772. dirs.add(dir);
  1773. const onReaddir = (er, entries, didRealpaths = false) => {
  1774. /* c8 ignore start */
  1775. if (er)
  1776. return results.emit('error', er);
  1777. /* c8 ignore stop */
  1778. if (follow && !didRealpaths) {
  1779. const promises = [];
  1780. for (const e of entries) {
  1781. if (e.isSymbolicLink()) {
  1782. promises.push(e
  1783. .realpath()
  1784. .then((r) => r?.isUnknown() ? r.lstat() : r));
  1785. }
  1786. }
  1787. if (promises.length) {
  1788. Promise.all(promises).then(() => onReaddir(null, entries, true));
  1789. return;
  1790. }
  1791. }
  1792. for (const e of entries) {
  1793. if (e && (!filter || filter(e))) {
  1794. if (!results.write(withFileTypes ? e : e.fullpath())) {
  1795. paused = true;
  1796. }
  1797. }
  1798. }
  1799. processing--;
  1800. for (const e of entries) {
  1801. const r = e.realpathCached() || e;
  1802. if (r.shouldWalk(dirs, walkFilter)) {
  1803. queue.push(r);
  1804. }
  1805. }
  1806. if (paused && !results.flowing) {
  1807. results.once('drain', process);
  1808. }
  1809. else if (!sync) {
  1810. process();
  1811. }
  1812. };
  1813. // zalgo containment
  1814. let sync = true;
  1815. dir.readdirCB(onReaddir, true);
  1816. sync = false;
  1817. }
  1818. };
  1819. process();
  1820. return results;
  1821. }
  1822. streamSync(entry = this.cwd, opts = {}) {
  1823. if (typeof entry === 'string') {
  1824. entry = this.cwd.resolve(entry);
  1825. }
  1826. else if (!(entry instanceof PathBase)) {
  1827. opts = entry;
  1828. entry = this.cwd;
  1829. }
  1830. const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
  1831. const results = new minipass_1.Minipass({ objectMode: true });
  1832. const dirs = new Set();
  1833. if (!filter || filter(entry)) {
  1834. results.write(withFileTypes ? entry : entry.fullpath());
  1835. }
  1836. const queue = [entry];
  1837. let processing = 0;
  1838. const process = () => {
  1839. let paused = false;
  1840. while (!paused) {
  1841. const dir = queue.shift();
  1842. if (!dir) {
  1843. if (processing === 0)
  1844. results.end();
  1845. return;
  1846. }
  1847. processing++;
  1848. dirs.add(dir);
  1849. const entries = dir.readdirSync();
  1850. for (const e of entries) {
  1851. if (!filter || filter(e)) {
  1852. if (!results.write(withFileTypes ? e : e.fullpath())) {
  1853. paused = true;
  1854. }
  1855. }
  1856. }
  1857. processing--;
  1858. for (const e of entries) {
  1859. let r = e;
  1860. if (e.isSymbolicLink()) {
  1861. if (!(follow && (r = e.realpathSync())))
  1862. continue;
  1863. if (r.isUnknown())
  1864. r.lstatSync();
  1865. }
  1866. if (r.shouldWalk(dirs, walkFilter)) {
  1867. queue.push(r);
  1868. }
  1869. }
  1870. }
  1871. if (paused && !results.flowing)
  1872. results.once('drain', process);
  1873. };
  1874. process();
  1875. return results;
  1876. }
  1877. chdir(path = this.cwd) {
  1878. const oldCwd = this.cwd;
  1879. this.cwd = typeof path === 'string' ? this.cwd.resolve(path) : path;
  1880. this.cwd[setAsCwd](oldCwd);
  1881. }
  1882. }
  1883. exports.PathScurryBase = PathScurryBase;
  1884. /**
  1885. * Windows implementation of {@link PathScurryBase}
  1886. *
  1887. * Defaults to case insensitve, uses `'\\'` to generate path strings. Uses
  1888. * {@link PathWin32} for Path objects.
  1889. */
  1890. class PathScurryWin32 extends PathScurryBase {
  1891. /**
  1892. * separator for generating path strings
  1893. */
  1894. sep = '\\';
  1895. constructor(cwd = process.cwd(), opts = {}) {
  1896. const { nocase = true } = opts;
  1897. super(cwd, path_1.win32, '\\', { ...opts, nocase });
  1898. this.nocase = nocase;
  1899. for (let p = this.cwd; p; p = p.parent) {
  1900. p.nocase = this.nocase;
  1901. }
  1902. }
  1903. /**
  1904. * @internal
  1905. */
  1906. parseRootPath(dir) {
  1907. // if the path starts with a single separator, it's not a UNC, and we'll
  1908. // just get separator as the root, and driveFromUNC will return \
  1909. // In that case, mount \ on the root from the cwd.
  1910. return path_1.win32.parse(dir).root.toUpperCase();
  1911. }
  1912. /**
  1913. * @internal
  1914. */
  1915. newRoot(fs) {
  1916. return new PathWin32(this.rootPath, IFDIR, undefined, this.roots, this.nocase, this.childrenCache(), { fs });
  1917. }
  1918. /**
  1919. * Return true if the provided path string is an absolute path
  1920. */
  1921. isAbsolute(p) {
  1922. return (p.startsWith('/') || p.startsWith('\\') || /^[a-z]:(\/|\\)/i.test(p));
  1923. }
  1924. }
  1925. exports.PathScurryWin32 = PathScurryWin32;
  1926. /**
  1927. * {@link PathScurryBase} implementation for all posix systems other than Darwin.
  1928. *
  1929. * Defaults to case-sensitive matching, uses `'/'` to generate path strings.
  1930. *
  1931. * Uses {@link PathPosix} for Path objects.
  1932. */
  1933. class PathScurryPosix extends PathScurryBase {
  1934. /**
  1935. * separator for generating path strings
  1936. */
  1937. sep = '/';
  1938. constructor(cwd = process.cwd(), opts = {}) {
  1939. const { nocase = false } = opts;
  1940. super(cwd, path_1.posix, '/', { ...opts, nocase });
  1941. this.nocase = nocase;
  1942. }
  1943. /**
  1944. * @internal
  1945. */
  1946. parseRootPath(_dir) {
  1947. return '/';
  1948. }
  1949. /**
  1950. * @internal
  1951. */
  1952. newRoot(fs) {
  1953. return new PathPosix(this.rootPath, IFDIR, undefined, this.roots, this.nocase, this.childrenCache(), { fs });
  1954. }
  1955. /**
  1956. * Return true if the provided path string is an absolute path
  1957. */
  1958. isAbsolute(p) {
  1959. return p.startsWith('/');
  1960. }
  1961. }
  1962. exports.PathScurryPosix = PathScurryPosix;
  1963. /**
  1964. * {@link PathScurryBase} implementation for Darwin (macOS) systems.
  1965. *
  1966. * Defaults to case-insensitive matching, uses `'/'` for generating path
  1967. * strings.
  1968. *
  1969. * Uses {@link PathPosix} for Path objects.
  1970. */
  1971. class PathScurryDarwin extends PathScurryPosix {
  1972. constructor(cwd = process.cwd(), opts = {}) {
  1973. const { nocase = true } = opts;
  1974. super(cwd, { ...opts, nocase });
  1975. }
  1976. }
  1977. exports.PathScurryDarwin = PathScurryDarwin;
  1978. /**
  1979. * Default {@link PathBase} implementation for the current platform.
  1980. *
  1981. * {@link PathWin32} on Windows systems, {@link PathPosix} on all others.
  1982. */
  1983. exports.Path = process.platform === 'win32' ? PathWin32 : PathPosix;
  1984. /**
  1985. * Default {@link PathScurryBase} implementation for the current platform.
  1986. *
  1987. * {@link PathScurryWin32} on Windows systems, {@link PathScurryDarwin} on
  1988. * Darwin (macOS) systems, {@link PathScurryPosix} on all others.
  1989. */
  1990. exports.PathScurry = process.platform === 'win32'
  1991. ? PathScurryWin32
  1992. : process.platform === 'darwin'
  1993. ? PathScurryDarwin
  1994. : PathScurryPosix;
  1995. //# sourceMappingURL=index.js.map