import { CreateReadStreamOptions , CreateWriteStreamOptions , } from "@yarnpkg/fslib" ; import { FakeFS , WriteFileOptions , ProxiedFS } from "@yarnpkg/fslib" ; import { WatchOptions , WatchCallback , Watcher } from "@yarnpkg/fslib" ; import { FSPath , NativePath , PortablePath , npath , ppath } from "@yarnpkg/fslib" ; import { RmdirOptions } from "@yarnpkg/fslib" ; import { Dirent , Filename , MkdirOptions , WatchFileCallback , WatchFileOptions , StatWatcher , OpendirOptions , Dir , SymlinkType , } from "@yarnpkg/fslib" ; import fs , { BigIntStats , Stats } from "fs" ; import { load } from "js-yaml" ; import YAWN from "yawn-yaml/cjs" ; import { LruCache } from "./lru" ; export class PackageYamlFS extends ProxiedFS < NativePath , PortablePath > { protected readonly baseFs : PortablePackageYamlFS ; constructor ( realFs ) { super ( npath ) ; this . baseFs = new PortablePackageYamlFS ( realFs ) ; } protected mapFromBase ( path ) { return npath . fromPortablePath ( path ) ; } protected mapToBase ( path ) { return npath . toPortablePath ( path ) ; } patchManifestPath ( p ) { return this . baseFs . patchManifestPath ( p ) ; } } export abstract class BasePortableFakeFS extends FakeFS < PortablePath > { protected constructor ( ) { super ( ppath ) ; } } const ManifestFiles = [ "package.json" , "package.yaml" , "package.yml" ] as const ; type ManifestFilename = typeof ManifestFiles [ number ] ; export class PortablePackageYamlFS extends BasePortableFakeFS { private readonly realFs : typeof fs ; protected cache : LruCache < string > ; constructor ( realFs = fs ) { super ( ) ; this . realFs = { ... realFs } ; this . cache = new LruCache ( ) ; } convertManifestPath ( p , f ) { const str = p . toString ( ) ; const rest = str . substring ( 0 , str . lastIndexOf ( "/" ) + 1 ) ; return `${ rest }${ f }` as PortablePath ; } isPathForManifest ( p ) { const str = p . toString ( ) ; const file = str . substring ( str . lastIndexOf ( "/" ) + 1 , str . length ) ; return ManifestFiles . includes ( file as ManifestFilename ) ? ( file as ManifestFilename ) : false ; } doesManifestExist ( p ) { const str = p . toString ( ) ; const rest = str . substring ( 0 , str . lastIndexOf ( "/" ) + 1 ) ; return ManifestFiles . find ( ( manifest ) => { return this . realFs . existsSync ( npath . fromPortablePath ( `${ rest }${ manifest }` ) ) ; } ) ; } patchManifestPath ( p ) { const cached = this . cache . get ( p ) ; if ( typeof cached !== "undefined" ) { return cached as PortablePath ; } let patched = p ; if ( ! ! this . isPathForManifest ( p ) ) { const manifestName = this . doesManifestExist ( p ) ; if ( typeof manifestName !== "undefined" ) { patched = this . convertManifestPath ( p , manifestName ) ; } this . cache . set ( p , patched ) ; } return patched ; } readManifestFile ( p , encoding ? ) { try { const manifestType = this . isPathForManifest ( p ) ; if ( manifestType === false || manifestType == "package.json" ) { return false ; } const fsNativePath = typeof p === `string` ? npath . fromPortablePath ( p ) : p ; const data = this . realFs . readFileSync ( fsNativePath , encoding as BufferEncoding | ( fs . BaseEncodingOptions & { flag ? : string | undefined ; } ) | null | undefined ) ; let rawManifest = `` ; if ( data instanceof Buffer ) { rawManifest = data . toString ( ) ; } else { rawManifest = data ; } const pkgYml = load ( rawManifest ) ; return JSON . stringify ( pkgYml ) ; } catch { } return false ; } writeManifestFile ( p , content , manifestFilename , opts ? ) { if ( typeof content === `string` || Buffer . isBuffer ( content ) ) { if ( manifestFilename == "package.json" ) { return false ; } const mJsonStr = Buffer . isBuffer ( content ) ? content . toString ( ) : content ; const manifestObject = JSON . parse ( mJsonStr ) ; const nativeManifestPath = npath . fromPortablePath ( p as PortablePath ) ; try { const rawManifest = this . realFs . readFileSync ( nativeManifestPath , `utf-8` ) ; const manifestYawn = new YAWN ( rawManifest ) ; manifestYawn . json = manifestObject ; if ( opts ) { this . realFs . writeFileSync ( npath . fromPortablePath ( nativeManifestPath ) , manifestYawn . yaml , opts as fs . WriteFileOptions ) ; } else { this . realFs . writeFileSync ( npath . fromPortablePath ( nativeManifestPath ) , manifestYawn . yaml ) ; } return true ; } catch { } } return false ; } getExtractHint ( ) { return false ; } getRealPath ( ) { return PortablePath . root ; } resolve ( p ) { p = this . patchManifestPath ( p ) ; return ppath . resolve ( p ) ; } async openPromise ( p , flags , mode ? ) { p = this . patchManifestPath ( p ) ; return await new Promise < number > ( ( resolve , reject ) => { this . realFs . open ( npath . fromPortablePath ( p ) , flags , mode , this . makeCallback ( resolve , reject ) ) ; } ) ; } openSync ( p , flags , mode ? ) { p = this . patchManifestPath ( p ) ; return this . realFs . openSync ( npath . fromPortablePath ( p ) , flags , mode ) ; } async opendirPromise ( p , opts ? ) { return await new Promise < Dir < PortablePath > > ( ( resolve , reject ) => { if ( typeof opts !== `undefined` ) { this . realFs . opendir ( npath . fromPortablePath ( p ) , opts , this . makeCallback ( resolve , reject ) as any ) ; } else { this . realFs . opendir ( npath . fromPortablePath ( p ) , this . makeCallback ( resolve , reject ) as any ) ; } } ) . then ( ( dir ) => { return Object . defineProperty ( dir , `path` , { value : p , configurable : true , writable : true , } ) ; } ) ; } opendirSync ( p , opts ? ) { const dir = typeof opts !== `undefined` ? ( this . realFs . opendirSync ( npath . fromPortablePath ( p ) , opts ) as Dir < PortablePath > ) : ( this . realFs . opendirSync ( npath . fromPortablePath ( p ) ) as Dir < PortablePath > ) ; return Object . defineProperty ( dir , `path` , { value : p , configurable : true , writable : true , } ) ; } async readPromise ( fd , buffer , offset = 0 , length = 0 , position = - 1 ) { return await new Promise < number > ( ( resolve , reject ) => { this . realFs . read ( fd , buffer , offset , length , position , ( error , bytesRead ) => { if ( error ) { reject ( error ) ; } else { resolve ( bytesRead ) ; } } ) ; } ) ; } readSync ( fd , buffer , offset , length , position ) { return this . realFs . readSync ( fd , buffer , offset , length , position ) ; } writePromise ( fd , buffer , offset ? , length ? , position ? ) ; writePromise ( fd , buffer , position ? ) ; async writePromise ( fd , buffer , offset ? , length ? , position ? ) { return await new Promise < number > ( ( resolve , reject ) => { if ( typeof buffer === `string` ) { return this . realFs . write ( fd , buffer , offset , this . makeCallback ( resolve , reject ) ) ; } else { return this . realFs . write ( fd , buffer , offset , length , position , this . makeCallback ( resolve , reject ) ) ; } } ) ; } writeSync ( fd , buffer , offset ? , length ? , position ? ) ; writeSync ( fd , buffer , position ? ) ; writeSync ( fd , buffer , offset ? , length ? , position ? ) { if ( typeof buffer === `string` ) { return this . realFs . writeSync ( fd , buffer , offset ) ; } else { return this . realFs . writeSync ( fd , buffer , offset , length , position ) ; } } async closePromise ( fd ) { await new Promise < void > ( ( resolve , reject ) => { this . realFs . close ( fd , this . makeCallback ( resolve , reject ) ) ; } ) ; } closeSync ( fd ) { this . realFs . closeSync ( fd ) ; } createReadStream ( p , opts ? ) { if ( p !== null ) { p = this . patchManifestPath ( p ) ; } const realPath = ( p !== null ? npath . fromPortablePath ( p ) : p ) as fs . PathLike ; return this . realFs . createReadStream ( realPath , opts as BufferEncoding | undefined ) ; } createWriteStream ( p , opts ? ) { if ( p !== null ) { p = this . patchManifestPath ( p ) ; } const realPath = ( p !== null ? npath . fromPortablePath ( p ) : p ) as fs . PathLike ; return this . realFs . createWriteStream ( realPath , opts as BufferEncoding | undefined ) ; } async realpathPromise ( p ) { p = this . patchManifestPath ( p ) ; return await new Promise < string > ( ( resolve , reject ) => { this . realFs . realpath ( npath . fromPortablePath ( p ) , { } , this . makeCallback ( resolve , reject ) ) ; } ) . then ( ( path ) => { return npath . toPortablePath ( path ) ; } ) ; } realpathSync ( p ) { p = this . patchManifestPath ( p ) ; return npath . toPortablePath ( this . realFs . realpathSync ( npath . fromPortablePath ( p ) , { } ) ) ; } async existsPromise ( p ) { p = this . patchManifestPath ( p ) ; return await new Promise < boolean > ( ( resolve ) => { if ( this . realFs . existsSync ( npath . fromPortablePath ( p ) ) ) { resolve ( true ) ; } else { resolve ( false ) ; } } ) ; } accessSync ( p , mode ? ) { p = this . patchManifestPath ( p ) ; return this . realFs . accessSync ( npath . fromPortablePath ( p ) , mode ) ; } async accessPromise ( p , mode ? ) { p = this . patchManifestPath ( p ) ; return await new Promise < void > ( ( resolve , reject ) => { this . realFs . access ( npath . fromPortablePath ( p ) , mode , this . makeCallback ( resolve , reject ) ) ; } ) ; } existsSync ( p ) { p = this . patchManifestPath ( p ) ; return this . realFs . existsSync ( npath . fromPortablePath ( p ) ) ; } async statPromise ( p ) ; async statPromise ( p , opts ) ; async statPromise ( p , opts ? ) ; async statPromise ( p , opts ? ) { return await new Promise < Stats > ( ( resolve , reject ) => { p = this . patchManifestPath ( p ) ; if ( opts ) { this . realFs . stat ( npath . fromPortablePath ( p ) , opts as fs . StatOptions & { bigint ? : false | undefined ; } , this . makeCallback ( resolve , reject ) ) ; } else { this . realFs . stat ( npath . fromPortablePath ( p ) , this . makeCallback ( resolve , reject ) ) ; } } ) ; } statSync ( p ) ; statSync ( p , opts ) ; statSync ( p , opts ? ) ; statSync ( p , opts ? ) { p = this . patchManifestPath ( p ) ; if ( opts ) { return this . realFs . statSync ( npath . fromPortablePath ( p ) , opts ) ; } else { return this . realFs . statSync ( npath . fromPortablePath ( p ) ) ; } } async fstatPromise ( fd ) ; async fstatPromise ( fd , opts ) ; async fstatPromise ( fd , opts ? ) ; async fstatPromise ( fd , opts ? ) { return await new Promise < Stats > ( ( resolve , reject ) => { if ( opts ) { this . realFs . fstat ( fd , opts , this . makeCallback ( resolve , reject ) ) ; } else { this . realFs . fstat ( fd , this . makeCallback ( resolve , reject ) ) ; } } ) ; } fstatSync ( fd ) ; fstatSync ( fd , opts ) ; fstatSync ( fd , opts ? ) ; fstatSync ( fd , opts ? ) { if ( opts ) { return this . realFs . fstatSync ( fd , opts ) ; } else { return this . realFs . fstatSync ( fd ) ; } } async lstatPromise ( p ) ; async lstatPromise ( p , opts ) ; async lstatPromise ( p , opts ? ) ; async lstatPromise ( p , opts ? ) { return await new Promise < Stats > ( ( resolve , reject ) => { p = this . patchManifestPath ( p ) ; if ( opts ) { this . realFs . lstat ( npath . fromPortablePath ( p ) , opts , this . makeCallback ( resolve , reject ) ) ; } else { this . realFs . lstat ( npath . fromPortablePath ( p ) , this . makeCallback ( resolve , reject ) ) ; } } ) ; } lstatSync ( p ) ; lstatSync ( p , opts ) ; lstatSync ( p , opts ? ) ; lstatSync ( p , opts ? ) { p = this . patchManifestPath ( p ) ; if ( opts ) { return this . realFs . lstatSync ( npath . fromPortablePath ( p ) , opts ) ; } else { return this . realFs . lstatSync ( npath . fromPortablePath ( p ) ) ; } } async chmodPromise ( p , mask ) { return await new Promise < void > ( ( resolve , reject ) => { p = this . patchManifestPath ( p ) ; this . realFs . chmod ( npath . fromPortablePath ( p ) , mask , this . makeCallback ( resolve , reject ) ) ; } ) ; } chmodSync ( p , mask ) { p = this . patchManifestPath ( p ) ; return this . realFs . chmodSync ( npath . fromPortablePath ( p ) , mask ) ; } async chownPromise ( p , uid , gid ) { return await new Promise < void > ( ( resolve , reject ) => { p = this . patchManifestPath ( p ) ; this . realFs . chown ( npath . fromPortablePath ( p ) , uid , gid , this . makeCallback ( resolve , reject ) ) ; } ) ; } chownSync ( p , uid , gid ) { p = this . patchManifestPath ( p ) ; return this . realFs . chownSync ( npath . fromPortablePath ( p ) , uid , gid ) ; } async renamePromise ( oldP , newP ) { this . cache . delete ( oldP ) ; this . cache . delete ( newP ) ; return await new Promise < void > ( ( resolve , reject ) => { this . realFs . rename ( npath . fromPortablePath ( oldP ) , npath . fromPortablePath ( newP ) , this . makeCallback ( resolve , reject ) ) ; } ) ; } renameSync ( oldP , newP ) { this . cache . delete ( oldP ) ; this . cache . delete ( newP ) ; return this . realFs . renameSync ( npath . fromPortablePath ( oldP ) , npath . fromPortablePath ( newP ) ) ; } async copyFilePromise ( sourceP , destP , flags = 0 ) { return await new Promise < void > ( ( resolve , reject ) => { this . realFs . copyFile ( npath . fromPortablePath ( sourceP ) , npath . fromPortablePath ( destP ) , flags , this . makeCallback ( resolve , reject ) ) ; } ) ; } copyFileSync ( sourceP , destP , flags = 0 ) { this . cache . delete ( sourceP ) ; this . cache . delete ( destP ) ; return this . realFs . copyFileSync ( npath . fromPortablePath ( sourceP ) , npath . fromPortablePath ( destP ) , flags ) ; } async appendFilePromise ( p , content , opts ? ) { p = this . patchManifestPath ( p as PortablePath ) ; return await new Promise < void > ( ( resolve , reject ) => { const fsNativePath = typeof p === `string` ? npath . fromPortablePath ( p ) : p ; if ( opts ) { this . realFs . appendFile ( fsNativePath , content as string | Uint8Array , opts as fs . WriteFileOptions , this . makeCallback ( resolve , reject ) ) ; } else { this . realFs . appendFile ( fsNativePath , content as string | Uint8Array , this . makeCallback ( resolve , reject ) ) ; } } ) ; } appendFileSync ( p , content , opts ? ) { const fsNativePath = typeof p === `string` ? npath . fromPortablePath ( p ) : p ; if ( opts ) { this . realFs . appendFileSync ( fsNativePath , content as string | Uint8Array , opts as fs . WriteFileOptions ) ; } else { this . realFs . appendFileSync ( fsNativePath , content as string | Uint8Array ) ; } } async writeFilePromise ( p , content , opts ? ) { await new Promise < void > ( ( resolve , reject ) => { p = this . patchManifestPath ( p as PortablePath ) ; const m = this . isPathForManifest ( p ) ; if ( m !== false ) { const success = this . writeManifestFile ( p , content , m , opts ) ; if ( success ) { resolve ( ) ; return ; } } const fsNativePath = typeof p === `string` ? npath . fromPortablePath ( p ) : p ; if ( opts ) { this . realFs . writeFile ( fsNativePath , content as string | NodeJS . ArrayBufferView , opts as fs . WriteFileOptions , this . makeCallback ( resolve , reject ) ) ; } else { this . realFs . writeFile ( fsNativePath , content as string | NodeJS . ArrayBufferView , this . makeCallback ( resolve , reject ) ) ; } } ) ; return ; } writeFileSync ( p , content , opts ? ) { p = this . patchManifestPath ( p as PortablePath ) ; const m = this . isPathForManifest ( p ) ; if ( m !== false ) { const success = this . writeManifestFile ( p , content , m , opts ) ; if ( success ) { return ; } } const fsNativePath = typeof p === `string` ? npath . fromPortablePath ( p ) : p ; if ( opts ) { return this . realFs . writeFileSync ( fsNativePath , content as string | NodeJS . ArrayBufferView , opts as fs . WriteFileOptions ) ; } else { return this . realFs . writeFileSync ( fsNativePath , content as string | NodeJS . ArrayBufferView ) ; } } async unlinkPromise ( p ) { p = this . patchManifestPath ( p ) ; return await new Promise < void > ( ( resolve , reject ) => { this . realFs . unlink ( npath . fromPortablePath ( p ) , this . makeCallback ( resolve , reject ) ) ; } ) ; } unlinkSync ( p ) { p = this . patchManifestPath ( p ) ; return this . realFs . unlinkSync ( npath . fromPortablePath ( p ) ) ; } async utimesPromise ( p , atime , mtime ) { return await new Promise < void > ( ( resolve , reject ) => { p = this . patchManifestPath ( p ) ; this . realFs . utimes ( npath . fromPortablePath ( p ) , atime , mtime , this . makeCallback ( resolve , reject ) ) ; } ) ; } utimesSync ( p , atime , mtime ) { p = this . patchManifestPath ( p ) ; this . realFs . utimesSync ( npath . fromPortablePath ( p ) , atime , mtime ) ; } async mkdirPromise ( p , opts ? ) { return await new Promise < void > ( ( resolve , reject ) => { this . realFs . mkdir ( npath . fromPortablePath ( p ) as fs . PathLike , opts as fs . Mode | ( fs . MakeDirectoryOptions & { recursive ? : false | undefined ; } ) , this . makeCallback ( resolve , reject ) ) ; } ) ; } mkdirSync ( p , opts ? ) { return this . realFs . mkdirSync ( npath . fromPortablePath ( p ) , opts ) ; } async rmdirPromise ( p , opts ? ) { this . cache . delete ( p ) ; return await new Promise < void > ( ( resolve , reject ) => { if ( opts ) { this . realFs . rmdir ( npath . fromPortablePath ( p ) , opts , this . makeCallback ( resolve , reject ) ) ; } else { this . realFs . rmdir ( npath . fromPortablePath ( p ) , this . makeCallback ( resolve , reject ) ) ; } } ) ; } rmdirSync ( p , opts ? ) { this . cache . delete ( p ) ; return this . realFs . rmdirSync ( npath . fromPortablePath ( p ) , opts ) ; } async linkPromise ( existingP , newP ) { return await new Promise < void > ( ( resolve , reject ) => { this . realFs . link ( npath . fromPortablePath ( existingP ) , npath . fromPortablePath ( newP ) , this . makeCallback ( resolve , reject ) ) ; } ) ; } linkSync ( existingP , newP ) { return this . realFs . linkSync ( npath . fromPortablePath ( existingP ) , npath . fromPortablePath ( newP ) ) ; } async symlinkPromise ( target , p , type ? ) { return await new Promise < void > ( ( resolve , reject ) => { this . realFs . symlink ( npath . fromPortablePath ( target . replace ( /\/+$/ , `` ) as PortablePath ) , npath . fromPortablePath ( p ) , type , this . makeCallback ( resolve , reject ) ) ; } ) ; } symlinkSync ( target , p , type ? ) { return this . realFs . symlinkSync ( npath . fromPortablePath ( target . replace ( /\/+$/ , `` ) as PortablePath ) , npath . fromPortablePath ( p ) , type ) ; } readFilePromise ( p , encoding ) ; readFilePromise ( p , encoding ? ) ; async readFilePromise ( p , encoding ? ) { return await new Promise < any > ( ( resolve , reject ) => { p = this . patchManifestPath ( p as PortablePath ) ; if ( this . isPathForManifest ( p ) ) { const manifest = this . readManifestFile ( p , encoding ) ; if ( manifest !== false ) { resolve ( manifest ) ; } } const fsNativePath = typeof p === `string` ? npath . fromPortablePath ( p ) : p ; this . realFs . readFile ( fsNativePath , encoding , this . makeCallback ( resolve , reject ) ) ; } ) ; } readFileSync ( p , encoding ) ; readFileSync ( p , encoding ? ) ; readFileSync ( p , encoding ? ) { p = this . patchManifestPath ( p as PortablePath ) ; if ( this . isPathForManifest ( p ) ) { const manifest = this . readManifestFile ( p , encoding ) ; if ( manifest !== false ) { return manifest ; } } const fsNativePath = typeof p === `string` ? npath . fromPortablePath ( p ) : p ; return this . realFs . readFileSync ( fsNativePath , encoding as BufferEncoding | ( fs . BaseEncodingOptions & { flag ? : string | undefined ; } ) | null | undefined ) ; } async readdirPromise ( p ) ; async readdirPromise ( p , opts ) ; async readdirPromise ( p , opts ) ; async readdirPromise ( p , opts ) ; async readdirPromise ( p , { withFileTypes } = { } ) { return await new Promise < Array < Filename > | Array < Dirent > > ( ( resolve , reject ) => { if ( withFileTypes ) { this . realFs . readdir ( npath . fromPortablePath ( p ) , { withFileTypes : true } , this . makeCallback ( resolve , reject ) as any ) ; } else { this . realFs . readdir ( npath . fromPortablePath ( p ) , this . makeCallback ( ( value ) => resolve ( value as Array < Filename > ) , reject ) ) ; } } ) ; } readdirSync ( p ) ; readdirSync ( p , opts ) ; readdirSync ( p , opts ) ; readdirSync ( p , opts ) ; readdirSync ( p , { withFileTypes } = { } ) { if ( withFileTypes ) { return this . realFs . readdirSync ( npath . fromPortablePath ( p ) , { withFileTypes : true , } as any ) ; } else { return this . realFs . readdirSync ( npath . fromPortablePath ( p ) ) as Array < Filename > ; } } async readlinkPromise ( p ) { return await new Promise < string > ( ( resolve , reject ) => { this . realFs . readlink ( npath . fromPortablePath ( p ) , this . makeCallback ( resolve , reject ) ) ; } ) . then ( ( path ) => { return npath . toPortablePath ( path ) ; } ) ; } readlinkSync ( p ) { return npath . toPortablePath ( this . realFs . readlinkSync ( npath . fromPortablePath ( p ) ) ) ; } async truncatePromise ( p , len ? ) { return await new Promise < void > ( ( resolve , reject ) => { this . realFs . truncate ( npath . fromPortablePath ( p ) , len , this . makeCallback ( resolve , reject ) ) ; } ) ; } truncateSync ( p , len ? ) { return this . realFs . truncateSync ( npath . fromPortablePath ( p ) , len ) ; } watch ( p , cb ? ) ; watch ( p , opts , cb ? ) ; watch ( p , a ? , b ? ) { p = this . patchManifestPath ( p ) ; return this . realFs . watch ( npath . fromPortablePath ( p ) , a , b ) ; } watchFile ( p , cb ) ; watchFile ( p , opts , cb ) ; watchFile ( p , a , b ? ) { p = this . patchManifestPath ( p ) ; return this . realFs . watchFile ( npath . fromPortablePath ( p ) , a , b ) as unknown as StatWatcher ; } unwatchFile ( p , cb ? ) { p = this . patchManifestPath ( p ) ; return this . realFs . unwatchFile ( npath . fromPortablePath ( p ) , cb ) ; } private makeCallback < T > ( resolve , reject ) { return ( err , result ) => { if ( err ) { reject ( err ) ; } else { resolve ( result ) ; } } ; } }