2016-10-20 12:31:17 +00:00
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Copyright ( c ) Microsoft Corporation . All rights reserved .
* Licensed under the MIT License . See License . txt in the project root for license information .
* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- * /
import * as es from 'event-stream' ;
import * as _ from 'underscore' ;
2019-02-05 21:21:05 +00:00
import * as fancyLog from 'fancy-log' ;
import * as ansiColors from 'ansi-colors' ;
2017-02-08 10:05:50 +00:00
import * as fs from 'fs' ;
import * as path from 'path' ;
2016-10-20 12:31:17 +00:00
2020-11-20 13:06:37 +00:00
class ErrorLog {
constructor ( public id : string ) {
}
allErrors : string [ ] [ ] = [ ] ;
startTime : number | null = null ;
count = 0 ;
onStart ( ) : void {
if ( this . count ++ > 0 ) {
return ;
}
2016-10-20 12:31:17 +00:00
2020-11-20 13:06:37 +00:00
this . startTime = new Date ( ) . getTime ( ) ;
fancyLog ( ` Starting ${ ansiColors . green ( 'compilation' ) } ${ this . id ? ansiColors . blue ( ` ${ this . id } ` ) : '' } ... ` ) ;
2016-10-20 12:31:17 +00:00
}
2020-11-20 13:06:37 +00:00
onEnd ( ) : void {
if ( -- this . count > 0 ) {
return ;
}
2016-10-20 12:31:17 +00:00
2020-11-20 13:06:37 +00:00
this . log ( ) ;
2016-10-20 12:31:17 +00:00
}
2020-11-20 13:06:37 +00:00
log ( ) : void {
const errors = _ . flatten ( this . allErrors ) ;
const seen = new Set < string > ( ) ;
2016-11-29 14:53:32 +00:00
2020-11-20 13:06:37 +00:00
errors . map ( err = > {
if ( ! seen . has ( err ) ) {
seen . add ( err ) ;
fancyLog ( ` ${ ansiColors . red ( 'Error' ) } : ${ err } ` ) ;
}
} ) ;
2017-02-08 10:05:50 +00:00
2020-11-20 13:06:37 +00:00
fancyLog ( ` Finished ${ ansiColors . green ( 'compilation' ) } ${ this . id ? ansiColors . blue ( ` ${ this . id } ` ) : '' } with ${ errors . length } errors after ${ ansiColors . magenta ( ( new Date ( ) . getTime ( ) - this . startTime ! ) + ' ms' ) } ` ) ;
2017-02-08 10:05:50 +00:00
2020-11-20 13:06:37 +00:00
const regex = / ^ ( [ ^ ( ] + ) \ ( ( \ d + ) , ( \ d + ) \ ) : ( . * ) $ / s ;
const messages = errors
. map ( err = > regex . exec ( err ) )
. filter ( match = > ! ! match )
. map ( x = > x as string [ ] )
. map ( ( [ , path , line , column , message ] ) = > ( { path , line : parseInt ( line ) , column : parseInt ( column ) , message } ) ) ;
2018-04-05 08:00:50 +00:00
2020-11-20 13:06:37 +00:00
try {
const logFileName = 'log' + ( this . id ? ` _ ${ this . id } ` : '' ) ;
fs . writeFileSync ( path . join ( buildLogFolder , logFileName ) , JSON . stringify ( messages ) ) ;
} catch ( err ) {
//noop
2018-04-05 08:00:50 +00:00
}
2020-11-20 13:06:37 +00:00
}
2017-02-08 10:05:50 +00:00
2020-11-20 13:06:37 +00:00
}
2017-02-08 10:06:15 +00:00
2020-11-20 13:06:37 +00:00
const errorLogsById = new Map < string , ErrorLog > ( ) ;
function getErrorLog ( id : string = '' ) {
let errorLog = errorLogsById . get ( id ) ;
if ( ! errorLog ) {
errorLog = new ErrorLog ( id ) ;
errorLogsById . set ( id , errorLog ) ;
2017-02-08 10:06:15 +00:00
}
2020-11-20 13:06:37 +00:00
return errorLog ;
}
2017-02-08 10:05:50 +00:00
2020-11-20 13:06:37 +00:00
const buildLogFolder = path . join ( path . dirname ( path . dirname ( __dirname ) ) , '.build' ) ;
try {
fs . mkdirSync ( buildLogFolder ) ;
} catch ( err ) {
// ignore
2016-10-20 12:31:17 +00:00
}
export interface IReporter {
2018-04-05 08:00:50 +00:00
( err : string ) : void ;
2016-10-20 12:31:17 +00:00
hasErrors ( ) : boolean ;
2016-11-29 14:53:32 +00:00
end ( emitError : boolean ) : NodeJS . ReadWriteStream ;
2016-10-20 12:31:17 +00:00
}
2020-11-20 13:06:37 +00:00
export function createReporter ( id? : string ) : IReporter {
const errorLog = getErrorLog ( id ) ;
2018-04-05 08:00:50 +00:00
const errors : string [ ] = [ ] ;
2020-11-20 13:06:37 +00:00
errorLog . allErrors . push ( errors ) ;
2016-10-20 12:31:17 +00:00
2018-10-14 15:59:27 +00:00
const result = ( err : string ) = > errors . push ( err ) ;
2016-10-20 12:31:17 +00:00
2018-10-14 15:59:27 +00:00
result . hasErrors = ( ) = > errors . length > 0 ;
2016-10-20 12:31:17 +00:00
2018-10-14 15:59:27 +00:00
result . end = ( emitError : boolean ) : NodeJS . ReadWriteStream = > {
errors . length = 0 ;
2020-11-20 13:06:37 +00:00
errorLog . onStart ( ) ;
2016-10-20 12:31:17 +00:00
2018-10-14 15:59:27 +00:00
return es . through ( undefined , function ( ) {
2020-11-20 13:06:37 +00:00
errorLog . onEnd ( ) ;
2016-10-20 12:31:17 +00:00
2018-10-14 15:59:27 +00:00
if ( emitError && errors . length > 0 ) {
if ( ! ( errors as any ) . __logged__ ) {
2020-11-20 13:06:37 +00:00
errorLog . log ( ) ;
2018-10-14 15:59:27 +00:00
}
2018-04-23 13:58:32 +00:00
2018-10-14 15:59:27 +00:00
( errors as any ) . __logged__ = true ;
2018-09-26 12:55:03 +00:00
2018-10-14 15:59:27 +00:00
const err = new Error ( ` Found ${ errors . length } errors ` ) ;
( err as any ) . __reporter__ = true ;
this . emit ( 'error' , err ) ;
} else {
this . emit ( 'end' ) ;
}
} ) ;
} ;
2016-10-20 12:31:17 +00:00
2018-10-14 15:59:27 +00:00
return result ;
2018-04-05 08:00:50 +00:00
}