namespace ts . server { export interface HostWithWriteMessage { writeMessage ( s ) : void ; } export interface WebHost extends HostWithWriteMessage { readFile ( path ) : string | undefined ; fileExists ( path ) : boolean ; } export class BaseLogger implements Logger { private seq = 0 ; private inGroup = false ; private firstInGroup = true ; constructor ( protected readonly level ) { } static padStringRight ( str , padding ) { return ( str + padding ) . slice ( 0 , padding . length ) ; } close ( ) { } getLogFileName ( ) { return undefined ; } perftrc ( s ) { this . msg ( s , Msg . Perf ) ; } info ( s ) { this . msg ( s , Msg . Info ) ; } err ( s ) { this . msg ( s , Msg . Err ) ; } startGroup ( ) { this . inGroup = true ; this . firstInGroup = true ; } endGroup ( ) { this . inGroup = false ; } loggingEnabled ( ) { return true ; } hasLevel ( level ) { return this . loggingEnabled ( ) && this . level >= level ; } msg ( s , type = Msg . Err ) { switch ( type ) { case Msg . Info : perfLogger . logInfoEvent ( s ) ; break ; case Msg . Perf : perfLogger . logPerfEvent ( s ) ; break ; default : perfLogger . logErrEvent ( s ) ; break ; } if ( ! this . canWrite ( ) ) return ; s = `[${ nowString ( ) }] ${ s }\n` ; if ( ! this . inGroup || this . firstInGroup ) { const prefix = BaseLogger . padStringRight ( type + " " + this . seq . toString ( ) , "          " ) ; s = prefix + s ; } this . write ( s , type ) ; if ( ! this . inGroup ) { this . seq ++ ; } } protected canWrite ( ) { return true ; } protected write ( _s , _type ) { } } export type MessageLogLevel = "info" | "perf" | "error" ; export interface LoggingMessage { readonly type : "log" ; readonly level : MessageLogLevel ; readonly body : string ; } export class MainProcessLogger extends BaseLogger { constructor ( level , private host ) { super ( level ) ; } protected write ( body , type ) { let level ; switch ( type ) { case Msg . Info : level = "info" ; break ; case Msg . Perf : level = "perf" ; break ; case Msg . Err : level = "error" ; break ; default : Debug . assertNever ( type ) ; } this . host . writeMessage ( { type : "log" , level , body , } as LoggingMessage ) ; } } export function createWebSystem ( host , args , getExecutingFilePath ) { const returnEmptyString = ( ) => "" ; const getExecutingDirectoryPath = memoize ( ( ) => memoize ( ( ) => ensureTrailingDirectorySeparator ( getDirectoryPath ( getExecutingFilePath ( ) ) ) ) ) ; const getWebPath = ( path ) => startsWith ( path , directorySeparator ) ? path . replace ( directorySeparator , getExecutingDirectoryPath ( ) ) : undefined ; return { args , newLine : "\r\n" , useCaseSensitiveFileNames : false , readFile : path => { const webPath = getWebPath ( path ) ; return webPath && host . readFile ( webPath ) ; } , write : host . writeMessage . bind ( host ) , watchFile : returnNoopFileWatcher , watchDirectory : returnNoopFileWatcher , getExecutingFilePath : ( ) => directorySeparator , getCurrentDirectory : returnEmptyString , setTimeout : ( cb , ms , ... args ) => setTimeout ( cb , ms , ... args ) , clearTimeout : handle => clearTimeout ( handle ) , setImmediate : x => setTimeout ( x , 0 ) , clearImmediate : handle => clearTimeout ( handle ) , require : ( ) => ( { module : undefined , error : new Error ( "Not implemented" ) } ) , exit : notImplemented , getEnvironmentVariable : returnEmptyString , fileExists : path => { const webPath = getWebPath ( path ) ; return ! ! webPath && host . fileExists ( webPath ) ; } , directoryExists : returnFalse , readDirectory : notImplemented , getDirectories : ( ) => [ ] , createDirectory : notImplemented , writeFile : notImplemented , resolvePath : identity , } ; } export interface StartSessionOptions { globalPlugins : SessionOptions [ "globalPlugins" ] ; pluginProbeLocations : SessionOptions [ "pluginProbeLocations" ] ; allowLocalPluginLoads : SessionOptions [ "allowLocalPluginLoads" ] ; useSingleInferredProject : SessionOptions [ "useSingleInferredProject" ] ; useInferredProjectPerProjectRoot : SessionOptions [ "useInferredProjectPerProjectRoot" ] ; suppressDiagnosticEvents : SessionOptions [ "suppressDiagnosticEvents" ] ; noGetErrOnBackgroundUpdate : SessionOptions [ "noGetErrOnBackgroundUpdate" ] ; syntaxOnly : SessionOptions [ "syntaxOnly" ] ; serverMode : SessionOptions [ "serverMode" ] ; } export class WorkerSession extends Session < { } > { constructor ( host , private webHost , options , logger , cancellationToken , hrtime ) { super ( { host , cancellationToken , ... options , typingsInstaller : nullTypingsInstaller , byteLength : notImplemented , hrtime , logger , canUseEvents : true , } ) ; } public send ( msg ) { if ( msg . type === "event" && ! this . canUseEvents ) { if ( this . logger . hasLevel ( LogLevel . verbose ) ) { this . logger . info ( `Session does not support events: ignored event: ${ JSON . stringify ( msg ) }` ) ; } return ; } if ( this . logger . hasLevel ( LogLevel . verbose ) ) { this . logger . info ( `${ msg . type }:${ indent ( JSON . stringify ( msg ) ) }` ) ; } this . webHost . writeMessage ( msg ) ; } protected parseMessage ( message ) { return message as protocol . Request ; } protected toStringMessage ( message ) { return JSON . stringify ( message , undefined , 2 ) ; } } }