PageRenderTime 48ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/node_modules/webpack/lib/util/fs.js

https://gitlab.com/ahmad.jamal/sally
JavaScript | 326 lines | 146 code | 21 blank | 159 comment | 45 complexity | d1cdb3c77dea26f056858cba131320bd MD5 | raw file
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const path = require("path");
  7. /** @typedef {import("../../declarations/WebpackOptions").WatchOptions} WatchOptions */
  8. /** @typedef {import("../FileSystemInfo").FileSystemInfoEntry} FileSystemInfoEntry */
  9. /**
  10. * @typedef {Object} IStats
  11. * @property {() => boolean} isFile
  12. * @property {() => boolean} isDirectory
  13. * @property {() => boolean} isBlockDevice
  14. * @property {() => boolean} isCharacterDevice
  15. * @property {() => boolean} isSymbolicLink
  16. * @property {() => boolean} isFIFO
  17. * @property {() => boolean} isSocket
  18. * @property {number | bigint} dev
  19. * @property {number | bigint} ino
  20. * @property {number | bigint} mode
  21. * @property {number | bigint} nlink
  22. * @property {number | bigint} uid
  23. * @property {number | bigint} gid
  24. * @property {number | bigint} rdev
  25. * @property {number | bigint} size
  26. * @property {number | bigint} blksize
  27. * @property {number | bigint} blocks
  28. * @property {number | bigint} atimeMs
  29. * @property {number | bigint} mtimeMs
  30. * @property {number | bigint} ctimeMs
  31. * @property {number | bigint} birthtimeMs
  32. * @property {Date} atime
  33. * @property {Date} mtime
  34. * @property {Date} ctime
  35. * @property {Date} birthtime
  36. */
  37. /**
  38. * @typedef {Object} IDirent
  39. * @property {() => boolean} isFile
  40. * @property {() => boolean} isDirectory
  41. * @property {() => boolean} isBlockDevice
  42. * @property {() => boolean} isCharacterDevice
  43. * @property {() => boolean} isSymbolicLink
  44. * @property {() => boolean} isFIFO
  45. * @property {() => boolean} isSocket
  46. * @property {string | Buffer} name
  47. */
  48. /** @typedef {function((NodeJS.ErrnoException | null)=): void} Callback */
  49. /** @typedef {function((NodeJS.ErrnoException | null)=, Buffer=): void} BufferCallback */
  50. /** @typedef {function((NodeJS.ErrnoException | null)=, Buffer|string=): void} BufferOrStringCallback */
  51. /** @typedef {function((NodeJS.ErrnoException | null)=, (string | Buffer)[] | IDirent[]=): void} DirentArrayCallback */
  52. /** @typedef {function((NodeJS.ErrnoException | null)=, string=): void} StringCallback */
  53. /** @typedef {function((NodeJS.ErrnoException | null)=, number=): void} NumberCallback */
  54. /** @typedef {function((NodeJS.ErrnoException | null)=, IStats=): void} StatsCallback */
  55. /** @typedef {function((NodeJS.ErrnoException | Error | null)=, any=): void} ReadJsonCallback */
  56. /** @typedef {function((NodeJS.ErrnoException | Error | null)=, IStats|string=): void} LstatReadlinkAbsoluteCallback */
  57. /**
  58. * @typedef {Object} Watcher
  59. * @property {function(): void} close closes the watcher and all underlying file watchers
  60. * @property {function(): void} pause closes the watcher, but keeps underlying file watchers alive until the next watch call
  61. * @property {function(): Set<string>=} getAggregatedChanges get current aggregated changes that have not yet send to callback
  62. * @property {function(): Set<string>=} getAggregatedRemovals get current aggregated removals that have not yet send to callback
  63. * @property {function(): Map<string, FileSystemInfoEntry | "ignore">} getFileTimeInfoEntries get info about files
  64. * @property {function(): Map<string, FileSystemInfoEntry | "ignore">} getContextTimeInfoEntries get info about directories
  65. */
  66. /**
  67. * @callback WatchMethod
  68. * @param {Iterable<string>} files watched files
  69. * @param {Iterable<string>} directories watched directories
  70. * @param {Iterable<string>} missing watched exitance entries
  71. * @param {number} startTime timestamp of start time
  72. * @param {WatchOptions} options options object
  73. * @param {function(Error=, Map<string, FileSystemInfoEntry | "ignore">, Map<string, FileSystemInfoEntry | "ignore">, Set<string>, Set<string>): void} callback aggregated callback
  74. * @param {function(string, number): void} callbackUndelayed callback when the first change was detected
  75. * @returns {Watcher} a watcher
  76. */
  77. // TODO webpack 6 make optional methods required
  78. /**
  79. * @typedef {Object} OutputFileSystem
  80. * @property {function(string, Buffer|string, Callback): void} writeFile
  81. * @property {function(string, Callback): void} mkdir
  82. * @property {function(string, DirentArrayCallback): void=} readdir
  83. * @property {function(string, Callback): void=} rmdir
  84. * @property {function(string, Callback): void=} unlink
  85. * @property {function(string, StatsCallback): void} stat
  86. * @property {function(string, BufferOrStringCallback): void} readFile
  87. * @property {(function(string, string): string)=} join
  88. * @property {(function(string, string): string)=} relative
  89. * @property {(function(string): string)=} dirname
  90. */
  91. /**
  92. * @typedef {Object} InputFileSystem
  93. * @property {function(string, BufferOrStringCallback): void} readFile
  94. * @property {(function(string, ReadJsonCallback): void)=} readJson
  95. * @property {function(string, BufferOrStringCallback): void} readlink
  96. * @property {function(string, DirentArrayCallback): void} readdir
  97. * @property {function(string, StatsCallback): void} stat
  98. * @property {function(string, StatsCallback): void=} lstat
  99. * @property {(function(string, BufferOrStringCallback): void)=} realpath
  100. * @property {(function(string=): void)=} purge
  101. * @property {(function(string, string): string)=} join
  102. * @property {(function(string, string): string)=} relative
  103. * @property {(function(string): string)=} dirname
  104. */
  105. /**
  106. * @typedef {Object} WatchFileSystem
  107. * @property {WatchMethod} watch
  108. */
  109. /**
  110. * @typedef {Object} IntermediateFileSystemExtras
  111. * @property {function(string): void} mkdirSync
  112. * @property {function(string): NodeJS.WritableStream} createWriteStream
  113. * @property {function(string, string, NumberCallback): void} open
  114. * @property {function(number, Buffer, number, number, number, NumberCallback): void} read
  115. * @property {function(number, Callback): void} close
  116. * @property {function(string, string, Callback): void} rename
  117. */
  118. /** @typedef {InputFileSystem & OutputFileSystem & IntermediateFileSystemExtras} IntermediateFileSystem */
  119. /**
  120. *
  121. * @param {InputFileSystem|OutputFileSystem|undefined} fs a file system
  122. * @param {string} rootPath the root path
  123. * @param {string} targetPath the target path
  124. * @returns {string} location of targetPath relative to rootPath
  125. */
  126. const relative = (fs, rootPath, targetPath) => {
  127. if (fs && fs.relative) {
  128. return fs.relative(rootPath, targetPath);
  129. } else if (path.posix.isAbsolute(rootPath)) {
  130. return path.posix.relative(rootPath, targetPath);
  131. } else if (path.win32.isAbsolute(rootPath)) {
  132. return path.win32.relative(rootPath, targetPath);
  133. } else {
  134. throw new Error(
  135. `${rootPath} is neither a posix nor a windows path, and there is no 'relative' method defined in the file system`
  136. );
  137. }
  138. };
  139. exports.relative = relative;
  140. /**
  141. * @param {InputFileSystem|OutputFileSystem|undefined} fs a file system
  142. * @param {string} rootPath a path
  143. * @param {string} filename a filename
  144. * @returns {string} the joined path
  145. */
  146. const join = (fs, rootPath, filename) => {
  147. if (fs && fs.join) {
  148. return fs.join(rootPath, filename);
  149. } else if (path.posix.isAbsolute(rootPath)) {
  150. return path.posix.join(rootPath, filename);
  151. } else if (path.win32.isAbsolute(rootPath)) {
  152. return path.win32.join(rootPath, filename);
  153. } else {
  154. throw new Error(
  155. `${rootPath} is neither a posix nor a windows path, and there is no 'join' method defined in the file system`
  156. );
  157. }
  158. };
  159. exports.join = join;
  160. /**
  161. * @param {InputFileSystem|OutputFileSystem|undefined} fs a file system
  162. * @param {string} absPath an absolute path
  163. * @returns {string} the parent directory of the absolute path
  164. */
  165. const dirname = (fs, absPath) => {
  166. if (fs && fs.dirname) {
  167. return fs.dirname(absPath);
  168. } else if (path.posix.isAbsolute(absPath)) {
  169. return path.posix.dirname(absPath);
  170. } else if (path.win32.isAbsolute(absPath)) {
  171. return path.win32.dirname(absPath);
  172. } else {
  173. throw new Error(
  174. `${absPath} is neither a posix nor a windows path, and there is no 'dirname' method defined in the file system`
  175. );
  176. }
  177. };
  178. exports.dirname = dirname;
  179. /**
  180. * @param {OutputFileSystem} fs a file system
  181. * @param {string} p an absolute path
  182. * @param {function(Error=): void} callback callback function for the error
  183. * @returns {void}
  184. */
  185. const mkdirp = (fs, p, callback) => {
  186. fs.mkdir(p, err => {
  187. if (err) {
  188. if (err.code === "ENOENT") {
  189. const dir = dirname(fs, p);
  190. if (dir === p) {
  191. callback(err);
  192. return;
  193. }
  194. mkdirp(fs, dir, err => {
  195. if (err) {
  196. callback(err);
  197. return;
  198. }
  199. fs.mkdir(p, err => {
  200. if (err) {
  201. if (err.code === "EEXIST") {
  202. callback();
  203. return;
  204. }
  205. callback(err);
  206. return;
  207. }
  208. callback();
  209. });
  210. });
  211. return;
  212. } else if (err.code === "EEXIST") {
  213. callback();
  214. return;
  215. }
  216. callback(err);
  217. return;
  218. }
  219. callback();
  220. });
  221. };
  222. exports.mkdirp = mkdirp;
  223. /**
  224. * @param {IntermediateFileSystem} fs a file system
  225. * @param {string} p an absolute path
  226. * @returns {void}
  227. */
  228. const mkdirpSync = (fs, p) => {
  229. try {
  230. fs.mkdirSync(p);
  231. } catch (err) {
  232. if (err) {
  233. if (err.code === "ENOENT") {
  234. const dir = dirname(fs, p);
  235. if (dir === p) {
  236. throw err;
  237. }
  238. mkdirpSync(fs, dir);
  239. fs.mkdirSync(p);
  240. return;
  241. } else if (err.code === "EEXIST") {
  242. return;
  243. }
  244. throw err;
  245. }
  246. }
  247. };
  248. exports.mkdirpSync = mkdirpSync;
  249. /**
  250. * @param {InputFileSystem} fs a file system
  251. * @param {string} p an absolute path
  252. * @param {ReadJsonCallback} callback callback
  253. * @returns {void}
  254. */
  255. const readJson = (fs, p, callback) => {
  256. if ("readJson" in fs) return fs.readJson(p, callback);
  257. fs.readFile(p, (err, buf) => {
  258. if (err) return callback(err);
  259. let data;
  260. try {
  261. data = JSON.parse(buf.toString("utf-8"));
  262. } catch (e) {
  263. return callback(e);
  264. }
  265. return callback(null, data);
  266. });
  267. };
  268. exports.readJson = readJson;
  269. /**
  270. * @param {InputFileSystem} fs a file system
  271. * @param {string} p an absolute path
  272. * @param {ReadJsonCallback} callback callback
  273. * @returns {void}
  274. */
  275. const lstatReadlinkAbsolute = (fs, p, callback) => {
  276. let i = 3;
  277. const doReadLink = () => {
  278. fs.readlink(p, (err, target) => {
  279. if (err && --i > 0) {
  280. // It might was just changed from symlink to file
  281. // we retry 2 times to catch this case before throwing the error
  282. return doStat();
  283. }
  284. if (err || !target) return doStat();
  285. const value = target.toString();
  286. callback(null, join(fs, dirname(fs, p), value));
  287. });
  288. };
  289. const doStat = () => {
  290. if ("lstat" in fs) {
  291. return fs.lstat(p, (err, stats) => {
  292. if (err) return callback(err);
  293. if (stats.isSymbolicLink()) {
  294. return doReadLink();
  295. }
  296. callback(null, stats);
  297. });
  298. } else {
  299. return fs.stat(p, callback);
  300. }
  301. };
  302. if ("lstat" in fs) return doStat();
  303. doReadLink();
  304. };
  305. exports.lstatReadlinkAbsolute = lstatReadlinkAbsolute;