[79a0317] | 1 | /*
|
---|
| 2 | MIT License http://www.opensource.org/licenses/mit-license.php
|
---|
| 3 | Author Tobias Koppers @sokra
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | "use strict";
|
---|
| 7 |
|
---|
| 8 | const path = require("path");
|
---|
| 9 |
|
---|
| 10 | /** @typedef {import("../../declarations/WebpackOptions").WatchOptions} WatchOptions */
|
---|
| 11 | /** @typedef {import("../FileSystemInfo").FileSystemInfoEntry} FileSystemInfoEntry */
|
---|
| 12 |
|
---|
| 13 | /**
|
---|
| 14 | * @template T
|
---|
| 15 | * @typedef {object} IStatsBase
|
---|
| 16 | * @property {() => boolean} isFile
|
---|
| 17 | * @property {() => boolean} isDirectory
|
---|
| 18 | * @property {() => boolean} isBlockDevice
|
---|
| 19 | * @property {() => boolean} isCharacterDevice
|
---|
| 20 | * @property {() => boolean} isSymbolicLink
|
---|
| 21 | * @property {() => boolean} isFIFO
|
---|
| 22 | * @property {() => boolean} isSocket
|
---|
| 23 | * @property {T} dev
|
---|
| 24 | * @property {T} ino
|
---|
| 25 | * @property {T} mode
|
---|
| 26 | * @property {T} nlink
|
---|
| 27 | * @property {T} uid
|
---|
| 28 | * @property {T} gid
|
---|
| 29 | * @property {T} rdev
|
---|
| 30 | * @property {T} size
|
---|
| 31 | * @property {T} blksize
|
---|
| 32 | * @property {T} blocks
|
---|
| 33 | * @property {T} atimeMs
|
---|
| 34 | * @property {T} mtimeMs
|
---|
| 35 | * @property {T} ctimeMs
|
---|
| 36 | * @property {T} birthtimeMs
|
---|
| 37 | * @property {Date} atime
|
---|
| 38 | * @property {Date} mtime
|
---|
| 39 | * @property {Date} ctime
|
---|
| 40 | * @property {Date} birthtime
|
---|
| 41 | */
|
---|
| 42 |
|
---|
| 43 | /**
|
---|
| 44 | * @typedef {IStatsBase<number>} IStats
|
---|
| 45 | */
|
---|
| 46 |
|
---|
| 47 | /**
|
---|
| 48 | * @typedef {IStatsBase<bigint> & { atimeNs: bigint, mtimeNs: bigint, ctimeNs: bigint, birthtimeNs: bigint }} IBigIntStats
|
---|
| 49 | */
|
---|
| 50 |
|
---|
| 51 | /**
|
---|
| 52 | * @typedef {object} Dirent
|
---|
| 53 | * @property {() => boolean} isFile
|
---|
| 54 | * @property {() => boolean} isDirectory
|
---|
| 55 | * @property {() => boolean} isBlockDevice
|
---|
| 56 | * @property {() => boolean} isCharacterDevice
|
---|
| 57 | * @property {() => boolean} isSymbolicLink
|
---|
| 58 | * @property {() => boolean} isFIFO
|
---|
| 59 | * @property {() => boolean} isSocket
|
---|
| 60 | * @property {string} name
|
---|
| 61 | * @property {string} path
|
---|
| 62 | */
|
---|
| 63 |
|
---|
| 64 | /** @typedef {string | number | boolean | null} JsonPrimitive */
|
---|
| 65 | /** @typedef {JsonValue[]} JsonArray */
|
---|
| 66 | /** @typedef {JsonPrimitive | JsonObject | JsonArray} JsonValue */
|
---|
| 67 | /** @typedef {{[Key in string]: JsonValue} & {[Key in string]?: JsonValue | undefined}} JsonObject */
|
---|
| 68 |
|
---|
| 69 | /** @typedef {function(NodeJS.ErrnoException | null): void} NoParamCallback */
|
---|
| 70 | /** @typedef {function(NodeJS.ErrnoException | null, string=): void} StringCallback */
|
---|
| 71 | /** @typedef {function(NodeJS.ErrnoException | null, Buffer=): void} BufferCallback */
|
---|
| 72 | /** @typedef {function(NodeJS.ErrnoException | null, (string | Buffer)=): void} StringOrBufferCallback */
|
---|
| 73 | /** @typedef {function(NodeJS.ErrnoException | null, (string[])=): void} ReaddirStringCallback */
|
---|
| 74 | /** @typedef {function(NodeJS.ErrnoException | null, (Buffer[])=): void} ReaddirBufferCallback */
|
---|
| 75 | /** @typedef {function(NodeJS.ErrnoException | null, (string[] | Buffer[])=): void} ReaddirStringOrBufferCallback */
|
---|
| 76 | /** @typedef {function(NodeJS.ErrnoException | null, (Dirent[])=): void} ReaddirDirentCallback */
|
---|
| 77 | /** @typedef {function(NodeJS.ErrnoException | null, IStats=): void} StatsCallback */
|
---|
| 78 | /** @typedef {function(NodeJS.ErrnoException | null, IBigIntStats=): void} BigIntStatsCallback */
|
---|
| 79 | /** @typedef {function(NodeJS.ErrnoException | null, (IStats | IBigIntStats)=): void} StatsOrBigIntStatsCallback */
|
---|
| 80 | /** @typedef {function(NodeJS.ErrnoException | null, number=): void} NumberCallback */
|
---|
| 81 | /** @typedef {function(NodeJS.ErrnoException | Error | null, JsonObject=): void} ReadJsonCallback */
|
---|
| 82 |
|
---|
| 83 | /** @typedef {Map<string, FileSystemInfoEntry | "ignore">} TimeInfoEntries */
|
---|
| 84 |
|
---|
| 85 | /**
|
---|
| 86 | * @typedef {object} WatcherInfo
|
---|
| 87 | * @property {Set<string> | null} changes get current aggregated changes that have not yet send to callback
|
---|
| 88 | * @property {Set<string> | null} removals get current aggregated removals that have not yet send to callback
|
---|
| 89 | * @property {TimeInfoEntries} fileTimeInfoEntries get info about files
|
---|
| 90 | * @property {TimeInfoEntries} contextTimeInfoEntries get info about directories
|
---|
| 91 | */
|
---|
| 92 |
|
---|
| 93 | /** @typedef {Set<string>} Changes */
|
---|
| 94 | /** @typedef {Set<string>} Removals */
|
---|
| 95 |
|
---|
| 96 | // TODO webpack 6 deprecate missing getInfo
|
---|
| 97 | /**
|
---|
| 98 | * @typedef {object} Watcher
|
---|
| 99 | * @property {function(): void} close closes the watcher and all underlying file watchers
|
---|
| 100 | * @property {function(): void} pause closes the watcher, but keeps underlying file watchers alive until the next watch call
|
---|
| 101 | * @property {(function(): Changes | null)=} getAggregatedChanges get current aggregated changes that have not yet send to callback
|
---|
| 102 | * @property {(function(): Removals | null)=} getAggregatedRemovals get current aggregated removals that have not yet send to callback
|
---|
| 103 | * @property {function(): TimeInfoEntries} getFileTimeInfoEntries get info about files
|
---|
| 104 | * @property {function(): TimeInfoEntries} getContextTimeInfoEntries get info about directories
|
---|
| 105 | * @property {function(): WatcherInfo=} getInfo get info about timestamps and changes
|
---|
| 106 | */
|
---|
| 107 |
|
---|
| 108 | /**
|
---|
| 109 | * @callback WatchMethod
|
---|
| 110 | * @param {Iterable<string>} files watched files
|
---|
| 111 | * @param {Iterable<string>} directories watched directories
|
---|
| 112 | * @param {Iterable<string>} missing watched existence entries
|
---|
| 113 | * @param {number} startTime timestamp of start time
|
---|
| 114 | * @param {WatchOptions} options options object
|
---|
| 115 | * @param {function(Error | null, TimeInfoEntries=, TimeInfoEntries=, Changes=, Removals=): void} callback aggregated callback
|
---|
| 116 | * @param {function(string, number): void} callbackUndelayed callback when the first change was detected
|
---|
| 117 | * @returns {Watcher} a watcher
|
---|
| 118 | */
|
---|
| 119 |
|
---|
| 120 | // TODO webpack 6 make optional methods required and avoid using non standard methods like `join`, `relative`, `dirname`, move IntermediateFileSystemExtras methods to InputFilesystem or OutputFilesystem
|
---|
| 121 |
|
---|
| 122 | /**
|
---|
| 123 | * @typedef {string | Buffer | URL} PathLike
|
---|
| 124 | */
|
---|
| 125 |
|
---|
| 126 | /**
|
---|
| 127 | * @typedef {PathLike | number} PathOrFileDescriptor
|
---|
| 128 | */
|
---|
| 129 |
|
---|
| 130 | /**
|
---|
| 131 | * @typedef {object} ObjectEncodingOptions
|
---|
| 132 | * @property {BufferEncoding | null | undefined} [encoding]
|
---|
| 133 | */
|
---|
| 134 |
|
---|
| 135 | /**
|
---|
| 136 | * @typedef {{
|
---|
| 137 | * (path: PathOrFileDescriptor, options: ({ encoding?: null | undefined, flag?: string | undefined } & import("events").Abortable) | undefined | null, callback: BufferCallback): void;
|
---|
| 138 | * (path: PathOrFileDescriptor, options: ({ encoding: BufferEncoding, flag?: string | undefined } & import("events").Abortable) | BufferEncoding, callback: StringCallback): void;
|
---|
| 139 | * (path: PathOrFileDescriptor, options: (ObjectEncodingOptions & { flag?: string | undefined } & import("events").Abortable) | BufferEncoding | undefined | null, callback: StringOrBufferCallback): void;
|
---|
| 140 | * (path: PathOrFileDescriptor, callback: BufferCallback): void;
|
---|
| 141 | * }} ReadFile
|
---|
| 142 | */
|
---|
| 143 |
|
---|
| 144 | /**
|
---|
| 145 | * @typedef {{
|
---|
| 146 | * (path: PathOrFileDescriptor, options?: { encoding?: null | undefined, flag?: string | undefined } | null): Buffer;
|
---|
| 147 | * (path: PathOrFileDescriptor, options: { encoding: BufferEncoding, flag?: string | undefined } | BufferEncoding): string;
|
---|
| 148 | * (path: PathOrFileDescriptor, options?: (ObjectEncodingOptions & { flag?: string | undefined }) | BufferEncoding | null): string | Buffer;
|
---|
| 149 | * }} ReadFileSync
|
---|
| 150 | */
|
---|
| 151 |
|
---|
| 152 | /**
|
---|
| 153 | * @typedef {ObjectEncodingOptions | BufferEncoding | undefined | null} EncodingOption
|
---|
| 154 | */
|
---|
| 155 |
|
---|
| 156 | /**
|
---|
| 157 | * @typedef {'buffer'| { encoding: 'buffer' }} BufferEncodingOption
|
---|
| 158 | */
|
---|
| 159 |
|
---|
| 160 | /**
|
---|
| 161 | * @typedef {object} StatOptions
|
---|
| 162 | * @property {(boolean | undefined)=} bigint
|
---|
| 163 | */
|
---|
| 164 |
|
---|
| 165 | /**
|
---|
| 166 | * @typedef {object} StatSyncOptions
|
---|
| 167 | * @property {(boolean | undefined)=} bigint
|
---|
| 168 | * @property {(boolean | undefined)=} throwIfNoEntry
|
---|
| 169 | */
|
---|
| 170 |
|
---|
| 171 | /**
|
---|
| 172 | * @typedef {{
|
---|
| 173 | * (path: PathLike, options: EncodingOption, callback: StringCallback): void;
|
---|
| 174 | * (path: PathLike, options: BufferEncodingOption, callback: BufferCallback): void;
|
---|
| 175 | * (path: PathLike, options: EncodingOption, callback: StringOrBufferCallback): void;
|
---|
| 176 | * (path: PathLike, callback: StringCallback): void;
|
---|
| 177 | * }} Readlink
|
---|
| 178 | */
|
---|
| 179 |
|
---|
| 180 | /**
|
---|
| 181 | * @typedef {{
|
---|
| 182 | * (path: PathLike, options?: EncodingOption): string;
|
---|
| 183 | * (path: PathLike, options: BufferEncodingOption): Buffer;
|
---|
| 184 | * (path: PathLike, options?: EncodingOption): string | Buffer;
|
---|
| 185 | * }} ReadlinkSync
|
---|
| 186 | */
|
---|
| 187 |
|
---|
| 188 | /**
|
---|
| 189 | * @typedef {{
|
---|
| 190 | * (path: PathLike, options: { encoding: BufferEncoding | null, withFileTypes?: false | undefined, recursive?: boolean | undefined } | BufferEncoding | undefined | null, callback: ReaddirStringCallback): void;
|
---|
| 191 | * (path: PathLike, options: { encoding: 'buffer', withFileTypes?: false | undefined, recursive?: boolean | undefined } | 'buffer', callback: ReaddirBufferCallback): void;
|
---|
| 192 | * (path: PathLike, callback: ReaddirStringCallback): void;
|
---|
| 193 | * (path: PathLike, options: (ObjectEncodingOptions & { withFileTypes?: false | undefined, recursive?: boolean | undefined }) | BufferEncoding | undefined | null, callback: ReaddirStringOrBufferCallback): void;
|
---|
| 194 | * (path: PathLike, options: ObjectEncodingOptions & { withFileTypes: true, recursive?: boolean | undefined }, callback: ReaddirDirentCallback): void;
|
---|
| 195 | * }} Readdir
|
---|
| 196 | */
|
---|
| 197 |
|
---|
| 198 | /**
|
---|
| 199 | * @typedef {{
|
---|
| 200 | * (path: PathLike, options?: { encoding: BufferEncoding | null, withFileTypes?: false | undefined, recursive?: boolean | undefined } | BufferEncoding | null): string[];
|
---|
| 201 | * (path: PathLike, options: { encoding: 'buffer', withFileTypes?: false | undefined, recursive?: boolean | undefined } | 'buffer'): Buffer[];
|
---|
| 202 | * (path: PathLike, options?: (ObjectEncodingOptions & { withFileTypes?: false | undefined, recursive?: boolean | undefined }) | BufferEncoding | null): string[] | Buffer[];
|
---|
| 203 | * (path: PathLike, options: ObjectEncodingOptions & { withFileTypes: true, recursive?: boolean | undefined }): Dirent[];
|
---|
| 204 | * }} ReaddirSync
|
---|
| 205 | */
|
---|
| 206 |
|
---|
| 207 | /**
|
---|
| 208 | * @typedef {{
|
---|
| 209 | * (path: PathLike, callback: StatsCallback): void;
|
---|
| 210 | * (path: PathLike, options: (StatOptions & { bigint?: false | undefined }) | undefined, callback: StatsCallback): void;
|
---|
| 211 | * (path: PathLike, options: StatOptions & { bigint: true }, callback: BigIntStatsCallback): void;
|
---|
| 212 | * (path: PathLike, options: StatOptions | undefined, callback: StatsOrBigIntStatsCallback): void;
|
---|
| 213 | * }} Stat
|
---|
| 214 | */
|
---|
| 215 |
|
---|
| 216 | /**
|
---|
| 217 | * @typedef {{
|
---|
| 218 | * (path: PathLike, options?: undefined): IStats;
|
---|
| 219 | * (path: PathLike, options?: StatSyncOptions & { bigint?: false | undefined, throwIfNoEntry: false }): IStats | undefined;
|
---|
| 220 | * (path: PathLike, options: StatSyncOptions & { bigint: true, throwIfNoEntry: false }): IBigIntStats | undefined;
|
---|
| 221 | * (path: PathLike, options?: StatSyncOptions & { bigint?: false | undefined }): IStats;
|
---|
| 222 | * (path: PathLike, options: StatSyncOptions & { bigint: true }): IBigIntStats;
|
---|
| 223 | * (path: PathLike, options: StatSyncOptions & { bigint: boolean, throwIfNoEntry?: false | undefined }): IStats | IBigIntStats;
|
---|
| 224 | * (path: PathLike, options?: StatSyncOptions): IStats | IBigIntStats | undefined;
|
---|
| 225 | * }} StatSync
|
---|
| 226 | */
|
---|
| 227 |
|
---|
| 228 | /**
|
---|
| 229 | * @typedef {{
|
---|
| 230 | * (path: PathLike, callback: StatsCallback): void;
|
---|
| 231 | * (path: PathLike, options: (StatOptions & { bigint?: false | undefined }) | undefined, callback: StatsCallback): void;
|
---|
| 232 | * (path: PathLike, options: StatOptions & { bigint: true }, callback: BigIntStatsCallback): void;
|
---|
| 233 | * (path: PathLike, options: StatOptions | undefined, callback: StatsOrBigIntStatsCallback): void;
|
---|
| 234 | * }} LStat
|
---|
| 235 | */
|
---|
| 236 |
|
---|
| 237 | /**
|
---|
| 238 | * @typedef {{
|
---|
| 239 | * (path: PathLike, options?: undefined): IStats;
|
---|
| 240 | * (path: PathLike, options?: StatSyncOptions & { bigint?: false | undefined, throwIfNoEntry: false }): IStats | undefined;
|
---|
| 241 | * (path: PathLike, options: StatSyncOptions & { bigint: true, throwIfNoEntry: false }): IBigIntStats | undefined;
|
---|
| 242 | * (path: PathLike, options?: StatSyncOptions & { bigint?: false | undefined }): IStats;
|
---|
| 243 | * (path: PathLike, options: StatSyncOptions & { bigint: true }): IBigIntStats;
|
---|
| 244 | * (path: PathLike, options: StatSyncOptions & { bigint: boolean, throwIfNoEntry?: false | undefined }): IStats | IBigIntStats;
|
---|
| 245 | * (path: PathLike, options?: StatSyncOptions): IStats | IBigIntStats | undefined;
|
---|
| 246 | * }} LStatSync
|
---|
| 247 | */
|
---|
| 248 |
|
---|
| 249 | /**
|
---|
| 250 | * @typedef {{
|
---|
| 251 | * (path: PathLike, options: EncodingOption, callback: StringCallback): void;
|
---|
| 252 | * (path: PathLike, options: BufferEncodingOption, callback: BufferCallback): void;
|
---|
| 253 | * (path: PathLike, options: EncodingOption, callback: StringOrBufferCallback): void;
|
---|
| 254 | * (path: PathLike, callback: StringCallback): void;
|
---|
| 255 | * }} RealPath
|
---|
| 256 | */
|
---|
| 257 |
|
---|
| 258 | /**
|
---|
| 259 | * @typedef {{
|
---|
| 260 | * (path: PathLike, options?: EncodingOption): string;
|
---|
| 261 | * (path: PathLike, options: BufferEncodingOption): Buffer;
|
---|
| 262 | * (path: PathLike, options?: EncodingOption): string | Buffer;
|
---|
| 263 | * }} RealPathSync
|
---|
| 264 | */
|
---|
| 265 |
|
---|
| 266 | /**
|
---|
| 267 | * @typedef {function(PathOrFileDescriptor, ReadJsonCallback): void} ReadJson
|
---|
| 268 | */
|
---|
| 269 |
|
---|
| 270 | /**
|
---|
| 271 | * @typedef {function(PathOrFileDescriptor): JsonObject} ReadJsonSync
|
---|
| 272 | */
|
---|
| 273 |
|
---|
| 274 | /**
|
---|
| 275 | * @typedef {function((string | string[] | Set<string>)=): void} Purge
|
---|
| 276 | */
|
---|
| 277 |
|
---|
| 278 | /**
|
---|
| 279 | * @typedef {object} InputFileSystem
|
---|
| 280 | * @property {ReadFile} readFile
|
---|
| 281 | * @property {ReadFileSync=} readFileSync
|
---|
| 282 | * @property {Readlink} readlink
|
---|
| 283 | * @property {ReadlinkSync=} readlinkSync
|
---|
| 284 | * @property {Readdir} readdir
|
---|
| 285 | * @property {ReaddirSync=} readdirSync
|
---|
| 286 | * @property {Stat} stat
|
---|
| 287 | * @property {StatSync=} statSync
|
---|
| 288 | * @property {LStat=} lstat
|
---|
| 289 | * @property {LStatSync=} lstatSync
|
---|
| 290 | * @property {RealPath=} realpath
|
---|
| 291 | * @property {RealPathSync=} realpathSync
|
---|
| 292 | * @property {ReadJson=} readJson
|
---|
| 293 | * @property {ReadJsonSync=} readJsonSync
|
---|
| 294 | * @property {Purge=} purge
|
---|
| 295 | * @property {(function(string, string): string)=} join
|
---|
| 296 | * @property {(function(string, string): string)=} relative
|
---|
| 297 | * @property {(function(string): string)=} dirname
|
---|
| 298 | */
|
---|
| 299 |
|
---|
| 300 | /**
|
---|
| 301 | * @typedef {number | string} Mode
|
---|
| 302 | */
|
---|
| 303 |
|
---|
| 304 | /**
|
---|
| 305 | * @typedef {(ObjectEncodingOptions & import("events").Abortable & { mode?: Mode | undefined, flag?: string | undefined, flush?: boolean | undefined }) | BufferEncoding | null} WriteFileOptions
|
---|
| 306 | */
|
---|
| 307 |
|
---|
| 308 | /**
|
---|
| 309 | * @typedef {{
|
---|
| 310 | * (file: PathOrFileDescriptor, data: string | NodeJS.ArrayBufferView, options: WriteFileOptions, callback: NoParamCallback): void;
|
---|
| 311 | * (file: PathOrFileDescriptor, data: string | NodeJS.ArrayBufferView, callback: NoParamCallback): void;
|
---|
| 312 | * }} WriteFile
|
---|
| 313 | */
|
---|
| 314 |
|
---|
| 315 | /**
|
---|
| 316 | * @typedef {{ recursive?: boolean | undefined, mode?: Mode | undefined }} MakeDirectoryOptions
|
---|
| 317 | */
|
---|
| 318 |
|
---|
| 319 | /**
|
---|
| 320 | * @typedef {{
|
---|
| 321 | * (file: PathLike, options: MakeDirectoryOptions & { recursive: true }, callback: StringCallback): void;
|
---|
| 322 | * (file: PathLike, options: Mode | (MakeDirectoryOptions & { recursive?: false | undefined; }) | null | undefined, callback: NoParamCallback): void;
|
---|
| 323 | * (file: PathLike, options: Mode | MakeDirectoryOptions | null | undefined, callback: StringCallback): void;
|
---|
| 324 | * (file: PathLike, callback: NoParamCallback): void;
|
---|
| 325 | * }} Mkdir
|
---|
| 326 | */
|
---|
| 327 |
|
---|
| 328 | /**
|
---|
| 329 | * @typedef {{ maxRetries?: number | undefined, recursive?: boolean | undefined, retryDelay?: number | undefined }} RmDirOptions
|
---|
| 330 | */
|
---|
| 331 |
|
---|
| 332 | /**
|
---|
| 333 | * @typedef {{
|
---|
| 334 | * (file: PathLike, callback: NoParamCallback): void;
|
---|
| 335 | * (file: PathLike, options: RmDirOptions, callback: NoParamCallback): void;
|
---|
| 336 | * }} Rmdir
|
---|
| 337 | */
|
---|
| 338 |
|
---|
| 339 | /**
|
---|
| 340 | * @typedef {function(PathLike, NoParamCallback): void} Unlink
|
---|
| 341 | */
|
---|
| 342 |
|
---|
| 343 | /**
|
---|
| 344 | * @typedef {object} OutputFileSystem
|
---|
| 345 | * @property {WriteFile} writeFile
|
---|
| 346 | * @property {Mkdir} mkdir
|
---|
| 347 | * @property {Readdir=} readdir
|
---|
| 348 | * @property {Rmdir=} rmdir
|
---|
| 349 | * @property {Unlink=} unlink
|
---|
| 350 | * @property {Stat} stat
|
---|
| 351 | * @property {LStat=} lstat
|
---|
| 352 | * @property {ReadFile} readFile
|
---|
| 353 | * @property {(function(string, string): string)=} join
|
---|
| 354 | * @property {(function(string, string): string)=} relative
|
---|
| 355 | * @property {(function(string): string)=} dirname
|
---|
| 356 | */
|
---|
| 357 |
|
---|
| 358 | /**
|
---|
| 359 | * @typedef {object} WatchFileSystem
|
---|
| 360 | * @property {WatchMethod} watch
|
---|
| 361 | */
|
---|
| 362 |
|
---|
| 363 | /**
|
---|
| 364 | * @typedef {{
|
---|
| 365 | * (path: PathLike, options: MakeDirectoryOptions & { recursive: true }): string | undefined;
|
---|
| 366 | * (path: PathLike, options?: Mode | (MakeDirectoryOptions & { recursive?: false | undefined }) | null): void;
|
---|
| 367 | * (path: PathLike, options?: Mode | MakeDirectoryOptions | null): string | undefined;
|
---|
| 368 | * }} MkdirSync
|
---|
| 369 | */
|
---|
| 370 |
|
---|
| 371 | /**
|
---|
| 372 | * @typedef {object} StreamOptions
|
---|
| 373 | * @property {(string | undefined)=} flags
|
---|
| 374 | * @property {(BufferEncoding | undefined)} encoding
|
---|
| 375 | * @property {(number | EXPECTED_ANY | undefined)=} fd
|
---|
| 376 | * @property {(number | undefined)=} mode
|
---|
| 377 | * @property {(boolean | undefined)=} autoClose
|
---|
| 378 | * @property {(boolean | undefined)=} emitClose
|
---|
| 379 | * @property {(number | undefined)=} start
|
---|
| 380 | * @property {(AbortSignal | null | undefined)=} signal
|
---|
| 381 | */
|
---|
| 382 |
|
---|
| 383 | /**
|
---|
| 384 | * @typedef {object} FSImplementation
|
---|
| 385 | * @property {((...args: EXPECTED_ANY[]) => EXPECTED_ANY)=} open
|
---|
| 386 | * @property {((...args: EXPECTED_ANY[]) => EXPECTED_ANY)=} close
|
---|
| 387 | */
|
---|
| 388 |
|
---|
| 389 | /**
|
---|
| 390 | * @typedef {FSImplementation & { write: (...args: EXPECTED_ANY[]) => EXPECTED_ANY; close?: (...args: EXPECTED_ANY[]) => EXPECTED_ANY }} CreateWriteStreamFSImplementation
|
---|
| 391 | */
|
---|
| 392 |
|
---|
| 393 | /**
|
---|
| 394 | * @typedef {StreamOptions & { fs?: CreateWriteStreamFSImplementation | null | undefined }} WriteStreamOptions
|
---|
| 395 | */
|
---|
| 396 |
|
---|
| 397 | /**
|
---|
| 398 | * @typedef {function(PathLike, (BufferEncoding | WriteStreamOptions)=): NodeJS.WritableStream} CreateWriteStream
|
---|
| 399 | */
|
---|
| 400 |
|
---|
| 401 | /**
|
---|
| 402 | * @typedef {number | string} OpenMode
|
---|
| 403 | */
|
---|
| 404 |
|
---|
| 405 | /**
|
---|
| 406 | * @typedef {{
|
---|
| 407 | * (file: PathLike, flags: OpenMode | undefined, mode: Mode | undefined | null, callback: NumberCallback): void;
|
---|
| 408 | * (file: PathLike, flags: OpenMode | undefined, callback: NumberCallback): void;
|
---|
| 409 | * (file: PathLike, callback: NumberCallback): void;
|
---|
| 410 | * }} Open
|
---|
| 411 | */
|
---|
| 412 |
|
---|
| 413 | /**
|
---|
| 414 | * @typedef {number | bigint} ReadPosition
|
---|
| 415 | */
|
---|
| 416 |
|
---|
| 417 | /**
|
---|
| 418 | * @typedef {object} ReadSyncOptions
|
---|
| 419 | * @property {(number | undefined)=} offset
|
---|
| 420 | * @property {(number | undefined)=} length
|
---|
| 421 | * @property {(ReadPosition | null | undefined)=} position
|
---|
| 422 | */
|
---|
| 423 |
|
---|
| 424 | /**
|
---|
| 425 | * @template {NodeJS.ArrayBufferView} TBuffer
|
---|
| 426 | * @typedef {object} ReadAsyncOptions
|
---|
| 427 | * @property {(number | undefined)=} offset
|
---|
| 428 | * @property {(number | undefined)=} length
|
---|
| 429 | * @property {(ReadPosition | null | undefined)=} position
|
---|
| 430 | * @property {TBuffer=} buffer
|
---|
| 431 | */
|
---|
| 432 |
|
---|
| 433 | /**
|
---|
| 434 | * @template {NodeJS.ArrayBufferView} [TBuffer=Buffer]
|
---|
| 435 | * @typedef {{
|
---|
| 436 | * (fd: number, buffer: TBuffer, offset: number, length: number, position: ReadPosition | null, callback: (err: NodeJS.ErrnoException | null, bytesRead: number, buffer: TBuffer) => void): void;
|
---|
| 437 | * (fd: number, options: ReadAsyncOptions<TBuffer>, callback: (err: NodeJS.ErrnoException | null, bytesRead: number, buffer: TBuffer) => void): void;
|
---|
| 438 | * (fd: number, callback: (err: NodeJS.ErrnoException | null, bytesRead: number, buffer: NodeJS.ArrayBufferView) => void): void;
|
---|
| 439 | * }} Read
|
---|
| 440 | */
|
---|
| 441 |
|
---|
| 442 | /** @typedef {function(number, NoParamCallback): void} Close */
|
---|
| 443 |
|
---|
| 444 | /** @typedef {function(PathLike, PathLike, NoParamCallback): void} Rename */
|
---|
| 445 |
|
---|
| 446 | /**
|
---|
| 447 | * @typedef {object} IntermediateFileSystemExtras
|
---|
| 448 | * @property {MkdirSync} mkdirSync
|
---|
| 449 | * @property {CreateWriteStream} createWriteStream
|
---|
| 450 | * @property {Open} open
|
---|
| 451 | * @property {Read} read
|
---|
| 452 | * @property {Close} close
|
---|
| 453 | * @property {Rename} rename
|
---|
| 454 | */
|
---|
| 455 |
|
---|
| 456 | /** @typedef {InputFileSystem & OutputFileSystem & IntermediateFileSystemExtras} IntermediateFileSystem */
|
---|
| 457 |
|
---|
| 458 | /**
|
---|
| 459 | * @param {InputFileSystem|OutputFileSystem|undefined} fs a file system
|
---|
| 460 | * @param {string} rootPath the root path
|
---|
| 461 | * @param {string} targetPath the target path
|
---|
| 462 | * @returns {string} location of targetPath relative to rootPath
|
---|
| 463 | */
|
---|
| 464 | const relative = (fs, rootPath, targetPath) => {
|
---|
| 465 | if (fs && fs.relative) {
|
---|
| 466 | return fs.relative(rootPath, targetPath);
|
---|
| 467 | } else if (path.posix.isAbsolute(rootPath)) {
|
---|
| 468 | return path.posix.relative(rootPath, targetPath);
|
---|
| 469 | } else if (path.win32.isAbsolute(rootPath)) {
|
---|
| 470 | return path.win32.relative(rootPath, targetPath);
|
---|
| 471 | }
|
---|
| 472 | throw new Error(
|
---|
| 473 | `${rootPath} is neither a posix nor a windows path, and there is no 'relative' method defined in the file system`
|
---|
| 474 | );
|
---|
| 475 | };
|
---|
| 476 | module.exports.relative = relative;
|
---|
| 477 |
|
---|
| 478 | /**
|
---|
| 479 | * @param {InputFileSystem|OutputFileSystem|undefined} fs a file system
|
---|
| 480 | * @param {string} rootPath a path
|
---|
| 481 | * @param {string} filename a filename
|
---|
| 482 | * @returns {string} the joined path
|
---|
| 483 | */
|
---|
| 484 | const join = (fs, rootPath, filename) => {
|
---|
| 485 | if (fs && fs.join) {
|
---|
| 486 | return fs.join(rootPath, filename);
|
---|
| 487 | } else if (path.posix.isAbsolute(rootPath)) {
|
---|
| 488 | return path.posix.join(rootPath, filename);
|
---|
| 489 | } else if (path.win32.isAbsolute(rootPath)) {
|
---|
| 490 | return path.win32.join(rootPath, filename);
|
---|
| 491 | }
|
---|
| 492 | throw new Error(
|
---|
| 493 | `${rootPath} is neither a posix nor a windows path, and there is no 'join' method defined in the file system`
|
---|
| 494 | );
|
---|
| 495 | };
|
---|
| 496 | module.exports.join = join;
|
---|
| 497 |
|
---|
| 498 | /**
|
---|
| 499 | * @param {InputFileSystem|OutputFileSystem|undefined} fs a file system
|
---|
| 500 | * @param {string} absPath an absolute path
|
---|
| 501 | * @returns {string} the parent directory of the absolute path
|
---|
| 502 | */
|
---|
| 503 | const dirname = (fs, absPath) => {
|
---|
| 504 | if (fs && fs.dirname) {
|
---|
| 505 | return fs.dirname(absPath);
|
---|
| 506 | } else if (path.posix.isAbsolute(absPath)) {
|
---|
| 507 | return path.posix.dirname(absPath);
|
---|
| 508 | } else if (path.win32.isAbsolute(absPath)) {
|
---|
| 509 | return path.win32.dirname(absPath);
|
---|
| 510 | }
|
---|
| 511 | throw new Error(
|
---|
| 512 | `${absPath} is neither a posix nor a windows path, and there is no 'dirname' method defined in the file system`
|
---|
| 513 | );
|
---|
| 514 | };
|
---|
| 515 | module.exports.dirname = dirname;
|
---|
| 516 |
|
---|
| 517 | /**
|
---|
| 518 | * @param {OutputFileSystem} fs a file system
|
---|
| 519 | * @param {string} p an absolute path
|
---|
| 520 | * @param {function(Error=): void} callback callback function for the error
|
---|
| 521 | * @returns {void}
|
---|
| 522 | */
|
---|
| 523 | const mkdirp = (fs, p, callback) => {
|
---|
| 524 | fs.mkdir(p, err => {
|
---|
| 525 | if (err) {
|
---|
| 526 | if (err.code === "ENOENT") {
|
---|
| 527 | const dir = dirname(fs, p);
|
---|
| 528 | if (dir === p) {
|
---|
| 529 | callback(err);
|
---|
| 530 | return;
|
---|
| 531 | }
|
---|
| 532 | mkdirp(fs, dir, err => {
|
---|
| 533 | if (err) {
|
---|
| 534 | callback(err);
|
---|
| 535 | return;
|
---|
| 536 | }
|
---|
| 537 | fs.mkdir(p, err => {
|
---|
| 538 | if (err) {
|
---|
| 539 | if (err.code === "EEXIST") {
|
---|
| 540 | callback();
|
---|
| 541 | return;
|
---|
| 542 | }
|
---|
| 543 | callback(err);
|
---|
| 544 | return;
|
---|
| 545 | }
|
---|
| 546 | callback();
|
---|
| 547 | });
|
---|
| 548 | });
|
---|
| 549 | return;
|
---|
| 550 | } else if (err.code === "EEXIST") {
|
---|
| 551 | callback();
|
---|
| 552 | return;
|
---|
| 553 | }
|
---|
| 554 | callback(err);
|
---|
| 555 | return;
|
---|
| 556 | }
|
---|
| 557 | callback();
|
---|
| 558 | });
|
---|
| 559 | };
|
---|
| 560 | module.exports.mkdirp = mkdirp;
|
---|
| 561 |
|
---|
| 562 | /**
|
---|
| 563 | * @param {IntermediateFileSystem} fs a file system
|
---|
| 564 | * @param {string} p an absolute path
|
---|
| 565 | * @returns {void}
|
---|
| 566 | */
|
---|
| 567 | const mkdirpSync = (fs, p) => {
|
---|
| 568 | try {
|
---|
| 569 | fs.mkdirSync(p);
|
---|
| 570 | } catch (err) {
|
---|
| 571 | if (err) {
|
---|
| 572 | if (/** @type {NodeJS.ErrnoException} */ (err).code === "ENOENT") {
|
---|
| 573 | const dir = dirname(fs, p);
|
---|
| 574 | if (dir === p) {
|
---|
| 575 | throw err;
|
---|
| 576 | }
|
---|
| 577 | mkdirpSync(fs, dir);
|
---|
| 578 | fs.mkdirSync(p);
|
---|
| 579 | return;
|
---|
| 580 | } else if (/** @type {NodeJS.ErrnoException} */ (err).code === "EEXIST") {
|
---|
| 581 | return;
|
---|
| 582 | }
|
---|
| 583 | throw err;
|
---|
| 584 | }
|
---|
| 585 | }
|
---|
| 586 | };
|
---|
| 587 | module.exports.mkdirpSync = mkdirpSync;
|
---|
| 588 |
|
---|
| 589 | /**
|
---|
| 590 | * @param {InputFileSystem} fs a file system
|
---|
| 591 | * @param {string} p an absolute path
|
---|
| 592 | * @param {ReadJsonCallback} callback callback
|
---|
| 593 | * @returns {void}
|
---|
| 594 | */
|
---|
| 595 | const readJson = (fs, p, callback) => {
|
---|
| 596 | if ("readJson" in fs)
|
---|
| 597 | return /** @type {NonNullable<InputFileSystem["readJson"]>} */ (
|
---|
| 598 | fs.readJson
|
---|
| 599 | )(p, callback);
|
---|
| 600 | fs.readFile(p, (err, buf) => {
|
---|
| 601 | if (err) return callback(err);
|
---|
| 602 | let data;
|
---|
| 603 | try {
|
---|
| 604 | data = JSON.parse(/** @type {Buffer} */ (buf).toString("utf-8"));
|
---|
| 605 | } catch (err1) {
|
---|
| 606 | return callback(/** @type {Error} */ (err1));
|
---|
| 607 | }
|
---|
| 608 | return callback(null, data);
|
---|
| 609 | });
|
---|
| 610 | };
|
---|
| 611 | module.exports.readJson = readJson;
|
---|
| 612 |
|
---|
| 613 | /**
|
---|
| 614 | * @param {InputFileSystem} fs a file system
|
---|
| 615 | * @param {string} p an absolute path
|
---|
| 616 | * @param {function(NodeJS.ErrnoException | Error | null, (IStats | string)=): void} callback callback
|
---|
| 617 | * @returns {void}
|
---|
| 618 | */
|
---|
| 619 | const lstatReadlinkAbsolute = (fs, p, callback) => {
|
---|
| 620 | let i = 3;
|
---|
| 621 | const doReadLink = () => {
|
---|
| 622 | fs.readlink(p, (err, target) => {
|
---|
| 623 | if (err && --i > 0) {
|
---|
| 624 | // It might was just changed from symlink to file
|
---|
| 625 | // we retry 2 times to catch this case before throwing the error
|
---|
| 626 | return doStat();
|
---|
| 627 | }
|
---|
| 628 | if (err) return callback(err);
|
---|
| 629 | const value = /** @type {string} */ (target).toString();
|
---|
| 630 | callback(null, join(fs, dirname(fs, p), value));
|
---|
| 631 | });
|
---|
| 632 | };
|
---|
| 633 | const doStat = () => {
|
---|
| 634 | if ("lstat" in fs) {
|
---|
| 635 | return /** @type {NonNullable<InputFileSystem["lstat"]>} */ (fs.lstat)(
|
---|
| 636 | p,
|
---|
| 637 | (err, stats) => {
|
---|
| 638 | if (err) return callback(err);
|
---|
| 639 | if (/** @type {IStats} */ (stats).isSymbolicLink()) {
|
---|
| 640 | return doReadLink();
|
---|
| 641 | }
|
---|
| 642 | callback(null, stats);
|
---|
| 643 | }
|
---|
| 644 | );
|
---|
| 645 | }
|
---|
| 646 | return fs.stat(p, callback);
|
---|
| 647 | };
|
---|
| 648 | if ("lstat" in fs) return doStat();
|
---|
| 649 | doReadLink();
|
---|
| 650 | };
|
---|
| 651 | module.exports.lstatReadlinkAbsolute = lstatReadlinkAbsolute;
|
---|