| 
									
										
										
										
											2019-06-11 19:09:42 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const path = require("path"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 02:09:36 +08:00
										 |  |  | /** @typedef {import("../../declarations/WebpackOptions").WatchOptions} WatchOptions */ | 
					
						
							| 
									
										
										
										
											2020-07-08 16:21:31 +08:00
										 |  |  | /** @typedef {import("../FileSystemInfo").FileSystemInfoEntry} FileSystemInfoEntry */ | 
					
						
							| 
									
										
										
										
											2020-03-21 21:01:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-13 07:09:19 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} IStats | 
					
						
							|  |  |  |  * @property {() => boolean} isFile | 
					
						
							|  |  |  |  * @property {() => boolean} isDirectory | 
					
						
							|  |  |  |  * @property {() => boolean} isBlockDevice | 
					
						
							|  |  |  |  * @property {() => boolean} isCharacterDevice | 
					
						
							|  |  |  |  * @property {() => boolean} isSymbolicLink | 
					
						
							|  |  |  |  * @property {() => boolean} isFIFO | 
					
						
							|  |  |  |  * @property {() => boolean} isSocket | 
					
						
							|  |  |  |  * @property {number | bigint} dev | 
					
						
							|  |  |  |  * @property {number | bigint} ino | 
					
						
							|  |  |  |  * @property {number | bigint} mode | 
					
						
							|  |  |  |  * @property {number | bigint} nlink | 
					
						
							|  |  |  |  * @property {number | bigint} uid | 
					
						
							|  |  |  |  * @property {number | bigint} gid | 
					
						
							|  |  |  |  * @property {number | bigint} rdev | 
					
						
							|  |  |  |  * @property {number | bigint} size | 
					
						
							|  |  |  |  * @property {number | bigint} blksize | 
					
						
							|  |  |  |  * @property {number | bigint} blocks | 
					
						
							|  |  |  |  * @property {number | bigint} atimeMs | 
					
						
							|  |  |  |  * @property {number | bigint} mtimeMs | 
					
						
							|  |  |  |  * @property {number | bigint} ctimeMs | 
					
						
							|  |  |  |  * @property {number | bigint} birthtimeMs | 
					
						
							|  |  |  |  * @property {Date} atime | 
					
						
							|  |  |  |  * @property {Date} mtime | 
					
						
							|  |  |  |  * @property {Date} ctime | 
					
						
							|  |  |  |  * @property {Date} birthtime | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} IDirent | 
					
						
							|  |  |  |  * @property {() => boolean} isFile | 
					
						
							|  |  |  |  * @property {() => boolean} isDirectory | 
					
						
							|  |  |  |  * @property {() => boolean} isBlockDevice | 
					
						
							|  |  |  |  * @property {() => boolean} isCharacterDevice | 
					
						
							|  |  |  |  * @property {() => boolean} isSymbolicLink | 
					
						
							|  |  |  |  * @property {() => boolean} isFIFO | 
					
						
							|  |  |  |  * @property {() => boolean} isSocket | 
					
						
							|  |  |  |  * @property {string | Buffer} name | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-11 19:09:42 +08:00
										 |  |  | /** @typedef {function(NodeJS.ErrnoException=): void} Callback */ | 
					
						
							|  |  |  | /** @typedef {function(NodeJS.ErrnoException=, Buffer=): void} BufferCallback */ | 
					
						
							| 
									
										
										
										
											2020-06-18 04:17:14 +08:00
										 |  |  | /** @typedef {function(NodeJS.ErrnoException=, Buffer|string=): void} BufferOrStringCallback */ | 
					
						
							| 
									
										
										
										
											2021-01-13 07:09:19 +08:00
										 |  |  | /** @typedef {function(NodeJS.ErrnoException=, (string | Buffer)[] | IDirent[]=): void} DirentArrayCallback */ | 
					
						
							| 
									
										
										
										
											2019-08-13 04:59:09 +08:00
										 |  |  | /** @typedef {function(NodeJS.ErrnoException=, string=): void} StringCallback */ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:16:20 +08:00
										 |  |  | /** @typedef {function(NodeJS.ErrnoException=, number=): void} NumberCallback */ | 
					
						
							| 
									
										
										
										
											2021-01-13 07:09:19 +08:00
										 |  |  | /** @typedef {function(NodeJS.ErrnoException=, IStats=): void} StatsCallback */ | 
					
						
							| 
									
										
										
										
											2020-06-13 20:45:37 +08:00
										 |  |  | /** @typedef {function((NodeJS.ErrnoException | Error)=, any=): void} ReadJsonCallback */ | 
					
						
							| 
									
										
										
										
											2019-06-11 19:09:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-08 16:21:31 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} Watcher | 
					
						
							|  |  |  |  * @property {function(): void} close closes the watcher and all underlying file watchers | 
					
						
							|  |  |  |  * @property {function(): void} pause closes the watcher, but keeps underlying file watchers alive until the next watch call | 
					
						
							| 
									
										
										
										
											2021-01-12 05:15:31 +08:00
										 |  |  |  * @property {function(): Map<string, FileSystemInfoEntry | "ignore">} getFileTimeInfoEntries get info about files | 
					
						
							|  |  |  |  * @property {function(): Map<string, FileSystemInfoEntry | "ignore">} getContextTimeInfoEntries get info about directories | 
					
						
							| 
									
										
										
										
											2020-07-08 16:21:31 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @callback WatchMethod | 
					
						
							|  |  |  |  * @param {Iterable<string>} files watched files | 
					
						
							|  |  |  |  * @param {Iterable<string>} directories watched directories | 
					
						
							|  |  |  |  * @param {Iterable<string>} missing watched exitance entries | 
					
						
							|  |  |  |  * @param {number} startTime timestamp of start time | 
					
						
							| 
									
										
										
										
											2020-08-03 02:09:36 +08:00
										 |  |  |  * @param {WatchOptions} options options object | 
					
						
							| 
									
										
										
										
											2021-01-12 05:15:31 +08:00
										 |  |  |  * @param {function(Error=, Map<string, FileSystemInfoEntry | "ignore">, Map<string, FileSystemInfoEntry | "ignore">, Set<string>, Set<string>): void} callback aggregated callback | 
					
						
							| 
									
										
										
										
											2020-07-08 16:21:31 +08:00
										 |  |  |  * @param {function(string, number): void} callbackUndelayed callback when the first change was detected | 
					
						
							|  |  |  |  * @returns {Watcher} a watcher | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-11 19:09:42 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} OutputFileSystem | 
					
						
							|  |  |  |  * @property {function(string, Buffer|string, Callback): void} writeFile | 
					
						
							|  |  |  |  * @property {function(string, Callback): void} mkdir | 
					
						
							| 
									
										
										
										
											2019-11-04 16:23:18 +08:00
										 |  |  |  * @property {function(string, StatsCallback): void} stat | 
					
						
							| 
									
										
										
										
											2021-01-13 07:09:19 +08:00
										 |  |  |  * @property {function(string, BufferOrStringCallback): void} readFile | 
					
						
							| 
									
										
										
										
											2019-06-11 19:09:42 +08:00
										 |  |  |  * @property {(function(string, string): string)=} join | 
					
						
							|  |  |  |  * @property {(function(string, string): string)=} relative | 
					
						
							|  |  |  |  * @property {(function(string): string)=} dirname | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} InputFileSystem | 
					
						
							| 
									
										
										
										
											2021-01-13 07:09:19 +08:00
										 |  |  |  * @property {function(string, BufferOrStringCallback): void} readFile | 
					
						
							| 
									
										
										
										
											2020-06-13 20:45:37 +08:00
										 |  |  |  * @property {(function(string, ReadJsonCallback): void)=} readJson | 
					
						
							| 
									
										
										
										
											2020-06-18 04:17:14 +08:00
										 |  |  |  * @property {function(string, BufferOrStringCallback): void} readlink | 
					
						
							| 
									
										
										
										
											2021-01-13 07:09:19 +08:00
										 |  |  |  * @property {function(string, DirentArrayCallback): void} readdir | 
					
						
							| 
									
										
										
										
											2019-06-11 19:09:42 +08:00
										 |  |  |  * @property {function(string, StatsCallback): void} stat | 
					
						
							| 
									
										
										
										
											2021-01-13 07:09:19 +08:00
										 |  |  |  * @property {(function(string, BufferOrStringCallback): void)=} realpath | 
					
						
							| 
									
										
										
										
											2019-06-11 19:09:42 +08:00
										 |  |  |  * @property {(function(string=): void)=} purge | 
					
						
							|  |  |  |  * @property {(function(string, string): string)=} join | 
					
						
							|  |  |  |  * @property {(function(string, string): string)=} relative | 
					
						
							|  |  |  |  * @property {(function(string): string)=} dirname | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-08 16:21:31 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} WatchFileSystem | 
					
						
							|  |  |  |  * @property {WatchMethod} watch | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} IntermediateFileSystemExtras | 
					
						
							|  |  |  |  * @property {function(string): void} mkdirSync | 
					
						
							| 
									
										
										
										
											2021-01-13 07:09:19 +08:00
										 |  |  |  * @property {function(string): NodeJS.WritableStream} createWriteStream | 
					
						
							| 
									
										
										
										
											2020-12-14 20:16:20 +08:00
										 |  |  |  * @property {function(string, string, NumberCallback): void} open | 
					
						
							|  |  |  |  * @property {function(number, Buffer, number, number, number, NumberCallback): void} read | 
					
						
							|  |  |  |  * @property {function(number, Callback): void} close | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  |  * @property {function(string, string, Callback): void} rename | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** @typedef {InputFileSystem & OutputFileSystem & IntermediateFileSystemExtras} IntermediateFileSystem */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-11 19:09:42 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-05-08 05:44:15 +08:00
										 |  |  |  * @param {InputFileSystem|OutputFileSystem|undefined} fs a file system | 
					
						
							| 
									
										
										
										
											2019-06-11 19:09:42 +08:00
										 |  |  |  * @param {string} rootPath the root path | 
					
						
							|  |  |  |  * @param {string} targetPath the target path | 
					
						
							|  |  |  |  * @returns {string} location of targetPath relative to rootPath | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const relative = (fs, rootPath, targetPath) => { | 
					
						
							|  |  |  | 	if (fs && fs.relative) { | 
					
						
							|  |  |  | 		return fs.relative(rootPath, targetPath); | 
					
						
							|  |  |  | 	} else if (rootPath.startsWith("/")) { | 
					
						
							|  |  |  | 		return path.posix.relative(rootPath, targetPath); | 
					
						
							|  |  |  | 	} else if (rootPath.length > 1 && rootPath[1] === ":") { | 
					
						
							|  |  |  | 		return path.win32.relative(rootPath, targetPath); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		throw new Error( | 
					
						
							|  |  |  | 			`${rootPath} is neither a posix nor a windows path, and there is no 'relative' method defined in the file system` | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | exports.relative = relative; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2020-05-08 05:44:15 +08:00
										 |  |  |  * @param {InputFileSystem|OutputFileSystem|undefined} fs a file system | 
					
						
							| 
									
										
										
										
											2019-06-11 19:09:42 +08:00
										 |  |  |  * @param {string} rootPath a path | 
					
						
							|  |  |  |  * @param {string} filename a filename | 
					
						
							|  |  |  |  * @returns {string} the joined path | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const join = (fs, rootPath, filename) => { | 
					
						
							|  |  |  | 	if (fs && fs.join) { | 
					
						
							|  |  |  | 		return fs.join(rootPath, filename); | 
					
						
							|  |  |  | 	} else if (rootPath.startsWith("/")) { | 
					
						
							|  |  |  | 		return path.posix.join(rootPath, filename); | 
					
						
							|  |  |  | 	} else if (rootPath.length > 1 && rootPath[1] === ":") { | 
					
						
							|  |  |  | 		return path.win32.join(rootPath, filename); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		throw new Error( | 
					
						
							|  |  |  | 			`${rootPath} is neither a posix nor a windows path, and there is no 'join' method defined in the file system` | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | exports.join = join; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2020-05-08 05:44:15 +08:00
										 |  |  |  * @param {InputFileSystem|OutputFileSystem|undefined} fs a file system | 
					
						
							| 
									
										
										
										
											2019-06-11 19:09:42 +08:00
										 |  |  |  * @param {string} absPath an absolute path | 
					
						
							|  |  |  |  * @returns {string} the parent directory of the absolute path | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const dirname = (fs, absPath) => { | 
					
						
							|  |  |  | 	if (fs && fs.dirname) { | 
					
						
							|  |  |  | 		return fs.dirname(absPath); | 
					
						
							|  |  |  | 	} else if (absPath.startsWith("/")) { | 
					
						
							|  |  |  | 		return path.posix.dirname(absPath); | 
					
						
							|  |  |  | 	} else if (absPath.length > 1 && absPath[1] === ":") { | 
					
						
							|  |  |  | 		return path.win32.dirname(absPath); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		throw new Error( | 
					
						
							|  |  |  | 			`${absPath} is neither a posix nor a windows path, and there is no 'dirname' method defined in the file system` | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | exports.dirname = dirname; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {OutputFileSystem} fs a file system | 
					
						
							|  |  |  |  * @param {string} p an absolute path | 
					
						
							|  |  |  |  * @param {function(Error=): void} callback callback function for the error | 
					
						
							|  |  |  |  * @returns {void} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const mkdirp = (fs, p, callback) => { | 
					
						
							|  |  |  | 	fs.mkdir(p, err => { | 
					
						
							|  |  |  | 		if (err) { | 
					
						
							|  |  |  | 			if (err.code === "ENOENT") { | 
					
						
							|  |  |  | 				const dir = dirname(fs, p); | 
					
						
							|  |  |  | 				if (dir === p) { | 
					
						
							|  |  |  | 					callback(err); | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				mkdirp(fs, dir, err => { | 
					
						
							|  |  |  | 					if (err) { | 
					
						
							|  |  |  | 						callback(err); | 
					
						
							|  |  |  | 						return; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					fs.mkdir(p, err => { | 
					
						
							|  |  |  | 						if (err) { | 
					
						
							|  |  |  | 							if (err.code === "EEXIST") { | 
					
						
							|  |  |  | 								callback(); | 
					
						
							|  |  |  | 								return; | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							callback(err); | 
					
						
							|  |  |  | 							return; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						callback(); | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} else if (err.code === "EEXIST") { | 
					
						
							|  |  |  | 				callback(); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			callback(err); | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		callback(); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | exports.mkdirp = mkdirp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {IntermediateFileSystem} fs a file system | 
					
						
							|  |  |  |  * @param {string} p an absolute path | 
					
						
							|  |  |  |  * @returns {void} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const mkdirpSync = (fs, p) => { | 
					
						
							|  |  |  | 	try { | 
					
						
							|  |  |  | 		fs.mkdirSync(p); | 
					
						
							|  |  |  | 	} catch (err) { | 
					
						
							|  |  |  | 		if (err) { | 
					
						
							|  |  |  | 			if (err.code === "ENOENT") { | 
					
						
							|  |  |  | 				const dir = dirname(fs, p); | 
					
						
							|  |  |  | 				if (dir === p) { | 
					
						
							|  |  |  | 					throw err; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				mkdirpSync(fs, dir); | 
					
						
							|  |  |  | 				fs.mkdirSync(p); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} else if (err.code === "EEXIST") { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			throw err; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | exports.mkdirpSync = mkdirpSync; | 
					
						
							| 
									
										
										
										
											2020-06-13 20:45:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {InputFileSystem} fs a file system | 
					
						
							|  |  |  |  * @param {string} p an absolute path | 
					
						
							|  |  |  |  * @param {ReadJsonCallback} callback callback | 
					
						
							|  |  |  |  * @returns {void} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const readJson = (fs, p, callback) => { | 
					
						
							|  |  |  | 	if ("readJson" in fs) return fs.readJson(p, callback); | 
					
						
							|  |  |  | 	fs.readFile(p, (err, buf) => { | 
					
						
							|  |  |  | 		if (err) return callback(err); | 
					
						
							|  |  |  | 		let data; | 
					
						
							|  |  |  | 		try { | 
					
						
							|  |  |  | 			data = JSON.parse(buf.toString("utf-8")); | 
					
						
							|  |  |  | 		} catch (e) { | 
					
						
							|  |  |  | 			return callback(e); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return callback(null, data); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | exports.readJson = readJson; |