license fileoverview suppress const NEWLINE = '\n' ; const IGNORE_FRAMES = { } ; const creationTrace = '__creationTrace__' ; const ERROR_TAG = 'STACKTRACE TRACKING' ; const SEP_TAG = '__SEP_TAG__' ; let sepTemplate = SEP_TAG + '@[native]' ; class LongStackTrace { error : Error = getStacktrace ( ) ; timestamp : Date = new Date ( ) ; } function getStacktraceWithUncaughtError ( ) { return new Error ( ERROR_TAG ) ; } function getStacktraceWithCaughtError ( ) { try { throw getStacktraceWithUncaughtError ( ) ; } catch ( err ) { return err ; } } const error = getStacktraceWithUncaughtError ( ) ; const caughtError = getStacktraceWithCaughtError ( ) ; const getStacktrace = error . stack ? getStacktraceWithUncaughtError : ( caughtError . stack ? getStacktraceWithCaughtError : getStacktraceWithUncaughtError ) ; function getFrames ( error ) { return error . stack ? error . stack . split ( NEWLINE ) : [ ] ; } function addErrorStack ( lines , error ) { let trace = getFrames ( error ) ; for ( let i = 0 ; i < trace . length ; i ++ ) { const frame = trace [ i ] ; if ( ! IGNORE_FRAMES . hasOwnProperty ( frame ) ) { lines . push ( trace [ i ] ) ; } } } function renderLongStackTrace ( frames , stack ? ) { const longTrace = [ stack ? stack . trim ( ) : '' ] ; if ( frames ) { let timestamp = new Date ( ) . getTime ( ) ; for ( let i = 0 ; i < frames . length ; i ++ ) { const traceFrames = frames [ i ] ; const lastTime = traceFrames . timestamp ; let separator = `____________________Elapsed ${ timestamp - lastTime . getTime ( ) } ms; At: ${ lastTime }` ; separator = separator . replace ( /[^\w\d]/g , '_' ) ; longTrace . push ( sepTemplate . replace ( SEP_TAG , separator ) ) ; addErrorStack ( longTrace , traceFrames . error ) ; timestamp = lastTime . getTime ( ) ; } } return longTrace . join ( NEWLINE ) ; } ( Zone as any ) [ 'longStackTraceZoneSpec' ] = < ZoneSpec > { name : 'long-stack-trace' , longStackTraceLimit : 10 , getLongStackTrace : function ( error ) : string | undefined { if ( ! error ) { return undefined ; } const trace = ( error as any ) [ ( Zone as any ) . __symbol__ ( 'currentTaskTrace' ) ] ; if ( ! trace ) { return error . stack ; } return renderLongStackTrace ( trace , error . stack ) ; } , onScheduleTask : function ( parentZoneDelegate , currentZone , targetZone , task ) : any { if ( Error . stackTraceLimit > 0 ) { const currentTask = Zone . currentTask ; let trace = currentTask && currentTask . data && ( currentTask . data as any ) [ creationTrace ] || [ ] ; trace = [ new LongStackTrace ( ) ] . concat ( trace ) ; if ( trace . length > this . longStackTraceLimit ) { trace . length = this . longStackTraceLimit ; } if ( ! task . data ) task . data = { } ; if ( task . type === 'eventTask' ) { ( task . data as any ) = { ... ( task . data as any ) } ; } ( task . data as any ) [ creationTrace ] = trace ; } return parentZoneDelegate . scheduleTask ( targetZone , task ) ; } , onHandleError : function ( parentZoneDelegate , currentZone , targetZone , error ) : boolean { if ( Error . stackTraceLimit > 0 ) { const parentTask = Zone . currentTask || error . task ; if ( error instanceof Error && parentTask ) { const longStack = renderLongStackTrace ( parentTask . data && parentTask . data [ creationTrace ] , error . stack ) ; try { error . stack = ( error as any ) . longStack = longStack ; } catch ( err ) { } } } return parentZoneDelegate . handleError ( targetZone , error ) ; } } ; function captureStackTraces ( stackTraces , count ) { if ( count > 0 ) { stackTraces . push ( getFrames ( ( new LongStackTrace ( ) ) . error ) ) ; captureStackTraces ( stackTraces , count - 1 ) ; } } function computeIgnoreFrames ( ) { if ( Error . stackTraceLimit <= 0 ) { return ; } const frames = [ ] ; captureStackTraces ( frames , 2 ) ; const frames1 = frames [ 0 ] ; const frames2 = frames [ 1 ] ; for ( let i = 0 ; i < frames1 . length ; i ++ ) { const frame1 = frames1 [ i ] ; if ( frame1 . indexOf ( ERROR_TAG ) == - 1 ) { let match = frame1 . match ( /^\s*at\s+/ ) ; if ( match ) { sepTemplate = match [ 0 ] + SEP_TAG + ' (http://localhost)' ; break ; } } } for ( let i = 0 ; i < frames1 . length ; i ++ ) { const frame1 = frames1 [ i ] ; const frame2 = frames2 [ i ] ; if ( frame1 === frame2 ) { IGNORE_FRAMES [ frame1 ] = true ; } else { break ; } } } computeIgnoreFrames ( ) ;