import { relative , resolve } from 'path' ; import ts from 'typescript' ; import { logTypeScriptError } from './logger.js' ; const formatHost = { getCanonicalFileName : path => path , getCurrentDirectory : ts . sys . getCurrentDirectory , getNewLine : ( ) => ts . sys . newLine , } ; interface ICompileAndWatch { projectDir : string ; onStart ? : ( ) => void ; onFileChanged ? : ( ) => void ; onCompilationFailed ? : ( message : string , error : ts . Diagnostic ) => void ; onCompilationDone ? : ( ) => void ; } const noop = function ( ) { } ; export function compileAndWatch ( { projectDir , onStart = noop , onFileChanged = noop , onCompilationFailed = noop , onCompilationDone = noop , } ) { const tsConfigPath = resolve ( projectDir , 'tsconfig.json' ) ; if ( ! ts . sys . fileExists ( tsConfigPath ) ) { ts . sys . writeFile ( tsConfigPath , JSON . stringify ( { compilerOptions : { allowJs : true , target : 'esnext' , esModuleInterop : true , moduleResolution : 'node' , } } , undefined , 2 ) ) ; } const createProgram = ts . createSemanticDiagnosticsBuilderProgram ; const host = ts . createWatchCompilerHost ( tsConfigPath , { allowJs : true , outDir : '.glee' , rootDir : projectDir , } , ts . sys , createProgram , reportDiagnostic , onWatchStatusChanged ) ; const origCreateProgram = host . createProgram ; host . createProgram = ( rootNames , options , host , oldProgram ) => { return origCreateProgram ( rootNames , options , host , oldProgram ) ; } ; const origPostProgramCreate = host . afterProgramCreate ; host . afterProgramCreate = program => { origPostProgramCreate ( program ) ; } ; ts . createWatchProgram ( host ) ; function reportDiagnostic ( diagnostic ) { const fileName = relative ( process . cwd ( ) , diagnostic . file . getSourceFile ( ) . fileName ) ; const { line , character } = diagnostic . file . getLineAndCharacterOfPosition ( diagnostic . start ) ; logTypeScriptError ( diagnostic . code , ts . flattenDiagnosticMessageText ( diagnostic . messageText , formatHost . getNewLine ( ) ) , fileName , line , character ) ; } function onWatchStatusChanged ( diagnostic , newLine , options , errorCount ? ) { switch ( diagnostic . code ) { case 6031 : return onStart ( ) ; case 6032 : return onFileChanged ( ) ; case 6194 : if ( errorCount === 0 ) { return onCompilationDone ( ) ; } return onCompilationFailed ( ts . flattenDiagnosticMessageText ( diagnostic . messageText , ts . sys . newLine ) , diagnostic ) ; } } }