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
/ * *
2024-03-05 21:37:51 +08:00
* @ template T
2024-06-11 21:09:50 +08:00
* @ typedef { object } IStatsBase
2021-01-13 07:09:19 +08:00
* @ property { ( ) => boolean } isFile
* @ property { ( ) => boolean } isDirectory
* @ property { ( ) => boolean } isBlockDevice
* @ property { ( ) => boolean } isCharacterDevice
* @ property { ( ) => boolean } isSymbolicLink
* @ property { ( ) => boolean } isFIFO
* @ property { ( ) => boolean } isSocket
2024-03-05 21:37:51 +08:00
* @ property { T } dev
* @ property { T } ino
* @ property { T } mode
* @ property { T } nlink
* @ property { T } uid
* @ property { T } gid
* @ property { T } rdev
* @ property { T } size
* @ property { T } blksize
* @ property { T } blocks
* @ property { T } atimeMs
* @ property { T } mtimeMs
* @ property { T } ctimeMs
* @ property { T } birthtimeMs
2021-01-13 07:09:19 +08:00
* @ property { Date } atime
* @ property { Date } mtime
* @ property { Date } ctime
* @ property { Date } birthtime
* /
/ * *
2024-03-05 21:37:51 +08:00
* @ typedef { IStatsBase < number > } IStats
* /
/ * *
* @ typedef { IStatsBase < bigint > & { atimeNs : bigint , mtimeNs : bigint , ctimeNs : bigint , birthtimeNs : bigint } } IBigIntStats
* /
2025-06-24 22:43:58 +08:00
/* eslint-disable jsdoc/require-template */
2024-03-05 21:37:51 +08:00
/ * *
2025-06-24 22:43:58 +08:00
* @ template { string | Buffer } [ T = string ]
2024-06-11 21:09:50 +08:00
* @ typedef { object } Dirent
2025-06-24 22:43:58 +08:00
* @ property { ( ) => boolean } isFile true when is file , otherwise false
* @ property { ( ) => boolean } isDirectory true when is directory , otherwise false
* @ property { ( ) => boolean } isBlockDevice true when is block device , otherwise false
* @ property { ( ) => boolean } isCharacterDevice true when is character device , otherwise false
* @ property { ( ) => boolean } isSymbolicLink true when is symbolic link , otherwise false
* @ property { ( ) => boolean } isFIFO true when is FIFO , otherwise false
* @ property { ( ) => boolean } isSocket true when is socket , otherwise false
* @ property { T } name name
* @ property { string } parentPath path
* @ property { string = } path path
* /
/* eslint-enable jsdoc/require-template */
2021-01-13 07:09:19 +08:00
2024-03-06 21:40:12 +08:00
/** @typedef {string | number | boolean | null} JsonPrimitive */
/** @typedef {JsonValue[]} JsonArray */
/** @typedef {{[Key in string]: JsonValue} & {[Key in string]?: JsonValue | undefined}} JsonObject */
2025-04-04 21:38:51 +08:00
/** @typedef {JsonPrimitive | JsonObject | JsonArray} JsonValue */
2024-03-06 21:40:12 +08:00
2025-03-12 09:56:14 +08:00
/** @typedef {(err: NodeJS.ErrnoException | null) => void} NoParamCallback */
/** @typedef {(err: NodeJS.ErrnoException | null, result?: string) => void} StringCallback */
/** @typedef {(err: NodeJS.ErrnoException | null, result?: Buffer) => void} BufferCallback */
/** @typedef {(err: NodeJS.ErrnoException | null, result?: string | Buffer) => void} StringOrBufferCallback */
/** @typedef {(err: NodeJS.ErrnoException | null, result?: string[]) => void} ReaddirStringCallback */
/** @typedef {(err: NodeJS.ErrnoException | null, result?: Buffer[]) => void} ReaddirBufferCallback */
/** @typedef {(err: NodeJS.ErrnoException | null, result?: string[] | Buffer[]) => void} ReaddirStringOrBufferCallback */
/** @typedef {(err: NodeJS.ErrnoException | null, result?: Dirent[]) => void} ReaddirDirentCallback */
2025-06-24 22:43:58 +08:00
/** @typedef {(err: NodeJS.ErrnoException | null, result?: Dirent<Buffer>[]) => void} ReaddirDirentBufferCallback */
2025-03-12 09:56:14 +08:00
/** @typedef {(err: NodeJS.ErrnoException | null, result?: IStats) => void} StatsCallback */
/** @typedef {(err: NodeJS.ErrnoException | null, result?: IBigIntStats) => void} BigIntStatsCallback */
/** @typedef {(err: NodeJS.ErrnoException | null, result?: IStats | IBigIntStats) => void} StatsOrBigIntStatsCallback */
/** @typedef {(err: NodeJS.ErrnoException | null, result?: number) => void} NumberCallback */
/** @typedef {(err: NodeJS.ErrnoException | Error | null, result?: JsonObject) => void} ReadJsonCallback */
2019-06-11 19:09:42 +08:00
2024-08-09 01:03:17 +08:00
/** @typedef {Map<string, FileSystemInfoEntry | "ignore">} TimeInfoEntries */
2021-11-25 16:27:04 +08:00
/ * *
2024-06-11 21:09:50 +08:00
* @ typedef { object } WatcherInfo
2024-10-02 05:18:10 +08:00
* @ property { Set < string > | null } changes get current aggregated changes that have not yet send to callback
* @ property { Set < string > | null } removals get current aggregated removals that have not yet send to callback
2024-08-09 01:03:17 +08:00
* @ property { TimeInfoEntries } fileTimeInfoEntries get info about files
* @ property { TimeInfoEntries } contextTimeInfoEntries get info about directories
2021-11-25 16:27:04 +08:00
* /
2024-08-09 01:03:17 +08:00
/** @typedef {Set<string>} Changes */
/** @typedef {Set<string>} Removals */
2021-11-25 16:27:04 +08:00
// TODO webpack 6 deprecate missing getInfo
2020-07-08 16:21:31 +08:00
/ * *
2024-06-11 21:09:50 +08:00
* @ typedef { object } Watcher
2025-03-12 09:56:14 +08:00
* @ property { ( ) => void } close closes the watcher and all underlying file watchers
* @ property { ( ) => void } pause closes the watcher , but keeps underlying file watchers alive until the next watch call
* @ property { ( ( ) => Changes | null ) = } getAggregatedChanges get current aggregated changes that have not yet send to callback
* @ property { ( ( ) => Removals | null ) = } getAggregatedRemovals get current aggregated removals that have not yet send to callback
* @ property { ( ) => TimeInfoEntries } getFileTimeInfoEntries get info about files
* @ property { ( ) => TimeInfoEntries } getContextTimeInfoEntries get info about directories
* @ property { ( ) => WatcherInfo = } getInfo get info about timestamps and changes
2020-07-08 16:21:31 +08:00
* /
/ * *
* @ callback WatchMethod
* @ param { Iterable < string > } files watched files
* @ param { Iterable < string > } directories watched directories
2024-02-20 00:46:07 +08:00
* @ param { Iterable < string > } missing watched existence entries
2020-07-08 16:21:31 +08:00
* @ param { number } startTime timestamp of start time
2020-08-03 02:09:36 +08:00
* @ param { WatchOptions } options options object
2025-03-12 10:07:44 +08:00
* @ param { ( err : Error | null , timeInfoEntries1 ? : TimeInfoEntries , timeInfoEntries2 ? : TimeInfoEntries , changes ? : Changes , removals ? : Removals ) => void } callback aggregated callback
2025-03-12 09:56:14 +08:00
* @ param { ( value : string , num : number ) => void } callbackUndelayed callback when the first change was detected
2020-07-08 16:21:31 +08:00
* @ returns { Watcher } a watcher
* /
2024-03-11 22:06:28 +08:00
// TODO webpack 6 make optional methods required and avoid using non standard methods like `join`, `relative`, `dirname`, move IntermediateFileSystemExtras methods to InputFilesystem or OutputFilesystem
2021-10-19 01:23:29 +08:00
2019-06-11 19:09:42 +08:00
/ * *
2024-03-05 21:37:51 +08:00
* @ typedef { string | Buffer | URL } PathLike
* /
/ * *
* @ typedef { PathLike | number } PathOrFileDescriptor
* /
/ * *
2024-06-11 21:09:50 +08:00
* @ typedef { object } ObjectEncodingOptions
2025-04-16 22:04:11 +08:00
* @ property { BufferEncoding | null | undefined = } encoding
2024-03-05 21:37:51 +08:00
* /
/ * *
* @ typedef { {
* ( path : PathOrFileDescriptor , options : ( { encoding ? : null | undefined , flag ? : string | undefined } & import ( "events" ) . Abortable ) | undefined | null , callback : BufferCallback ) : void ;
* ( path : PathOrFileDescriptor , options : ( { encoding : BufferEncoding , flag ? : string | undefined } & import ( "events" ) . Abortable ) | BufferEncoding , callback : StringCallback ) : void ;
* ( path : PathOrFileDescriptor , options : ( ObjectEncodingOptions & { flag ? : string | undefined } & import ( "events" ) . Abortable ) | BufferEncoding | undefined | null , callback : StringOrBufferCallback ) : void ;
2024-03-05 22:40:46 +08:00
* ( path : PathOrFileDescriptor , callback : BufferCallback ) : void ;
2024-03-05 21:37:51 +08:00
* } } ReadFile
* /
/ * *
* @ typedef { {
* ( path : PathOrFileDescriptor , options ? : { encoding ? : null | undefined , flag ? : string | undefined } | null ) : Buffer ;
* ( path : PathOrFileDescriptor , options : { encoding : BufferEncoding , flag ? : string | undefined } | BufferEncoding ) : string ;
* ( path : PathOrFileDescriptor , options ? : ( ObjectEncodingOptions & { flag ? : string | undefined } ) | BufferEncoding | null ) : string | Buffer ;
* } } ReadFileSync
* /
/ * *
* @ typedef { ObjectEncodingOptions | BufferEncoding | undefined | null } EncodingOption
* /
/ * *
* @ typedef { 'buffer' | { encoding : 'buffer' } } BufferEncodingOption
* /
/ * *
2024-06-11 21:09:50 +08:00
* @ typedef { object } StatOptions
2024-03-05 21:37:51 +08:00
* @ property { ( boolean | undefined ) = } bigint
* /
/ * *
2024-06-11 21:09:50 +08:00
* @ typedef { object } StatSyncOptions
2024-03-05 21:37:51 +08:00
* @ property { ( boolean | undefined ) = } bigint
* @ property { ( boolean | undefined ) = } throwIfNoEntry
* /
/ * *
* @ typedef { {
* ( path : PathLike , options : EncodingOption , callback : StringCallback ) : void ;
* ( path : PathLike , options : BufferEncodingOption , callback : BufferCallback ) : void ;
* ( path : PathLike , options : EncodingOption , callback : StringOrBufferCallback ) : void ;
2024-03-05 22:40:46 +08:00
* ( path : PathLike , callback : StringCallback ) : void ;
2024-03-05 21:37:51 +08:00
* } } Readlink
* /
/ * *
* @ typedef { {
* ( path : PathLike , options ? : EncodingOption ) : string ;
* ( path : PathLike , options : BufferEncodingOption ) : Buffer ;
* ( path : PathLike , options ? : EncodingOption ) : string | Buffer ;
* } } ReadlinkSync
* /
/ * *
* @ typedef { {
2025-06-24 22:43:58 +08:00
* ( path : PathLike , options : { encoding : BufferEncoding | null , withFileTypes ? : false | undefined , recursive ? : boolean | undefined } | BufferEncoding | undefined | null , callback : ( err : NodeJS . ErrnoException | null , files ? : string [ ] ) => void ) : void ;
* ( path : PathLike , options : { encoding : 'buffer' , withFileTypes ? : false | undefined , recursive ? : boolean | undefined } | 'buffer' , callback : ( err : NodeJS . ErrnoException | null , files ? : Buffer [ ] ) => void ) : void ;
* ( path : PathLike , options : ( ObjectEncodingOptions & { withFileTypes ? : false | undefined , recursive ? : boolean | undefined } ) | BufferEncoding | undefined | null , callback : ( err : NodeJS . ErrnoException | null , files ? : string [ ] | Buffer [ ] ) => void ) : void ;
* ( path : PathLike , callback : ( err : NodeJS . ErrnoException | null , files ? : string [ ] ) => void ) : void ;
* ( path : PathLike , options : ObjectEncodingOptions & { withFileTypes : true , recursive ? : boolean | undefined } , callback : ( err : NodeJS . ErrnoException | null , files ? : Dirent < string > [ ] ) => void ) : void ;
* ( path : PathLike , options : { encoding : 'buffer' , withFileTypes : true , recursive ? : boolean | undefined } , callback : ( err : NodeJS . ErrnoException | null , files : Dirent < Buffer > [ ] ) => void ) : void ;
2024-03-05 21:37:51 +08:00
* } } Readdir
* /
/ * *
* @ typedef { {
2025-06-24 22:43:58 +08:00
* ( path : PathLike , options ? : { encoding : BufferEncoding | null , withFileTypes ? : false | undefined , recursive ? : boolean | undefined ; } | BufferEncoding | null ) : string [ ] ;
2024-03-05 21:37:51 +08:00
* ( path : PathLike , options : { encoding : 'buffer' , withFileTypes ? : false | undefined , recursive ? : boolean | undefined } | 'buffer' ) : Buffer [ ] ;
* ( path : PathLike , options ? : ( ObjectEncodingOptions & { withFileTypes ? : false | undefined , recursive ? : boolean | undefined } ) | BufferEncoding | null ) : string [ ] | Buffer [ ] ;
* ( path : PathLike , options : ObjectEncodingOptions & { withFileTypes : true , recursive ? : boolean | undefined } ) : Dirent [ ] ;
2025-06-24 22:43:58 +08:00
* ( path : PathLike , options : { encoding : "buffer" , withFileTypes : true , recursive ? : boolean | undefined } ) : Dirent < Buffer > [ ] ;
2024-03-05 21:37:51 +08:00
* } } ReaddirSync
* /
/ * *
* @ typedef { {
* ( path : PathLike , callback : StatsCallback ) : void ;
* ( path : PathLike , options : ( StatOptions & { bigint ? : false | undefined } ) | undefined , callback : StatsCallback ) : void ;
* ( path : PathLike , options : StatOptions & { bigint : true } , callback : BigIntStatsCallback ) : void ;
* ( path : PathLike , options : StatOptions | undefined , callback : StatsOrBigIntStatsCallback ) : void ;
* } } Stat
* /
/ * *
* @ typedef { {
* ( path : PathLike , options ? : undefined ) : IStats ;
* ( path : PathLike , options ? : StatSyncOptions & { bigint ? : false | undefined , throwIfNoEntry : false } ) : IStats | undefined ;
* ( path : PathLike , options : StatSyncOptions & { bigint : true , throwIfNoEntry : false } ) : IBigIntStats | undefined ;
* ( path : PathLike , options ? : StatSyncOptions & { bigint ? : false | undefined } ) : IStats ;
* ( path : PathLike , options : StatSyncOptions & { bigint : true } ) : IBigIntStats ;
* ( path : PathLike , options : StatSyncOptions & { bigint : boolean , throwIfNoEntry ? : false | undefined } ) : IStats | IBigIntStats ;
* ( path : PathLike , options ? : StatSyncOptions ) : IStats | IBigIntStats | undefined ;
* } } StatSync
* /
/ * *
* @ typedef { {
* ( path : PathLike , callback : StatsCallback ) : void ;
* ( path : PathLike , options : ( StatOptions & { bigint ? : false | undefined } ) | undefined , callback : StatsCallback ) : void ;
* ( path : PathLike , options : StatOptions & { bigint : true } , callback : BigIntStatsCallback ) : void ;
* ( path : PathLike , options : StatOptions | undefined , callback : StatsOrBigIntStatsCallback ) : void ;
* } } LStat
* /
/ * *
* @ typedef { {
* ( path : PathLike , options ? : undefined ) : IStats ;
* ( path : PathLike , options ? : StatSyncOptions & { bigint ? : false | undefined , throwIfNoEntry : false } ) : IStats | undefined ;
* ( path : PathLike , options : StatSyncOptions & { bigint : true , throwIfNoEntry : false } ) : IBigIntStats | undefined ;
* ( path : PathLike , options ? : StatSyncOptions & { bigint ? : false | undefined } ) : IStats ;
* ( path : PathLike , options : StatSyncOptions & { bigint : true } ) : IBigIntStats ;
* ( path : PathLike , options : StatSyncOptions & { bigint : boolean , throwIfNoEntry ? : false | undefined } ) : IStats | IBigIntStats ;
* ( path : PathLike , options ? : StatSyncOptions ) : IStats | IBigIntStats | undefined ;
* } } LStatSync
* /
/ * *
* @ typedef { {
* ( path : PathLike , options : EncodingOption , callback : StringCallback ) : void ;
* ( path : PathLike , options : BufferEncodingOption , callback : BufferCallback ) : void ;
* ( path : PathLike , options : EncodingOption , callback : StringOrBufferCallback ) : void ;
* ( path : PathLike , callback : StringCallback ) : void ;
* } } RealPath
* /
/ * *
* @ typedef { {
* ( path : PathLike , options ? : EncodingOption ) : string ;
* ( path : PathLike , options : BufferEncodingOption ) : Buffer ;
* ( path : PathLike , options ? : EncodingOption ) : string | Buffer ;
* } } RealPathSync
* /
/ * *
2025-03-12 09:56:14 +08:00
* @ typedef { ( pathOrFileDescriptor : PathOrFileDescriptor , callback : ReadJsonCallback ) => void } ReadJson
2024-03-05 21:37:51 +08:00
* /
/ * *
2025-03-12 09:56:14 +08:00
* @ typedef { ( pathOrFileDescriptor : PathOrFileDescriptor ) => JsonObject } ReadJsonSync
2024-03-05 21:37:51 +08:00
* /
/ * *
2025-03-12 09:56:14 +08:00
* @ typedef { ( value ? : string | string [ ] | Set < string > ) => void } Purge
2024-03-05 21:37:51 +08:00
* /
/ * *
2024-06-11 21:09:50 +08:00
* @ typedef { object } InputFileSystem
2024-03-05 21:37:51 +08:00
* @ property { ReadFile } readFile
* @ property { ReadFileSync = } readFileSync
* @ property { Readlink } readlink
* @ property { ReadlinkSync = } readlinkSync
* @ property { Readdir } readdir
* @ property { ReaddirSync = } readdirSync
* @ property { Stat } stat
* @ property { StatSync = } statSync
* @ property { LStat = } lstat
* @ property { LStatSync = } lstatSync
* @ property { RealPath = } realpath
* @ property { RealPathSync = } realpathSync
* @ property { ReadJson = } readJson
* @ property { ReadJsonSync = } readJsonSync
* @ property { Purge = } purge
2025-03-12 09:56:14 +08:00
* @ property { ( ( path1 : string , path2 : string ) => string ) = } join
* @ property { ( ( from : string , to : string ) => string ) = } relative
* @ property { ( ( dirname : string ) => string ) = } dirname
2019-06-11 19:09:42 +08:00
* /
/ * *
2024-03-05 21:37:51 +08:00
* @ typedef { number | string } Mode
* /
/ * *
* @ typedef { ( ObjectEncodingOptions & import ( "events" ) . Abortable & { mode ? : Mode | undefined , flag ? : string | undefined , flush ? : boolean | undefined } ) | BufferEncoding | null } WriteFileOptions
* /
/ * *
* @ typedef { {
* ( file : PathOrFileDescriptor , data : string | NodeJS . ArrayBufferView , options : WriteFileOptions , callback : NoParamCallback ) : void ;
* ( file : PathOrFileDescriptor , data : string | NodeJS . ArrayBufferView , callback : NoParamCallback ) : void ;
* } } WriteFile
* /
/ * *
* @ typedef { { recursive ? : boolean | undefined , mode ? : Mode | undefined } } MakeDirectoryOptions
* /
/ * *
* @ typedef { {
2024-03-11 22:06:28 +08:00
* ( file : PathLike , options : MakeDirectoryOptions & { recursive : true } , callback : StringCallback ) : void ;
2024-03-05 21:37:51 +08:00
* ( file : PathLike , options : Mode | ( MakeDirectoryOptions & { recursive ? : false | undefined ; } ) | null | undefined , callback : NoParamCallback ) : void ;
2024-03-11 22:06:28 +08:00
* ( file : PathLike , options : Mode | MakeDirectoryOptions | null | undefined , callback : StringCallback ) : void ;
2024-03-05 21:37:51 +08:00
* ( file : PathLike , callback : NoParamCallback ) : void ;
* } } Mkdir
* /
/ * *
* @ typedef { { maxRetries ? : number | undefined , recursive ? : boolean | undefined , retryDelay ? : number | undefined } } RmDirOptions
* /
/ * *
* @ typedef { {
* ( file : PathLike , callback : NoParamCallback ) : void ;
* ( file : PathLike , options : RmDirOptions , callback : NoParamCallback ) : void ;
* } } Rmdir
* /
/ * *
2025-03-12 09:56:14 +08:00
* @ typedef { ( pathLike : PathLike , callback : NoParamCallback ) => void } Unlink
2024-03-05 21:37:51 +08:00
* /
/ * *
2024-06-11 21:09:50 +08:00
* @ typedef { object } OutputFileSystem
2024-03-05 21:37:51 +08:00
* @ property { WriteFile } writeFile
* @ property { Mkdir } mkdir
* @ property { Readdir = } readdir
* @ property { Rmdir = } rmdir
* @ property { Unlink = } unlink
* @ property { Stat } stat
* @ property { LStat = } lstat
* @ property { ReadFile } readFile
2025-03-12 09:56:14 +08:00
* @ property { ( ( path1 : string , path2 : string ) => string ) = } join
* @ property { ( ( from : string , to : string ) => string ) = } relative
* @ property { ( ( dirname : string ) => string ) = } dirname
2019-06-11 19:09:42 +08:00
* /
2020-07-08 16:21:31 +08:00
/ * *
2024-06-11 21:09:50 +08:00
* @ typedef { object } WatchFileSystem
2020-07-08 16:21:31 +08:00
* @ property { WatchMethod } watch
* /
2024-03-05 21:37:51 +08:00
/ * *
* @ typedef { {
* ( path : PathLike , options : MakeDirectoryOptions & { recursive : true } ) : string | undefined ;
* ( path : PathLike , options ? : Mode | ( MakeDirectoryOptions & { recursive ? : false | undefined } ) | null ) : void ;
* ( path : PathLike , options ? : Mode | MakeDirectoryOptions | null ) : string | undefined ;
* } } MkdirSync
* /
/ * *
2024-06-11 21:09:50 +08:00
* @ typedef { object } StreamOptions
2024-03-05 21:37:51 +08:00
* @ property { ( string | undefined ) = } flags
* @ property { ( BufferEncoding | undefined ) } encoding
2024-10-25 02:13:59 +08:00
* @ property { ( number | EXPECTED _ANY | undefined ) = } fd
2024-03-05 21:37:51 +08:00
* @ property { ( number | undefined ) = } mode
* @ property { ( boolean | undefined ) = } autoClose
* @ property { ( boolean | undefined ) = } emitClose
* @ property { ( number | undefined ) = } start
* @ property { ( AbortSignal | null | undefined ) = } signal
* /
/ * *
2024-06-11 21:09:50 +08:00
* @ typedef { object } FSImplementation
2024-10-25 02:13:59 +08:00
* @ property { ( ( ... args : EXPECTED _ANY [ ] ) => EXPECTED _ANY ) = } open
* @ property { ( ( ... args : EXPECTED _ANY [ ] ) => EXPECTED _ANY ) = } close
2024-03-05 21:37:51 +08:00
* /
/ * *
2024-10-25 02:13:59 +08:00
* @ typedef { FSImplementation & { write : ( ... args : EXPECTED _ANY [ ] ) => EXPECTED _ANY ; close ? : ( ... args : EXPECTED _ANY [ ] ) => EXPECTED _ANY } } CreateWriteStreamFSImplementation
2024-03-05 21:37:51 +08:00
* /
/ * *
* @ typedef { StreamOptions & { fs ? : CreateWriteStreamFSImplementation | null | undefined } } WriteStreamOptions
* /
/ * *
2025-03-12 09:56:14 +08:00
* @ typedef { ( pathLike : PathLike , result ? : BufferEncoding | WriteStreamOptions ) => NodeJS . WritableStream } CreateWriteStream
2024-03-05 21:37:51 +08:00
* /
/ * *
* @ typedef { number | string } OpenMode
* /
/ * *
* @ typedef { {
* ( file : PathLike , flags : OpenMode | undefined , mode : Mode | undefined | null , callback : NumberCallback ) : void ;
* ( file : PathLike , flags : OpenMode | undefined , callback : NumberCallback ) : void ;
* ( file : PathLike , callback : NumberCallback ) : void ;
* } } Open
* /
/ * *
* @ typedef { number | bigint } ReadPosition
* /
/ * *
2024-06-11 21:09:50 +08:00
* @ typedef { object } ReadSyncOptions
2024-03-05 21:37:51 +08:00
* @ property { ( number | undefined ) = } offset
* @ property { ( number | undefined ) = } length
* @ property { ( ReadPosition | null | undefined ) = } position
* /
/ * *
* @ template { NodeJS . ArrayBufferView } TBuffer
2024-06-11 21:09:50 +08:00
* @ typedef { object } ReadAsyncOptions
2024-03-05 21:37:51 +08:00
* @ property { ( number | undefined ) = } offset
* @ property { ( number | undefined ) = } length
* @ property { ( ReadPosition | null | undefined ) = } position
* @ property { TBuffer = } buffer
* /
/ * *
2025-03-11 10:34:56 +08:00
* @ template { NodeJS . ArrayBufferView } [ TBuffer = NodeJS . ArrayBufferView ]
2024-03-05 21:37:51 +08:00
* @ typedef { {
* ( fd : number , buffer : TBuffer , offset : number , length : number , position : ReadPosition | null , callback : ( err : NodeJS . ErrnoException | null , bytesRead : number , buffer : TBuffer ) => void ) : void ;
* ( fd : number , options : ReadAsyncOptions < TBuffer > , callback : ( err : NodeJS . ErrnoException | null , bytesRead : number , buffer : TBuffer ) => void ) : void ;
* ( fd : number , callback : ( err : NodeJS . ErrnoException | null , bytesRead : number , buffer : NodeJS . ArrayBufferView ) => void ) : void ;
* } } Read
* /
2025-03-12 09:56:14 +08:00
/** @typedef {(df: number, callback: NoParamCallback) => void} Close */
2024-03-05 21:37:51 +08:00
2025-03-12 09:56:14 +08:00
/** @typedef {(a: PathLike, b: PathLike, callback: NoParamCallback) => void} Rename */
2024-03-05 21:37:51 +08:00
2019-09-04 19:34:34 +08:00
/ * *
2024-06-11 21:09:50 +08:00
* @ typedef { object } IntermediateFileSystemExtras
2024-03-05 21:37:51 +08:00
* @ property { MkdirSync } mkdirSync
* @ property { CreateWriteStream } createWriteStream
* @ property { Open } open
* @ property { Read } read
* @ property { Close } close
* @ property { Rename } 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 ) ;
2021-02-23 01:30:45 +08:00
} else if ( path . posix . isAbsolute ( rootPath ) ) {
2019-06-11 19:09:42 +08:00
return path . posix . relative ( rootPath , targetPath ) ;
2021-02-23 01:30:45 +08:00
} else if ( path . win32 . isAbsolute ( rootPath ) ) {
2019-06-11 19:09:42 +08:00
return path . win32 . relative ( rootPath , targetPath ) ;
}
2024-07-31 04:21:27 +08:00
throw new Error (
` ${ rootPath } is neither a posix nor a windows path, and there is no 'relative' method defined in the file system `
) ;
2019-06-11 19:09:42 +08:00
} ;
2024-07-31 04:54:55 +08:00
module . exports . relative = relative ;
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 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 ) ;
2021-02-23 01:30:45 +08:00
} else if ( path . posix . isAbsolute ( rootPath ) ) {
2019-06-11 19:09:42 +08:00
return path . posix . join ( rootPath , filename ) ;
2021-02-23 01:30:45 +08:00
} else if ( path . win32 . isAbsolute ( rootPath ) ) {
2019-06-11 19:09:42 +08:00
return path . win32 . join ( rootPath , filename ) ;
}
2024-07-31 04:21:27 +08:00
throw new Error (
` ${ rootPath } is neither a posix nor a windows path, and there is no 'join' method defined in the file system `
) ;
2019-06-11 19:09:42 +08:00
} ;
2024-07-31 04:54:55 +08:00
module . exports . join = join ;
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 } 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 ) ;
2021-02-23 01:30:45 +08:00
} else if ( path . posix . isAbsolute ( absPath ) ) {
2019-06-11 19:09:42 +08:00
return path . posix . dirname ( absPath ) ;
2021-02-23 01:30:45 +08:00
} else if ( path . win32 . isAbsolute ( absPath ) ) {
2019-06-11 19:09:42 +08:00
return path . win32 . dirname ( absPath ) ;
}
2024-07-31 04:21:27 +08:00
throw new Error (
` ${ absPath } is neither a posix nor a windows path, and there is no 'dirname' method defined in the file system `
) ;
2019-06-11 19:09:42 +08:00
} ;
2024-07-31 04:54:55 +08:00
module . exports . dirname = dirname ;
2019-06-11 19:09:42 +08:00
/ * *
* @ param { OutputFileSystem } fs a file system
* @ param { string } p an absolute path
2025-03-12 09:56:14 +08:00
* @ param { ( err ? : Error ) => void } callback callback function for the error
2019-06-11 19:09:42 +08:00
* @ 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 ( ) ;
} ) ;
} ;
2024-07-31 04:54:55 +08:00
module . exports . mkdirp = mkdirp ;
2019-06-11 19:09:42 +08:00
/ * *
* @ 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 ) {
2024-03-05 22:40:46 +08:00
if ( /** @type {NodeJS.ErrnoException} */ ( err ) . code === "ENOENT" ) {
2019-06-11 19:09:42 +08:00
const dir = dirname ( fs , p ) ;
if ( dir === p ) {
throw err ;
}
mkdirpSync ( fs , dir ) ;
fs . mkdirSync ( p ) ;
return ;
2024-03-05 22:40:46 +08:00
} else if ( /** @type {NodeJS.ErrnoException} */ ( err ) . code === "EEXIST" ) {
2019-06-11 19:09:42 +08:00
return ;
}
throw err ;
}
}
} ;
2024-07-31 04:54:55 +08:00
module . 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 ) => {
2024-02-22 22:20:17 +08:00
if ( "readJson" in fs )
return /** @type {NonNullable<InputFileSystem["readJson"]>} */ (
fs . readJson
) ( p , callback ) ;
2020-06-13 20:45:37 +08:00
fs . readFile ( p , ( err , buf ) => {
if ( err ) return callback ( err ) ;
let data ;
try {
2024-02-22 22:20:17 +08:00
data = JSON . parse ( /** @type {Buffer} */ ( buf ) . toString ( "utf-8" ) ) ;
2024-07-31 15:37:05 +08:00
} catch ( err1 ) {
return callback ( /** @type {Error} */ ( err1 ) ) ;
2020-06-13 20:45:37 +08:00
}
return callback ( null , data ) ;
} ) ;
} ;
2024-07-31 04:54:55 +08:00
module . exports . readJson = readJson ;
2021-08-17 14:19:01 +08:00
/ * *
* @ param { InputFileSystem } fs a file system
* @ param { string } p an absolute path
2025-03-12 09:56:14 +08:00
* @ param { ( err : NodeJS . ErrnoException | Error | null , stats ? : IStats | string ) => void } callback callback
2021-08-17 14:19:01 +08:00
* @ returns { void }
* /
const lstatReadlinkAbsolute = ( fs , p , callback ) => {
let i = 3 ;
const doReadLink = ( ) => {
fs . readlink ( p , ( err , target ) => {
if ( err && -- i > 0 ) {
// It might was just changed from symlink to file
// we retry 2 times to catch this case before throwing the error
return doStat ( ) ;
}
2024-08-22 23:31:35 +08:00
if ( err ) return callback ( err ) ;
2024-10-02 05:18:10 +08:00
const value = /** @type {string} */ ( target ) . toString ( ) ;
2021-08-17 14:19:01 +08:00
callback ( null , join ( fs , dirname ( fs , p ) , value ) ) ;
} ) ;
} ;
const doStat = ( ) => {
if ( "lstat" in fs ) {
2024-02-22 22:20:17 +08:00
return /** @type {NonNullable<InputFileSystem["lstat"]>} */ ( fs . lstat ) (
p ,
( err , stats ) => {
if ( err ) return callback ( err ) ;
if ( /** @type {IStats} */ ( stats ) . isSymbolicLink ( ) ) {
return doReadLink ( ) ;
}
callback ( null , stats ) ;
2021-08-17 14:19:01 +08:00
}
2024-02-22 22:20:17 +08:00
) ;
2021-08-17 14:19:01 +08:00
}
2024-07-31 04:21:27 +08:00
return fs . stat ( p , callback ) ;
2021-08-17 14:19:01 +08:00
} ;
if ( "lstat" in fs ) return doStat ( ) ;
doReadLink ( ) ;
} ;
2024-07-31 04:54:55 +08:00
module . exports . lstatReadlinkAbsolute = lstatReadlinkAbsolute ;