import { SourceMapConsumer , NullableMappedPosition } from 'source-map' ; import { CallSite , callSiteToString } from '@flood/element-report' ; interface StackLine { at : string ; file : string ; line : number ; column : number ; } export class SourceUnmapped { public static async init ( originalSource , originalFilename , sourceMap ) { const sourceMapConsumer = await new SourceMapConsumer ( sourceMap ) ; return new SourceUnmapped ( originalSource , originalFilename , sourceMapConsumer ) ; } constructor ( private originalSource , private originalFilename , private sourceMapConsumer ) { } public unMapNodeStackLine ( stackLine ) { return callSiteToString ( this . unMapCallSite ( stackLine ) ) ; } public unMapCallSite ( stackLine ) { const match = /\s+at [^(]+ \((.*?):(\d+):(\d+)\)/ . exec ( stackLine ) ; if ( match ) { const pos = { source : match [ 1 ] , line : + match [ 2 ] , column : + match [ 3 ] } ; const originalPos = this . sourceMapConsumer . originalPositionFor ( pos ) ; if ( originalPos . line === null || originalPos . column == null ) { return undefined ; } const code = this . extractSourceLine ( originalPos . line ) ; return { file : this . originalFilename , code : code , line : originalPos . line , column : originalPos . column , } ; } else { return undefined ; } } public unMapStack ( stack ) { return this . parseStack ( stack ) . map ( ( s ) => this . originalPositionFor ( s ) ) . filter ( ( x ) : x is StackLine => x !== undefined ) ; } public parseStack ( stack ) { return stack . map ( ( s ) => /\s+at ([^(]+) \((.*?):(\d+):(\d+)\)/ . exec ( s ) ) . filter ( ( x ) : x is RegExpExecArray => x !== null ) . filter ( ( x ) => { return x && x [ 1 ] && x [ 2 ] && x [ 3 ] && x [ 4 ] ; } ) . map ( ( match ) => ( { at : match [ 1 ] , file : match [ 2 ] , line : + match [ 3 ] , column : + match [ 4 ] } ) ) ; } public originalPositionFor ( pos ) { const originalPos = this . sourceMapConsumer . originalPositionFor ( { line : pos . line , column : pos . column , } ) ; if ( originalPos . line === null || originalPos . column === null ) { return undefined ; } return { at : pos . at , file : this . originalFilename , line : originalPos . line , column : originalPos . column , } ; } public unMapStackNodeStrings ( stack ) { const unmapped = this . unMapStack ( stack ) ; return unmapped . map ( this . stackLineToNodeString ) ; } public extractSourceLine ( line ) { return this . originalSource . split ( /(?:\r\n|\r|\n)/ ) [ line - 1 ] ; } public stackLineToNodeString ( m ) { return `    at ${ m . at } ${ m . file }:${ m . line }:${ m . column }` ; } }