import * as pathConsts from '../../../common/pathConsts' ; import { combinePaths , getDirectoryPath , normalizeSlashes , resolvePaths } from '../../../common/pathUtils' ; import { GlobalMetadataOptionNames } from '../fourslash/fourSlashTypes' ; import { TestHost } from '../testHost' ; import { bufferFrom } from '../utils' ; import { FileSet , FileSystemOptions , FileSystemResolver , MODULE_PATH , Mount , S_IFDIR , S_IFREG , TestFileSystem , } from './filesystem' ; export class TextDocument { readonly meta : Map < string , string > ; readonly file : string ; readonly text : string ; constructor ( file , text , meta ? ) { this . file = file ; this . text = text ; this . meta = meta || new Map < string , string > ( ) ; } } export interface FileSystemCreateOptions extends FileSystemOptions { documents ? : readonly TextDocument [ ] ; } export const libFolder = combinePaths ( MODULE_PATH , normalizeSlashes ( combinePaths ( pathConsts . lib , pathConsts . sitePackages ) ) ) ; export const distlibFolder = combinePaths ( MODULE_PATH , normalizeSlashes ( combinePaths ( pathConsts . lib , pathConsts . distPackages ) ) ) ; export const typeshedFolder = combinePaths ( MODULE_PATH , normalizeSlashes ( pathConsts . typeshedFallback ) ) ; export const srcFolder = normalizeSlashes ( '/.src' ) ; param host param ignoreCase param documents param files param cwd param time param meta export function createFromFileSystem ( host , ignoreCase , { documents , files , cwd , time , meta } = { } , mountPaths = new Map < string , string > ( ) ) { const typeshedPath = meta ? meta [ GlobalMetadataOptionNames . typeshed ] : undefined ; if ( typeshedPath ) { mountPaths . set ( typeshedFolder , typeshedPath ) ; } const fs = getBuiltLocal ( host , ignoreCase , cwd , mountPaths ) . shadow ( ) ; if ( meta ) { for ( const key of Object . keys ( meta ) ) { fs . meta . set ( key , meta [ key ] ) ; } } if ( time ) { fs . time ( time ) ; } if ( cwd ) { fs . mkdirpSync ( cwd ) ; fs . chdir ( cwd ) ; } if ( documents ) { for ( const document of documents ) { fs . mkdirpSync ( getDirectoryPath ( document . file ) ) ; fs . writeFileSync ( document . file , document . text , 'utf8' ) ; fs . filemeta ( document . file ) . set ( 'document' , document ) ; const symlink = document . meta . get ( 'symlink' ) ; if ( symlink ) { for ( const link of symlink . split ( ',' ) . map ( ( link ) => link . trim ( ) ) ) { fs . mkdirpSync ( getDirectoryPath ( link ) ) ; fs . symlinkSync ( resolvePaths ( fs . cwd ( ) , document . file ) , link ) ; } } } } if ( files ) { fs . apply ( files ) ; } return fs ; } let cacheKey ; let localCIFSCache ; let localCSFSCache ; function getBuiltLocal ( host , ignoreCase , cwd , mountPaths ) { if ( ! mountPaths . has ( typeshedFolder ) ) { mountPaths . set ( typeshedFolder , resolvePaths ( host . getWorkspaceRoot ( ) , pathConsts . typeshedFallback ) ) ; } if ( ! canReuseCache ( host , mountPaths ) ) { localCIFSCache = undefined ; localCSFSCache = undefined ; cacheKey = { host , mountPaths } ; } if ( ! localCIFSCache ) { const resolver = createResolver ( host ) ; const files = { } ; mountPaths . forEach ( ( v , k ) => ( files [ k ] = new Mount ( v , resolver ) ) ) ; localCIFSCache = new TestFileSystem ( true , { files , cwd , meta : { } , } ) ; localCIFSCache . makeReadonly ( ) ; } if ( ignoreCase ) { return localCIFSCache ; } if ( ! localCSFSCache ) { localCSFSCache = localCIFSCache . shadow ( false ) ; localCSFSCache . makeReadonly ( ) ; } return localCSFSCache ; } function canReuseCache ( host , mountPaths ) { if ( cacheKey === undefined ) { return false ; } if ( cacheKey . host !== host ) { return false ; } if ( cacheKey . mountPaths . size !== mountPaths . size ) { return false ; } for ( const key of cacheKey . mountPaths . keys ( ) ) { if ( cacheKey . mountPaths . get ( key ) !== mountPaths . get ( key ) ) { return false ; } } return true ; } function createResolver ( host ) { return { readdirSync ( path ) { const { files , directories } = host . getAccessibleFileSystemEntries ( path ) ; return directories . concat ( files ) ; } , statSync ( path ) { if ( host . directoryExists ( path ) ) { return { mode : S_IFDIR | 0o777 , size : 0 } ; } else if ( host . fileExists ( path ) ) { return { mode : S_IFREG | 0o666 , size : host . getFileSize ( path ) } ; } else { throw new Error ( 'ENOENT: path does not exist' ) ; } } , readFileSync ( path ) { return bufferFrom ( host . readFile ( path ) ! , 'utf8' ) ; } , } ; }