import * as os from 'os' ; import * as pathModule from 'path' ; import { NullConsole } from '../../common/console' ; import { combinePaths , directoryExists , fileExists , FileSystemEntries , getFileSize , resolvePaths , } from '../../common/pathUtils' ; import { createFromRealFileSystem } from '../../common/realFileSystem' ; import { compareStringsCaseInsensitive , compareStringsCaseSensitive } from '../../common/stringUtils' ; export const HOST = createHost ( ) ; export interface TestHost { useCaseSensitiveFileNames ( ) : boolean ; getAccessibleFileSystemEntries ( dirname ) : FileSystemEntries ; directoryExists ( path ) : boolean ; fileExists ( fileName ) : boolean ; getFileSize ( path ) : number ; readFile ( path ) : string | undefined ; getWorkspaceRoot ( ) : string ; writeFile ( path , contents ) : void ; listFiles ( path , filter ? , options ? ) : string [ ] ; log ( text ) : void ; } function createHost ( ) { const byteOrderMarkIndicator = '\uFEFF' ; const vfs = createFromRealFileSystem ( new NullConsole ( ) ) ; const useCaseSensitiveFileNames = isFileSystemCaseSensitive ( ) ; function isFileSystemCaseSensitive ( ) { const platform = os . platform ( ) ; if ( platform === 'win32' ) { return false ; } return ! vfs . existsSync ( swapCase ( __filename ) ) ; /** Convert all lowercase chars to uppercase, and vice-versa */ function swapCase ( s ) { return s . replace ( /\w/g , ( ch ) => { const up = ch . toUpperCase ( ) ; return ch === up ? ch . toLowerCase ( ) : up ; } ) ; } } function listFiles ( path , spec , options = { } ) { function filesInFolder ( folder ) { let paths = [ ] ; for ( const file of vfs . readdirSync ( folder ) ) { const pathToFile = pathModule . join ( folder , file ) ; const stat = vfs . statSync ( pathToFile ) ; if ( options . recursive && stat . isDirectory ( ) ) { paths = paths . concat ( filesInFolder ( pathToFile ) ) ; } else if ( stat . isFile ( ) && ( ! spec || file . match ( spec ) ) ) { paths . push ( pathToFile ) ; } } return paths ; } return filesInFolder ( path ) ; } function getAccessibleFileSystemEntries ( dirname ) { try { const entries = vfs . readdirSync ( dirname || '.' ) . sort ( useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive ) ; const files = [ ] ; const directories = [ ] ; for ( const entry of entries ) { if ( entry === '.' || entry === '..' ) { continue ; } const name = combinePaths ( dirname , entry ) ; try { const stat = vfs . statSync ( name ) ; if ( ! stat ) { continue ; } if ( stat . isFile ( ) ) { files . push ( entry ) ; } else if ( stat . isDirectory ( ) ) { directories . push ( entry ) ; } } catch { } } return { files , directories } ; } catch ( e ) { return { files : [ ] , directories : [ ] } ; } } function readFile ( fileName , _encoding ? ) { if ( ! fileExists ( vfs , fileName ) ) { return undefined ; } const buffer = vfs . readFileSync ( fileName ) ; let len = buffer . length ; if ( len >= 2 && buffer [ 0 ] === 0xfe && buffer [ 1 ] === 0xff ) { len &= ~ 1 ; for ( let i = 0 ; i < len ; i += 2 ) { const temp = buffer [ i ] ; buffer [ i ] = buffer [ i + 1 ] ; buffer [ i + 1 ] = temp ; } return buffer . toString ( 'utf16le' , 2 ) ; } if ( len >= 2 && buffer [ 0 ] === 0xff && buffer [ 1 ] === 0xfe ) { return buffer . toString ( 'utf16le' , 2 ) ; } if ( len >= 3 && buffer [ 0 ] === 0xef && buffer [ 1 ] === 0xbb && buffer [ 2 ] === 0xbf ) { return buffer . toString ( 'utf8' , 3 ) ; } return buffer . toString ( 'utf8' ) ; } function writeFile ( fileName , data , writeByteOrderMark ? ) { if ( writeByteOrderMark ) { data = byteOrderMarkIndicator + data ; } vfs . writeFileSync ( fileName , data , 'utf8' ) ; } return { useCaseSensitiveFileNames : ( ) => useCaseSensitiveFileNames , getFileSize : ( path ) => getFileSize ( vfs , path ) , readFile : ( path ) => readFile ( path ) , writeFile : ( path , content ) => { writeFile ( path , content ) ; } , fileExists : ( path ) => fileExists ( vfs , path ) , directoryExists : ( path ) => directoryExists ( vfs , path ) , listFiles , log : ( s ) => { console . log ( s ) ; } , getWorkspaceRoot : ( ) => resolvePaths ( __dirname , '../../..' ) , getAccessibleFileSystemEntries , } ; }