import os from 'os' ; import path from 'path' ; import invariant from 'tiny-invariant' ; import ts from 'typescript' ; import { parentPort } from 'worker_threads' ; import { Checker } from '../../Checker' ; import { consoleLog , diagnosticToTerminalLog , diagnosticToViteError , ensureCall , normalizeTsDiagnostic , } from '../../logger' ; import { ACTION_TYPES , CreateDiagnostic } from '../../types' ; import type { ErrorPayload } from 'vite' ; const createDiagnostic = ( pluginConfig ) => { let overlay = true ; let currErr = null ; return { config : ( { hmr } ) => { const viteOverlay = ! ( typeof hmr === 'object' && hmr . overlay === false ) ; if ( pluginConfig . overlay === false || ! viteOverlay ) { overlay = false ; } } , configureServer ( { root } ) { invariant ( pluginConfig . typescript , 'config.typescript should be `false`' ) ; const finalConfig = pluginConfig . typescript === true ? { root , tsconfigPath : 'tsconfig.json' } : { root : pluginConfig . typescript . root ?? root , tsconfigPath : pluginConfig . typescript . tsconfigPath ?? 'tsconfig.json' , } ; let configFile ; configFile = ts . findConfigFile ( finalConfig . root , ts . sys . fileExists , finalConfig . tsconfigPath ) ; if ( configFile === undefined ) { throw Error ( `Failed to find a valid tsconfig.json: ${ finalConfig . tsconfigPath } at ${ finalConfig . root } is not a valid tsconfig` ) ; } let logChunk = '' ; const reportDiagnostic = ( diagnostic ) => { const formattedDiagnostics = normalizeTsDiagnostic ( diagnostic ) ; if ( ! currErr ) { currErr = diagnosticToViteError ( formattedDiagnostics ) ; } logChunk += os . EOL + diagnosticToTerminalLog ( formattedDiagnostics , 'TypeScript' ) ; } ; const reportWatchStatusChanged = ( diagnostic , newLine , options , errorCount ) => { if ( diagnostic . code === 6031 ) return ; switch ( diagnostic . code ) { case 6031 : case 6032 : logChunk = '' ; currErr = null ; return ; case 6193 : case 6194 : if ( overlay ) { parentPort ?. postMessage ( { type : ACTION_TYPES . overlayError , payload : currErr ? { type : 'error' , err : currErr , } : null , } ) ; } } ensureCall ( ( ) => { if ( errorCount === 0 ) { logChunk = '' ; } consoleLog ( logChunk + os . EOL + diagnostic . messageText . toString ( ) ) ; } ) ; } ; const createProgram = ts . createEmitAndSemanticDiagnosticsBuilderProgram ; const host = ts . createWatchCompilerHost ( configFile , { noEmit : true } , ts . sys , createProgram , reportDiagnostic , reportWatchStatusChanged ) ; ts . createWatchProgram ( host ) ; } , } ; } ; export class TscChecker extends Checker < 'typescript' > { public constructor ( ) { super ( { name : 'typescript' , absFilePath : __filename , build : { buildBin : ( config ) => { if ( typeof config . typescript === 'object' ) { const { root , tsconfigPath , buildMode } = config . typescript ; let args = [ buildMode ? '-b' : '--noEmit' ] ; if ( tsconfigPath ) { const fullConfigPath = root ? path . join ( root , tsconfigPath ) : tsconfigPath ; args = args . concat ( [ '-p' , fullConfigPath ] ) ; } return [ 'tsc' , args ] ; } return [ 'tsc' , [ '--noEmit' ] ] ; } , } , createDiagnostic , } ) ; } public init ( ) { const createServeAndBuild = super . initMainThread ( ) ; module . exports . createServeAndBuild = createServeAndBuild ; super . initWorkerThread ( ) ; } } const tscChecker = new TscChecker ( ) ; tscChecker . prepare ( ) ; tscChecker . init ( ) ;