import * as nodeJsPath from 'path' ; import * as fs from 'fs' ; import * as fsx from 'fs-extra' ; import { Text , NewlineKind , Encoding } from './Text' ; import { PosixModeBits } from './PosixModeBits' ; import { LegacyAdapters } from './LegacyAdapters' ; remarks This avoids the need to import the `fs` package when using the  FileSystem API.
 *  public export type FileSystemStats = fs . Stats ; remarks This avoids the need to import the `fs` package when using the  FileSystem API.
 *  public export type FolderItem = fs . Dirent ; /**
 * The options for  FileSystem . readFolder public export interface IFileSystemReadFolderOptions { defaultValue absolutePaths ? : boolean ; } /**
 * The options for  FileSystem . writeFile public export interface IFileSystemWriteFileOptions { defaultValue ensureFolderExists ? : boolean ; defaultValue convertLineEndings ? : NewlineKind ; defaultValue encoding ? : Encoding ; } /**
 * The options for  FileSystem . readFile public export interface IFileSystemReadFileOptions { defaultValue encoding ? : Encoding ; defaultValue convertLineEndings ? : NewlineKind ; } /**
 * The options for  FileSystem . move public export interface IFileSystemMoveOptions { /**
     * The path of the existing object to be moved.
     * The path may be absolute or relative.
     */ sourcePath : string ; /**
     * The new path for the object.
     * The path may be absolute or relative.
     */ destinationPath : string ; defaultValue overwrite ? : boolean ; defaultValue ensureFolderExists ? : boolean ; } public export interface IFileSystemCopyFileBaseOptions { /**
     * The path of the existing object to be copied.
     * The path may be absolute or relative.
     */ sourcePath : string ; defaultValue AlreadyExistsBehavior . Overwrite alreadyExistsBehavior ? : AlreadyExistsBehavior ; } /**
 * The options for  FileSystem . copyFile public export interface IFileSystemCopyFileOptions extends IFileSystemCopyFileBaseOptions { /**
     * The path that the object will be copied to.
     * The path may be absolute or relative.
     */ destinationPath : string ; } /**
 * Specifies the behavior of APIs such as  FileSystem . copyFile or
 *  FileSystem . createSymbolicLinkFile when the output file path already exists.
 *
 *  remarks For  FileSystem . copyFile and related APIs, the "output file path" is
 *  IFileSystemCopyFileOptions . destinationPath .
 *
 * For  FileSystem . createSymbolicLinkFile and related APIs, the "output file path" is
 *  IFileSystemCreateLinkOptions . newLinkPath .
 *
 *  public export enum AlreadyExistsBehavior { remarks If overwriting the object would require recursively deleting a folder tree,
     * then the operation will fail.  As an example, suppose  FileSystem . copyFile * is copying a single file `/a/b/c` to the destination path `/d/e`, and `/d/e` is a
     * nonempty folder.  In this situation, an error will be reported; specifying
     * `AlreadyExistsBehavior.Overwrite` does not help.  Empty folders can be overwritten
     * depending on the details of the implementation.
      Overwrite = 'overwrite' , /**
     * If the output file path already exists, the operation will fail, and an error
     * will be reported.
     */ Error = 'error' , /**
     * If the output file path already exists, skip this item, and continue the operation.
     */ Ignore = 'ignore' } /**
 * Callback function type for  IFileSystemCopyFilesAsyncOptions . filter public export type FileSystemCopyFilesAsyncFilter = ( sourcePath : string , destinationPath : string ) => Promise < boolean > ; /**
 * Callback function type for  IFileSystemCopyFilesOptions . filter public export type FileSystemCopyFilesFilter = ( sourcePath : string , destinationPath : string ) => boolean ; /**
 * The options for  FileSystem . copyFilesAsync public export interface IFileSystemCopyFilesAsyncOptions { /**
     * The starting path of the file or folder to be copied.
     * The path may be absolute or relative.
     */ sourcePath : string ; /**
     * The path that the files will be copied to.
     * The path may be absolute or relative.
     */ destinationPath : string ; /**
     * If true, then when copying symlinks, copy the target object instead of copying the link.
     */ dereferenceSymlinks ? : boolean ; remarks alreadyExistsBehavior ? : AlreadyExistsBehavior ; /**
     * If true, then the target object will be assigned "last modification" and "last access" timestamps
     * that are the same as the source.  Otherwise, the OS default timestamps are assigned.
     */ preserveTimestamps ? : boolean ; /**
     * A callback that will be invoked for each path that is copied.  The callback can return `false`
     * to cause the object to be excluded from the operation.
     */ filter ? : FileSystemCopyFilesAsyncFilter | FileSystemCopyFilesFilter ; } /**
 * The options for  FileSystem . copyFiles public export interface IFileSystemCopyFilesOptions extends IFileSystemCopyFilesAsyncOptions { /**  {@inheritdoc IFileSystemCopyFilesAsyncOptions.filter} */ filter ? : FileSystemCopyFilesFilter ; } /**
 * The options for  FileSystem . deleteFile public export interface IFileSystemDeleteFileOptions { defaultValue throwIfNotExists ? : boolean ; } /**
 * The options for  FileSystem . updateTimes * Both times must be specified.
 *  public export interface IFileSystemUpdateTimeParameters { /**
     * The POSIX epoch time or Date when this was last accessed.
     */ accessedTime : number | Date ; /**
     * The POSIX epoch time or Date when this was last modified
     */ modifiedTime : number | Date ; } /**
 * The options for  FileSystem . createSymbolicLinkJunction ,  FileSystem . createSymbolicLinkFile ,
 *  FileSystem . createSymbolicLinkFolder , and  FileSystem . createHardLink .
 *
 *  public export interface IFileSystemCreateLinkOptions { /**
     * The newly created symbolic link will point to `linkTargetPath` as its target.
     */ linkTargetPath : string ; /**
     * The newly created symbolic link will have this path.
     */ newLinkPath : string ; /**
     * Specifies what to do if the path to create already exists.
     * The default is `AlreadyExistsBehavior.Error`.
     */ alreadyExistsBehavior ? : AlreadyExistsBehavior ; } interface IInternalFileSystemCreateLinkOptions extends IFileSystemCreateLinkOptions { /**
     * Specifies if the link target must exist.
     */ linkTargetMustExist ? : boolean ; } const MOVE_DEFAULT_OPTIONS = { overwrite : true , ensureFolderExists : false } ; const READ_FOLDER_DEFAULT_OPTIONS = { absolutePaths : false } ; const WRITE_FILE_DEFAULT_OPTIONS = { ensureFolderExists : false , convertLineEndings : undefined , encoding : Encoding . Utf8 } ; const APPEND_TO_FILE_DEFAULT_OPTIONS = { ... WRITE_FILE_DEFAULT_OPTIONS } ; const READ_FILE_DEFAULT_OPTIONS = { encoding : Encoding . Utf8 , convertLineEndings : undefined } ; const COPY_FILE_DEFAULT_OPTIONS = { alreadyExistsBehavior : AlreadyExistsBehavior . Overwrite } ; const COPY_FILES_DEFAULT_OPTIONS = { alreadyExistsBehavior : AlreadyExistsBehavior . Overwrite } ; const DELETE_FILE_DEFAULT_OPTIONS = { throwIfNotExists : false } ; remarks public export class FileSystem { remarks param path public static exists ( path ) { return FileSystem . _wrapException ( ( ) => { return fsx . existsSync ( path ) ; } ) ; } /**
     * An async version of  FileSystem . exists .
      public static async existsAsync ( path ) { return await FileSystem . _wrapExceptionAsync ( ( ) => { return new Promise < boolean > ( ( resolve ) => { fsx . exists ( path , resolve ) ; } ) ; } ) ; } param path public static getStatistics ( path ) { return FileSystem . _wrapException ( ( ) => { return fsx . statSync ( path ) ; } ) ; } /**
     * An async version of  FileSystem . getStatistics .
      public static async getStatisticsAsync ( path ) { return await FileSystem . _wrapExceptionAsync ( ( ) => { return fsx . stat ( path ) ; } ) ; } param path param times public static updateTimes ( path , times ) { return FileSystem . _wrapException ( ( ) => { fsx . utimesSync ( path , times . accessedTime , times . modifiedTime ) ; } ) ; } /**
     * An async version of  FileSystem . updateTimes .
      public static async updateTimesAsync ( path , times ) { await FileSystem . _wrapExceptionAsync ( ( ) => { return fsx . utimes ( path , times . accessedTime as number , times . modifiedTime as number ) ; } ) ; } param path param modeBits - POSIX-style file mode bits specified using the  PosixModeBits enum
      public static changePosixModeBits ( path , mode ) { FileSystem . _wrapException ( ( ) => { fs . chmodSync ( path , mode ) ; } ) ; } /**
     * An async version of  FileSystem . changePosixModeBits .
      public static async changePosixModeBitsAsync ( path , mode ) { await FileSystem . _wrapExceptionAsync ( ( ) => { return fsx . chmod ( path , mode ) ; } ) ; } param path remarks This calls  FileSystem . getStatistics to get the POSIX mode bits.
     * If statistics in addition to the mode bits are needed, it is more efficient
     * to call  FileSystem . getStatistics directly instead.
      public static getPosixModeBits ( path ) { return FileSystem . _wrapException ( ( ) => { return FileSystem . getStatistics ( path ) . mode ; } ) ; } /**
     * An async version of  FileSystem . getPosixModeBits .
      public static async getPosixModeBitsAsync ( path ) { return await FileSystem . _wrapExceptionAsync ( async ( ) => { return ( await FileSystem . getStatisticsAsync ( path ) ) . mode ; } ) ; } remarks param modeBits - POSIX-style file mode bits specified using the  PosixModeBits enum
      public static formatPosixModeBits ( modeBits ) { let result = '-' ; result += modeBits & PosixModeBits . UserRead ? 'r' : '-' ; result += modeBits & PosixModeBits . UserWrite ? 'w' : '-' ; result += modeBits & PosixModeBits . UserExecute ? 'x' : '-' ; result += modeBits & PosixModeBits . GroupRead ? 'r' : '-' ; result += modeBits & PosixModeBits . GroupWrite ? 'w' : '-' ; result += modeBits & PosixModeBits . GroupExecute ? 'x' : '-' ; result += modeBits & PosixModeBits . OthersRead ? 'r' : '-' ; result += modeBits & PosixModeBits . OthersWrite ? 'w' : '-' ; result += modeBits & PosixModeBits . OthersExecute ? 'x' : '-' ; return result ; } /**
     * Moves a file. The folder must exist, unless the `ensureFolderExists` option is provided.
     * Behind the scenes it uses `fs-extra.moveSync()`
     */ public static move ( options ) { FileSystem . _wrapException ( ( ) => { options = { ... MOVE_DEFAULT_OPTIONS , ... options } ; try { fsx . moveSync ( options . sourcePath , options . destinationPath , { overwrite : options . overwrite } ) ; } catch ( error ) { if ( options . ensureFolderExists ) { if ( ! FileSystem . isNotExistError ( error as Error ) ) { throw error ; } const folderPath = nodeJsPath . dirname ( options . destinationPath ) ; FileSystem . ensureFolder ( folderPath ) ; fsx . moveSync ( options . sourcePath , options . destinationPath , { overwrite : options . overwrite } ) ; } else { throw error ; } } } ) ; } /**
     * An async version of  FileSystem . move .
      public static async moveAsync ( options ) { await FileSystem . _wrapExceptionAsync ( async ( ) => { options = { ... MOVE_DEFAULT_OPTIONS , ... options } ; try { await fsx . move ( options . sourcePath , options . destinationPath , { overwrite : options . overwrite } ) ; } catch ( error ) { if ( options . ensureFolderExists ) { if ( ! FileSystem . isNotExistError ( error as Error ) ) { throw error ; } const folderPath = nodeJsPath . dirname ( options . destinationPath ) ; await FileSystem . ensureFolderAsync ( nodeJsPath . dirname ( folderPath ) ) ; await fsx . move ( options . sourcePath , options . destinationPath , { overwrite : options . overwrite } ) ; } else { throw error ; } } } ) ; } remarks param folderPath public static ensureFolder ( folderPath ) { FileSystem . _wrapException ( ( ) => { fsx . ensureDirSync ( folderPath ) ; } ) ; } /**
     * An async version of  FileSystem . ensureFolder .
      public static async ensureFolderAsync ( folderPath ) { await FileSystem . _wrapExceptionAsync ( ( ) => { return fsx . ensureDir ( folderPath ) ; } ) ; } deprecated Use  FileSystem . readFolderItemNames instead.
      public static readFolder ( folderPath , options ? ) { return FileSystem . readFolderItemNames ( folderPath , options ) ; } deprecated Use  FileSystem . readFolderItemNamesAsync instead.
      public static async readFolderAsync ( folderPath , options ? ) { return await FileSystem . readFolderItemNamesAsync ( folderPath , options ) ; } param folderPath param options public static readFolderItemNames ( folderPath , options ? ) { return FileSystem . _wrapException ( ( ) => { options = { ... READ_FOLDER_DEFAULT_OPTIONS , ... options } ; const fileNames = fsx . readdirSync ( folderPath ) ; if ( options . absolutePaths ) { return fileNames . map ( ( fileName ) => nodeJsPath . resolve ( folderPath , fileName ) ) ; } else { return fileNames ; } } ) ; } /**
     * An async version of  FileSystem . readFolderItemNames .
      public static async readFolderItemNamesAsync ( folderPath , options ? ) { return await FileSystem . _wrapExceptionAsync ( async ( ) => { options = { ... READ_FOLDER_DEFAULT_OPTIONS , ... options } ; const fileNames = await fsx . readdir ( folderPath ) ; if ( options . absolutePaths ) { return fileNames . map ( ( fileName ) => nodeJsPath . resolve ( folderPath , fileName ) ) ; } else { return fileNames ; } } ) ; } param folderPath param options public static readFolderItems ( folderPath , options ? ) { return FileSystem . _wrapException ( ( ) => { options = { ... READ_FOLDER_DEFAULT_OPTIONS , ... options } ; const folderEntries = fsx . readdirSync ( folderPath , { withFileTypes : true } ) ; if ( options . absolutePaths ) { return folderEntries . map ( ( folderEntry ) => { folderEntry . name = nodeJsPath . resolve ( folderPath , folderEntry . name ) ; return folderEntry ; } ) ; } else { return folderEntries ; } } ) ; } /**
     * An async version of  FileSystem . readFolderItems .
      public static async readFolderItemsAsync ( folderPath , options ? ) { return await FileSystem . _wrapExceptionAsync ( async ( ) => { options = { ... READ_FOLDER_DEFAULT_OPTIONS , ... options } ; const folderEntries = await LegacyAdapters . convertCallbackToPromise ( fs . readdir , folderPath , { withFileTypes : true } ) ; if ( options . absolutePaths ) { return folderEntries . map ( ( folderEntry ) => { folderEntry . name = nodeJsPath . resolve ( folderPath , folderEntry . name ) ; return folderEntry ; } ) ; } else { return folderEntries ; } } ) ; } remarks param folderPath public static deleteFolder ( folderPath ) { FileSystem . _wrapException ( ( ) => { fsx . removeSync ( folderPath ) ; } ) ; } /**
     * An async version of  FileSystem . deleteFolder .
      public static async deleteFolderAsync ( folderPath ) { await FileSystem . _wrapExceptionAsync ( ( ) => { return fsx . remove ( folderPath ) ; } ) ; } remarks param folderPath public static ensureEmptyFolder ( folderPath ) { FileSystem . _wrapException ( ( ) => { fsx . emptyDirSync ( folderPath ) ; } ) ; } /**
     * An async version of  FileSystem . ensureEmptyFolder .
      public static async ensureEmptyFolderAsync ( folderPath ) { await FileSystem . _wrapExceptionAsync ( ( ) => { return fsx . emptyDir ( folderPath ) ; } ) ; } remarks param filePath param contents param options public static writeFile ( filePath , contents , options ? ) { FileSystem . _wrapException ( ( ) => { options = { ... WRITE_FILE_DEFAULT_OPTIONS , ... options } ; if ( options . convertLineEndings ) { contents = Text . convertTo ( contents . toString ( ) , options . convertLineEndings ) ; } try { fsx . writeFileSync ( filePath , contents , { encoding : options . encoding } ) ; } catch ( error ) { if ( options . ensureFolderExists ) { if ( ! FileSystem . isNotExistError ( error as Error ) ) { throw error ; } const folderPath = nodeJsPath . dirname ( filePath ) ; FileSystem . ensureFolder ( folderPath ) ; fsx . writeFileSync ( filePath , contents , { encoding : options . encoding } ) ; } else { throw error ; } } } ) ; } /**
     * An async version of  FileSystem . writeFile .
      public static async writeFileAsync ( filePath , contents , options ? ) { await FileSystem . _wrapExceptionAsync ( async ( ) => { options = { ... WRITE_FILE_DEFAULT_OPTIONS , ... options } ; if ( options . convertLineEndings ) { contents = Text . convertTo ( contents . toString ( ) , options . convertLineEndings ) ; } try { await fsx . writeFile ( filePath , contents , { encoding : options . encoding } ) ; } catch ( error ) { if ( options . ensureFolderExists ) { if ( ! FileSystem . isNotExistError ( error as Error ) ) { throw error ; } const folderPath = nodeJsPath . dirname ( filePath ) ; await FileSystem . ensureFolderAsync ( folderPath ) ; await fsx . writeFile ( filePath , contents , { encoding : options . encoding } ) ; } else { throw error ; } } } ) ; } remarks param filePath param contents param options public static appendToFile ( filePath , contents , options ? ) { FileSystem . _wrapException ( ( ) => { options = { ... APPEND_TO_FILE_DEFAULT_OPTIONS , ... options } ; if ( options . convertLineEndings ) { contents = Text . convertTo ( contents . toString ( ) , options . convertLineEndings ) ; } try { fsx . appendFileSync ( filePath , contents , { encoding : options . encoding } ) ; } catch ( error ) { if ( options . ensureFolderExists ) { if ( ! FileSystem . isNotExistError ( error as Error ) ) { throw error ; } const folderPath = nodeJsPath . dirname ( filePath ) ; FileSystem . ensureFolder ( folderPath ) ; fsx . appendFileSync ( filePath , contents , { encoding : options . encoding } ) ; } else { throw error ; } } } ) ; } /**
     * An async version of  FileSystem . appendToFile .
      public static async appendToFileAsync ( filePath , contents , options ? ) { await FileSystem . _wrapExceptionAsync ( async ( ) => { options = { ... APPEND_TO_FILE_DEFAULT_OPTIONS , ... options } ; if ( options . convertLineEndings ) { contents = Text . convertTo ( contents . toString ( ) , options . convertLineEndings ) ; } try { await fsx . appendFile ( filePath , contents , { encoding : options . encoding } ) ; } catch ( error ) { if ( options . ensureFolderExists ) { if ( ! FileSystem . isNotExistError ( error as Error ) ) { throw error ; } const folderPath = nodeJsPath . dirname ( filePath ) ; await FileSystem . ensureFolderAsync ( folderPath ) ; await fsx . appendFile ( filePath , contents , { encoding : options . encoding } ) ; } else { throw error ; } } } ) ; } param filePath param options public static readFile ( filePath , options ? ) { return FileSystem . _wrapException ( ( ) => { options = { ... READ_FILE_DEFAULT_OPTIONS , ... options } ; let contents = FileSystem . readFileToBuffer ( filePath ) . toString ( options . encoding ) ; if ( options . convertLineEndings ) { contents = Text . convertTo ( contents , options . convertLineEndings ) ; } return contents ; } ) ; } /**
     * An async version of  FileSystem . readFile .
      public static async readFileAsync ( filePath , options ? ) { return await FileSystem . _wrapExceptionAsync ( async ( ) => { options = { ... READ_FILE_DEFAULT_OPTIONS , ... options } ; let contents = ( await FileSystem . readFileToBufferAsync ( filePath ) ) . toString ( options . encoding ) ; if ( options . convertLineEndings ) { contents = Text . convertTo ( contents , options . convertLineEndings ) ; } return contents ; } ) ; } param filePath public static readFileToBuffer ( filePath ) { return FileSystem . _wrapException ( ( ) => { return fsx . readFileSync ( filePath ) ; } ) ; } /**
     * An async version of  FileSystem . readFileToBuffer .
      public static async readFileToBufferAsync ( filePath ) { return await FileSystem . _wrapExceptionAsync ( ( ) => { return fsx . readFile ( filePath ) ; } ) ; } remarks The `copyFile()` API cannot be used to copy folders.  It copies at most one file.
     * Use  FileSystem . copyFiles if you need to recursively copy a tree of folders.
     *
     * The implementation is based on `copySync()` from the `fs-extra` package.
      public static copyFile ( options ) { options = { ... COPY_FILE_DEFAULT_OPTIONS , ... options } ; if ( FileSystem . getStatistics ( options . sourcePath ) . isDirectory ( ) ) { throw new Error ( 'The specified path refers to a folder; this operation expects a file object:\n' + options . sourcePath ) ; } FileSystem . _wrapException ( ( ) => { fsx . copySync ( options . sourcePath , options . destinationPath , { errorOnExist : options . alreadyExistsBehavior === AlreadyExistsBehavior . Error , overwrite : options . alreadyExistsBehavior === AlreadyExistsBehavior . Overwrite } ) ; } ) ; } /**
     * An async version of  FileSystem . copyFile .
      public static async copyFileAsync ( options ) { options = { ... COPY_FILE_DEFAULT_OPTIONS , ... options } ; if ( ( await FileSystem . getStatisticsAsync ( options . sourcePath ) ) . isDirectory ( ) ) { throw new Error ( 'The specified path refers to a folder; this operation expects a file object:\n' + options . sourcePath ) ; } await FileSystem . _wrapExceptionAsync ( ( ) => { return fsx . copy ( options . sourcePath , options . destinationPath , { errorOnExist : options . alreadyExistsBehavior === AlreadyExistsBehavior . Error , overwrite : options . alreadyExistsBehavior === AlreadyExistsBehavior . Overwrite } ) ; } ) ; } remarks If you only intend to copy a single file, it is recommended to use  FileSystem . copyFile * instead to more clearly communicate the intended operation.
     *
     * The implementation is based on `copySync()` from the `fs-extra` package.
      public static copyFiles ( options ) { options = { ... COPY_FILES_DEFAULT_OPTIONS , ... options } ; FileSystem . _wrapException ( ( ) => { fsx . copySync ( options . sourcePath , options . destinationPath , { dereference : ! ! options . dereferenceSymlinks , errorOnExist : options . alreadyExistsBehavior === AlreadyExistsBehavior . Error , overwrite : options . alreadyExistsBehavior === AlreadyExistsBehavior . Overwrite , preserveTimestamps : ! ! options . preserveTimestamps , filter : options . filter } ) ; } ) ; } /**
     * An async version of  FileSystem . copyFiles .
      public static async copyFilesAsync ( options ) { options = { ... COPY_FILES_DEFAULT_OPTIONS , ... options } ; await FileSystem . _wrapExceptionAsync ( async ( ) => { fsx . copySync ( options . sourcePath , options . destinationPath , { dereference : ! ! options . dereferenceSymlinks , errorOnExist : options . alreadyExistsBehavior === AlreadyExistsBehavior . Error , overwrite : options . alreadyExistsBehavior === AlreadyExistsBehavior . Overwrite , preserveTimestamps : ! ! options . preserveTimestamps , filter : options . filter } ) ; } ) ; } param filePath param options public static deleteFile ( filePath , options ? ) { FileSystem . _wrapException ( ( ) => { options = { ... DELETE_FILE_DEFAULT_OPTIONS , ... options } ; try { fsx . unlinkSync ( filePath ) ; } catch ( error ) { if ( options . throwIfNotExists || ! FileSystem . isNotExistError ( error as Error ) ) { throw error ; } } } ) ; } /**
     * An async version of  FileSystem . deleteFile .
      public static async deleteFileAsync ( filePath , options ? ) { await FileSystem . _wrapExceptionAsync ( async ( ) => { options = { ... DELETE_FILE_DEFAULT_OPTIONS , ... options } ; try { await fsx . unlink ( filePath ) ; } catch ( error ) { if ( options . throwIfNotExists || ! FileSystem . isNotExistError ( error as Error ) ) { throw error ; } } } ) ; } param path public static getLinkStatistics ( path ) { return FileSystem . _wrapException ( ( ) => { return fsx . lstatSync ( path ) ; } ) ; } /**
     * An async version of  FileSystem . getLinkStatistics .
      public static async getLinkStatisticsAsync ( path ) { return await FileSystem . _wrapExceptionAsync ( ( ) => { return fsx . lstat ( path ) ; } ) ; } remarks param path returns public static readLink ( path ) { return FileSystem . _wrapException ( ( ) => { return fsx . readlinkSync ( path ) ; } ) ; } /**
     * An async version of  FileSystem . readLink .
      public static async readLinkAsync ( path ) { return await FileSystem . _wrapExceptionAsync ( ( ) => { return fsx . readlink ( path ) ; } ) ; } remarks public static createSymbolicLinkJunction ( options ) { FileSystem . _wrapException ( ( ) => { return FileSystem . _handleLink ( ( ) => { return fsx . symlinkSync ( options . linkTargetPath , options . newLinkPath , 'junction' ) ; } , options ) ; } ) ; } /**
     * An async version of  FileSystem . createSymbolicLinkJunction .
      public static async createSymbolicLinkJunctionAsync ( options ) { await FileSystem . _wrapExceptionAsync ( ( ) => { return FileSystem . _handleLinkAsync ( ( ) => { return fsx . symlink ( options . linkTargetPath , options . newLinkPath , 'junction' ) ; } , options ) ; } ) ; } remarks To avoid administrator elevation on Windows, use  FileSystem . createHardLink instead.
     *
     * On Windows operating systems, the NTFS file system distinguishes file symlinks versus directory symlinks:
     * If the target is not the correct type, the symlink will be created successfully, but will fail to resolve.
     * Other operating systems do not make this distinction, in which case  FileSystem . createSymbolicLinkFile * and  FileSystem . createSymbolicLinkFolder can be used interchangeably, but doing so will make your
     * tool incompatible with Windows.
      public static createSymbolicLinkFile ( options ) { FileSystem . _wrapException ( ( ) => { return FileSystem . _handleLink ( ( ) => { return fsx . symlinkSync ( options . linkTargetPath , options . newLinkPath , 'file' ) ; } , options ) ; } ) ; } /**
     * An async version of  FileSystem . createSymbolicLinkFile .
      public static async createSymbolicLinkFileAsync ( options ) { await FileSystem . _wrapExceptionAsync ( ( ) => { return FileSystem . _handleLinkAsync ( ( ) => { return fsx . symlink ( options . linkTargetPath , options . newLinkPath , 'file' ) ; } , options ) ; } ) ; } remarks To avoid administrator elevation on Windows, use  FileSystem . createSymbolicLinkJunction instead.
     *
     * On Windows operating systems, the NTFS file system distinguishes file symlinks versus directory symlinks:
     * If the target is not the correct type, the symlink will be created successfully, but will fail to resolve.
     * Other operating systems do not make this distinction, in which case  FileSystem . createSymbolicLinkFile * and  FileSystem . createSymbolicLinkFolder can be used interchangeably, but doing so will make your
     * tool incompatible with Windows.
      public static createSymbolicLinkFolder ( options ) { FileSystem . _wrapException ( ( ) => { return FileSystem . _handleLink ( ( ) => { return fsx . symlinkSync ( options . linkTargetPath , options . newLinkPath , 'dir' ) ; } , options ) ; } ) ; } /**
     * An async version of  FileSystem . createSymbolicLinkFolder .
      public static async createSymbolicLinkFolderAsync ( options ) { await FileSystem . _wrapExceptionAsync ( ( ) => { return FileSystem . _handleLinkAsync ( ( ) => { return fsx . symlink ( options . linkTargetPath , options . newLinkPath , 'dir' ) ; } , options ) ; } ) ; } remarks public static createHardLink ( options ) { FileSystem . _wrapException ( ( ) => { return FileSystem . _handleLink ( ( ) => { return fsx . linkSync ( options . linkTargetPath , options . newLinkPath ) ; } , { ... options , linkTargetMustExist : true } ) ; } ) ; } /**
     * An async version of  FileSystem . createHardLink .
      public static async createHardLinkAsync ( options ) { await FileSystem . _wrapExceptionAsync ( ( ) => { return FileSystem . _handleLinkAsync ( ( ) => { return fsx . link ( options . linkTargetPath , options . newLinkPath ) ; } , { ... options , linkTargetMustExist : true } ) ; } ) ; } param linkPath public static getRealPath ( linkPath ) { return FileSystem . _wrapException ( ( ) => { return fsx . realpathSync ( linkPath ) ; } ) ; } /**
     * An async version of  FileSystem . getRealPath .
      public static async getRealPathAsync ( linkPath ) { return await FileSystem . _wrapExceptionAsync ( ( ) => { return fsx . realpath ( linkPath ) ; } ) ; } /**
     * Returns true if the error object indicates the file or folder already exists (`EEXIST`).
     */ public static isExistError ( error ) { return FileSystem . isErrnoException ( error ) && error . code === 'EEXIST' ; } /**
     * Returns true if the error object indicates the file or folder does not exist (`ENOENT` or `ENOTDIR`)
     */ public static isNotExistError ( error ) { return FileSystem . isFileDoesNotExistError ( error ) || FileSystem . isFolderDoesNotExistError ( error ) ; } /**
     * Returns true if the error object indicates the file does not exist (`ENOENT`).
     */ public static isFileDoesNotExistError ( error ) { return FileSystem . isErrnoException ( error ) && error . code === 'ENOENT' ; } /**
     * Returns true if the error object indicates the folder does not exist (`ENOTDIR`).
     */ public static isFolderDoesNotExistError ( error ) { return FileSystem . isErrnoException ( error ) && error . code === 'ENOTDIR' ; } /**
     * Returns true if the error object indicates that the `unlink` system call failed
     * due to a permissions issue (`EPERM`).
     */ public static isUnlinkNotPermittedError ( error ) { return FileSystem . isErrnoException ( error ) && error . code === 'EPERM' && error . syscall === 'unlink' ; } /**
     * Detects if the provided error object is a `NodeJS.ErrnoException`
     */ public static isErrnoException ( error ) { const typedError = error ; return ( typeof typedError . code === 'string' && typeof typedError . errno === 'number' && typeof typedError . path === 'string' && typeof typedError . syscall === 'string' ) ; } private static _handleLink ( linkFn , options ) { try { linkFn ( ) ; } catch ( error ) { if ( FileSystem . isExistError ( error as Error ) ) { switch ( options . alreadyExistsBehavior ) { case AlreadyExistsBehavior . Ignore : break ; case AlreadyExistsBehavior . Overwrite : this . deleteFile ( options . newLinkPath ) ; linkFn ( ) ; break ; case AlreadyExistsBehavior . Error : default : throw error ; } } else { if ( FileSystem . isNotExistError ( error as Error ) && ( ! options . linkTargetMustExist || FileSystem . exists ( options . linkTargetPath ) ) ) { this . ensureFolder ( nodeJsPath . dirname ( options . newLinkPath ) ) ; linkFn ( ) ; } else { throw error ; } } } } private static async _handleLinkAsync ( linkFn , options ) { try { await linkFn ( ) ; } catch ( error ) { if ( FileSystem . isExistError ( error as Error ) ) { switch ( options . alreadyExistsBehavior ) { case AlreadyExistsBehavior . Ignore : break ; case AlreadyExistsBehavior . Overwrite : await this . deleteFileAsync ( options . newLinkPath ) ; await linkFn ( ) ; break ; case AlreadyExistsBehavior . Error : default : throw error ; } } else { if ( FileSystem . isNotExistError ( error as Error ) && ( ! options . linkTargetMustExist || ( await FileSystem . existsAsync ( options . linkTargetPath ) ) ) ) { await this . ensureFolderAsync ( nodeJsPath . dirname ( options . newLinkPath ) ) ; await linkFn ( ) ; } else { throw error ; } } } } private static _wrapException < TResult > ( fn ) { try { return fn ( ) ; } catch ( error ) { FileSystem . _updateErrorMessage ( error as Error ) ; throw error ; } } private static async _wrapExceptionAsync < TResult > ( fn ) { try { return await fn ( ) ; } catch ( error ) { FileSystem . _updateErrorMessage ( error as Error ) ; throw error ; } } private static _updateErrorMessage ( error ) { if ( FileSystem . isErrnoException ( error ) ) { if ( FileSystem . isFileDoesNotExistError ( error ) ) { error . message = `File does not exist: ${ error . path }\n${ error . message }` ; } else if ( FileSystem . isFolderDoesNotExistError ( error ) ) { error . message = `Folder does not exist: ${ error . path }\n${ error . message }` ; } else if ( FileSystem . isExistError ( error ) ) { const extendedError = error ; error . message = `File or folder already exists: ${ extendedError . dest }\n${ error . message }` ; } else if ( FileSystem . isUnlinkNotPermittedError ( error ) ) { error . message = `File or folder could not be deleted: ${ error . path }\n${ error . message }` ; } } } }