import type * as fs from 'fs' ; import { getOrAdd } from './common/collectionUtils' ; import { FileSystem , FileWatcher , FileWatcherEventHandler , MkDirOptions , Stats , TmpfileOptions , VirtualDirent , } from './common/fileSystem' ; import { combinePaths , ensureTrailingDirectorySeparator , getDirectoryPath , getFileName } from './common/pathUtils' ; export class ReadOnlyAugmentedFileSystem implements FileSystem { private readonly _entryMap = new Map < string , string > ( ) ; private readonly _reverseEntryMap = new Map < string , string > ( ) ; private readonly _folderMap = new Map < string , { name : string ; isFile : boolean ; } [ ] > ( ) ; constructor ( protected _realFS ) { } existsSync ( path ) { if ( this . _isMovedEntry ( path ) ) { return false ; } return this . _realFS . existsSync ( this . _getOriginalPath ( path ) ) ; } mkdirSync ( path , options ? ) { throw new Error ( 'Operation is not allowed.' ) ; } chdir ( path ) { throw new Error ( 'Operation is not allowed.' ) ; } readdirEntriesSync ( path ) { const maybeDirectory = ensureTrailingDirectorySeparator ( path ) ; const entries = [ ] ; const movedEntries = this . _folderMap . get ( maybeDirectory ) ; if ( ! movedEntries || this . _realFS . existsSync ( path ) ) { entries . push ( ... this . _realFS . readdirEntriesSync ( path ) . filter ( ( item ) => { return ! this . _isMovedEntry ( combinePaths ( path , item . name ) ) ; } ) ) ; } if ( ! movedEntries ) { return entries ; } return entries . concat ( movedEntries . map ( ( e ) => new VirtualDirent ( e . name , e . isFile ) ) ) ; } readdirSync ( path ) { return this . readdirEntriesSync ( path ) . map ( ( p ) => p . name ) ; } readFileSync ( path , encoding ? ) ; readFileSync ( path , encoding ) ; readFileSync ( path , encoding ? ) { return this . _realFS . readFileSync ( this . _getOriginalPath ( path ) , encoding ) ; } writeFileSync ( path , data , encoding ) { throw new Error ( 'Operation is not allowed.' ) ; } statSync ( path ) { return this . _realFS . statSync ( this . _getOriginalPath ( path ) ) ; } unlinkSync ( path ) { throw new Error ( 'Operation is not allowed.' ) ; } realpathSync ( path ) { if ( this . _entryMap . has ( path ) ) { return path ; } return this . _realFS . realpathSync ( path ) ; } getModulePath ( ) { return this . _realFS . getModulePath ( ) ; } createFileSystemWatcher ( paths , listener ) { return this . _realFS . createFileSystemWatcher ( paths , listener ) ; } createReadStream ( path ) { return this . _realFS . createReadStream ( this . _getOriginalPath ( path ) ) ; } createWriteStream ( path ) { throw new Error ( 'Operation is not allowed.' ) ; } copyFileSync ( src , dst ) { throw new Error ( 'Operation is not allowed.' ) ; } readFile ( path ) { return this . _realFS . readFile ( this . _getOriginalPath ( path ) ) ; } readFileText ( path , encoding ? ) { return this . _realFS . readFileText ( this . _getOriginalPath ( path ) , encoding ) ; } tmpdir ( ) { return this . _realFS . tmpdir ( ) ; } tmpfile ( options ? ) { return this . _realFS . tmpfile ( options ) ; } realCasePath ( path ) { return this . _realFS . realCasePath ( path ) ; } getUri ( originalPath ) { return this . _realFS . getUri ( originalPath ) ; } isMappedFilePath ( filepath ) { return this . _entryMap . has ( filepath ) || this . _realFS . isMappedFilePath ( filepath ) ; } getOriginalFilePath ( mappedFilePath ) { return this . _realFS . getOriginalFilePath ( this . _getOriginalPath ( mappedFilePath ) ) ; } getMappedFilePath ( originalFilepath ) { const mappedFilePath = this . _realFS . getMappedFilePath ( originalFilepath ) ; return this . _reverseEntryMap . get ( mappedFilePath ) ?? mappedFilePath ; } isInZipOrEgg ( path ) { return this . _realFS . isInZipOrEgg ( path ) ; } protected _recordMovedEntry ( mappedPath , originalPath , reversible = true , isFile = true ) { this . _entryMap . set ( mappedPath , originalPath ) ; if ( reversible ) { this . _reverseEntryMap . set ( originalPath , mappedPath ) ; } const directory = ensureTrailingDirectorySeparator ( getDirectoryPath ( mappedPath ) ) ; const folderInfo = getOrAdd ( this . _folderMap , directory , ( ) => [ ] ) ; const name = getFileName ( mappedPath ) ; if ( ! folderInfo . some ( ( entry ) => entry . name === name ) ) { folderInfo . push ( { name , isFile } ) ; } } protected _getOriginalPath ( mappedFilePath ) { return this . _entryMap . get ( mappedFilePath ) ?? mappedFilePath ; } protected _isMovedEntry ( path ) { return this . _reverseEntryMap . has ( path ) ; } protected _clear ( ) { this . _entryMap . clear ( ) ; this . _reverseEntryMap . clear ( ) ; this . _folderMap . clear ( ) ; } }