77let debug = require ( 'internal/util/debuglog' ) . debuglog ( 'source_map' , ( fn ) => {
88 debug = fn ;
99} ) ;
10+ const { getStringWidth } = require ( 'internal/util/inspect' ) ;
11+ const { readFileSync } = require ( 'fs' ) ;
1012const { findSourceMap } = require ( 'internal/source_map/source_map_cache' ) ;
1113const {
1214 kNoOverride,
@@ -36,7 +38,17 @@ const prepareStackTrace = (globalThis, error, trace) => {
3638 if ( trace . length === 0 ) {
3739 return errorString ;
3840 }
41+
42+ let errorSource = '' ;
43+ let firstSource ;
44+ let firstLine ;
45+ let firstColumn ;
3946 const preparedTrace = trace . map ( ( t , i ) => {
47+ if ( i === 0 ) {
48+ firstLine = t . getLineNumber ( ) ;
49+ firstColumn = t . getColumnNumber ( ) ;
50+ firstSource = t . getFileName ( ) ;
51+ }
4052 let str = i !== 0 ? '\n at ' : '' ;
4153 str = `${ str } ${ t } ` ;
4254 try {
@@ -51,18 +63,57 @@ const prepareStackTrace = (globalThis, error, trace) => {
5163 } = sm . findEntry ( t . getLineNumber ( ) - 1 , t . getColumnNumber ( ) - 1 ) ;
5264 if ( originalSource && originalLine !== undefined &&
5365 originalColumn !== undefined ) {
54- str +=
55- `\n -> ${ originalSource . replace ( 'file://' , '' ) } :${ originalLine + 1 } :${ originalColumn + 1 } ` ;
66+ const originalSourceNoScheme = originalSource
67+ . replace ( / ^ f i l e : \/ \/ / , '' ) ;
68+ if ( i === 0 ) {
69+ firstLine = originalLine + 1 ;
70+ firstColumn = originalColumn + 1 ;
71+ firstSource = originalSourceNoScheme ;
72+ // Show error in original source context to help user pinpoint it:
73+ errorSource = getErrorSource ( firstSource , firstLine , firstColumn ) ;
74+ }
75+ // Show both original and transpiled stack trace information:
76+ str += `\n -> ${ originalSourceNoScheme } :${ originalLine + 1 } :` +
77+ `${ originalColumn + 1 } ` ;
5678 }
5779 }
5880 } catch ( err ) {
5981 debug ( err . stack ) ;
6082 }
6183 return str ;
6284 } ) ;
63- return `${ errorString } \n at ${ preparedTrace . join ( '' ) } ` ;
85+ return `${ errorSource } ${ errorString } \n at ${ preparedTrace . join ( '' ) } ` ;
6486} ;
6587
88+ // Places a snippet of code from where the exception was originally thrown
89+ // above the stack trace. This logic is modeled after GetErrorSource in
90+ // node_errors.cc.
91+ function getErrorSource ( firstSource , firstLine , firstColumn ) {
92+ let exceptionLine = '' ;
93+ let source ;
94+ try {
95+ source = readFileSync ( firstSource , 'utf8' ) ;
96+ } catch ( err ) {
97+ debug ( err ) ;
98+ return exceptionLine ;
99+ }
100+ const lines = source . split ( / \r ? \n / , firstLine ) ;
101+ const line = lines [ firstLine - 1 ] ;
102+ if ( ! line ) return exceptionLine ;
103+
104+ // Display ^ in appropriate position, regardless of whether tabs or
105+ // spaces are used:
106+ let prefix = '' ;
107+ for ( const character of line . slice ( 0 , firstColumn ) ) {
108+ prefix += ( character === '\t' ) ? '\t' :
109+ ' ' . repeat ( getStringWidth ( character ) ) ;
110+ }
111+ prefix = prefix . slice ( 0 , - 1 ) ; // The last character is the '^'.
112+
113+ exceptionLine = `${ firstSource } :${ firstLine } \n${ line } \n${ prefix } ^\n\n` ;
114+ return exceptionLine ;
115+ }
116+
66117module . exports = {
67118 prepareStackTrace,
68119} ;
0 commit comments