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
* @ 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
* /
/ * *
* @ typedef { Object } Dirent
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 { string } name
* @ property { string } path
2021-01-13 07:09:19 +08:00
* /
2024-03-05 21:37:51 +08:00
/** @typedef {function(NodeJS.ErrnoException | null): void} NoParamCallback */
/** @typedef {function(NodeJS.ErrnoException | null, string): void} StringCallback */
/** @typedef {function(NodeJS.ErrnoException | null, string=): void} OptionalStringCallback */
/** @typedef {function(NodeJS.ErrnoException | null, Buffer): void} BufferCallback */
/** @typedef {function(NodeJS.ErrnoException | null, string | Buffer): void} StringOrBufferCallback */
/** @typedef {function(NodeJS.ErrnoException | null, string[]): void} ReaddirStringCallback */
/** @typedef {function(NodeJS.ErrnoException | null, Buffer[]): void} ReaddirBufferCallback */
/** @typedef {function(NodeJS.ErrnoException | null, string[] | Buffer[]): void} ReaddirStringOrBufferCallback */
/** @typedef {function(NodeJS.ErrnoException | null, Dirent[]): void} ReaddirDirentCallback */
/** @typedef {function(NodeJS.ErrnoException | null, IStats): void} StatsCallback */
/** @typedef {function(NodeJS.ErrnoException | null, IBigIntStats): void} BigIntStatsCallback */
/** @typedef {function(NodeJS.ErrnoException | null, IStats | IBigIntStats): void} StatsOrBigIntStatsCallback */
/** @typedef {function(NodeJS.ErrnoException | null, number): void} NumberCallback */
2024-03-05 22:40:46 +08:00
/** @typedef {function(NodeJS.ErrnoException | Error | null, any=): void} ReadJsonCallback */
2019-06-11 19:09:42 +08:00
2021-11-25 16:27:04 +08:00
/ * *
* @ typedef { Object } WatcherInfo
* @ property { Set < string > } changes get current aggregated changes that have not yet send to callback
* @ property { Set < string > } removals get current aggregated removals that have not yet send to callback
* @ property { Map < string , FileSystemInfoEntry | "ignore" > } fileTimeInfoEntries get info about files
* @ property { Map < string , FileSystemInfoEntry | "ignore" > } contextTimeInfoEntries get info about directories
* /
// TODO webpack 6 deprecate missing getInfo
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-02-25 03:12:32 +08:00
* @ property { function ( ) : Set < string >= } getAggregatedChanges get current aggregated changes that have not yet send to callback
* @ property { function ( ) : Set < string >= } getAggregatedRemovals get current aggregated removals that have not yet send to callback
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
2021-11-25 16:27:04 +08:00
* @ property { function ( ) : 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
* @ 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
* /
2024-03-05 21:37:51 +08:00
// TODO webpack 6 make optional methods required and avoid using non standard methods like `join`, `relative`, `dirname`, move IntermediateFileSystemExtras methods to InputFilesystem and 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
* /
/ * *
* @ typedef { Object } ObjectEncodingOptions
* @ property { BufferEncoding | null | undefined } [ encoding ]
* /
/ * *
* @ 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
* /
/ * *
* @ typedef { Object } StatOptions
* @ property { ( boolean | undefined ) = } bigint
* /
/ * *
* @ typedef { Object } StatSyncOptions
* @ 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 { {
* ( path : PathLike , options : { encoding : BufferEncoding | null , withFileTypes ? : false | undefined , recursive ? : boolean | undefined } | BufferEncoding | undefined | null , callback : ReaddirStringCallback ) : void ;
* ( path : PathLike , options : { encoding : 'buffer' , withFileTypes ? : false | undefined , recursive ? : boolean | undefined } | 'buffer' , callback : ReaddirBufferCallback ) : void ;
* ( path : PathLike , callback : ReaddirStringCallback ) : void ;
* ( path : PathLike , options : ( ObjectEncodingOptions & { withFileTypes ? : false | undefined , recursive ? : boolean | undefined } ) | BufferEncoding | undefined | null , callback : ReaddirStringOrBufferCallback ) : void ;
* ( path : PathLike , options : ObjectEncodingOptions & { withFileTypes : true , recursive ? : boolean | undefined } , callback : ReaddirDirentCallback ) : void ;
* } } Readdir
* /
/ * *
* @ typedef { {
* ( path : PathLike , options ? : { encoding : BufferEncoding | null , withFileTypes ? : false | undefined , recursive ? : boolean | undefined } | BufferEncoding | null ) : string [ ] ;
* ( 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 [ ] ;
* } } 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
* /
/ * *
* @ typedef { function ( PathOrFileDescriptor , ReadJsonCallback ) : void } ReadJson
* /
/ * *
* @ typedef { function ( PathOrFileDescriptor ) : void } ReadJsonSync
* /
/ * *
* @ typedef { function ( ( string | string [ ] | Set < string > ) = ) : void } Purge
* /
/ * *
* @ typedef { Object } InputFileSystem
* @ 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
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
* /
/ * *
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 { {
* ( file : PathLike , options : MakeDirectoryOptions & { recursive : true } , callback : OptionalStringCallback ) : void ;
* ( file : PathLike , options : Mode | ( MakeDirectoryOptions & { recursive ? : false | undefined ; } ) | null | undefined , callback : NoParamCallback ) : void ;
* ( file : PathLike , options : Mode | MakeDirectoryOptions | null | undefined , callback : OptionalStringCallback ) : void ;
* ( 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
* /
/ * *
* @ typedef { function ( PathLike , NoParamCallback ) : void } Unlink
* /
/ * *
* @ typedef { Object } OutputFileSystem
* @ property { WriteFile } writeFile
* @ property { Mkdir } mkdir
* @ property { Readdir = } readdir
* @ property { Rmdir = } rmdir
* @ property { Unlink = } unlink
* @ property { Stat } stat
* @ property { LStat = } lstat
* @ property { ReadFile } 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
* /
2020-07-08 16:21:31 +08:00
/ * *
* @ typedef { Object } WatchFileSystem
* @ 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
* /
/ * *
* @ typedef { Object } StreamOptions
* @ property { ( string | undefined ) = } flags
* @ property { ( BufferEncoding | undefined ) } encoding
* @ property { ( number | any | undefined ) = } fd
* @ property { ( number | undefined ) = } mode
* @ property { ( boolean | undefined ) = } autoClose
* @ property { ( boolean | undefined ) = } emitClose
* @ property { ( number | undefined ) = } start
* @ property { ( AbortSignal | null | undefined ) = } signal
* /
/ * *
* @ typedef { Object } FSImplementation
* @ property { ( ( ... args : any [ ] ) => any ) = } open
* @ property { ( ( ... args : any [ ] ) => any ) = } close
* /
/ * *
* @ typedef { FSImplementation & { write : ( ... args : any [ ] ) => any ; close ? : ( ... args : any [ ] ) => any } } CreateWriteStreamFSImplementation
* /
/ * *
* @ typedef { StreamOptions & { fs ? : CreateWriteStreamFSImplementation | null | undefined } } WriteStreamOptions
* /
/ * *
* @ typedef { function ( PathLike , ( BufferEncoding | WriteStreamOptions ) = ) : NodeJS . WritableStream } CreateWriteStream
* /
/ * *
* @ 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
* /
/ * *
* @ typedef { Object } ReadSyncOptions
* @ property { ( number | undefined ) = } offset
* @ property { ( number | undefined ) = } length
* @ property { ( ReadPosition | null | undefined ) = } position
* /
/ * *
* @ template { NodeJS . ArrayBufferView } TBuffer
* @ typedef { Object } ReadAsyncOptions
* @ property { ( number | undefined ) = } offset
* @ property { ( number | undefined ) = } length
* @ property { ( ReadPosition | null | undefined ) = } position
* @ property { TBuffer = } buffer
* /
/ * *
* @ template { NodeJS . ArrayBufferView } [ TBuffer = Buffer ]
* @ 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
* /
/** @typedef {function(number, NoParamCallback): void} Close */
/** @typedef {function(PathLike, PathLike, NoParamCallback): void} Rename */
2019-09-04 19:34:34 +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 ) ;
} 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 ) ;
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 ) ;
} 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 ) ;
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 ) ;
} 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 ) {
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 ;
}
}
} ;
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" ) ) ;
2020-06-13 20:45:37 +08:00
} catch ( e ) {
2024-02-22 22:20:17 +08:00
return callback ( /** @type {Error} */ ( e ) ) ;
2020-06-13 20:45:37 +08:00
}
return callback ( null , data ) ;
} ) ;
} ;
exports . readJson = readJson ;
2021-08-17 14:19:01 +08:00
/ * *
* @ param { InputFileSystem } fs a file system
* @ param { string } p an absolute path
* @ param { ReadJsonCallback } callback callback
* @ 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 ( ) ;
}
if ( err || ! target ) return doStat ( ) ;
const value = target . toString ( ) ;
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
} else {
return fs . stat ( p , callback ) ;
}
} ;
if ( "lstat" in fs ) return doStat ( ) ;
doReadLink ( ) ;
} ;
exports . lstatReadlinkAbsolute = lstatReadlinkAbsolute ;