5
5
} = primordials ;
6
6
7
7
const debug = require ( 'internal/util/debuglog' ) . debuglog ( 'source_map' ) ;
8
+ const { getStringWidth } = require ( 'internal/util/inspect' ) ;
9
+ const { readFileSync } = require ( 'fs' ) ;
8
10
const { findSourceMap } = require ( 'internal/source_map/source_map_cache' ) ;
9
11
const {
10
12
kNoOverride,
@@ -34,7 +36,17 @@ const prepareStackTrace = (globalThis, error, trace) => {
34
36
if ( trace . length === 0 ) {
35
37
return errorString ;
36
38
}
39
+
40
+ let errorSource = '' ;
41
+ let firstSource ;
42
+ let firstLine ;
43
+ let firstColumn ;
37
44
const preparedTrace = trace . map ( ( t , i ) => {
45
+ if ( i === 0 ) {
46
+ firstLine = t . getLineNumber ( ) ;
47
+ firstColumn = t . getColumnNumber ( ) ;
48
+ firstSource = t . getFileName ( ) ;
49
+ }
38
50
let str = i !== 0 ? '\n at ' : '' ;
39
51
str = `${ str } ${ t } ` ;
40
52
try {
@@ -49,18 +61,57 @@ const prepareStackTrace = (globalThis, error, trace) => {
49
61
} = sm . findEntry ( t . getLineNumber ( ) - 1 , t . getColumnNumber ( ) - 1 ) ;
50
62
if ( originalSource && originalLine !== undefined &&
51
63
originalColumn !== undefined ) {
52
- str +=
53
- `\n -> ${ originalSource . replace ( 'file://' , '' ) } :${ originalLine + 1 } :${ originalColumn + 1 } ` ;
64
+ const originalSourceNoScheme = originalSource
65
+ . replace ( / ^ f i l e : \/ \/ / , '' ) ;
66
+ if ( i === 0 ) {
67
+ firstLine = originalLine + 1 ;
68
+ firstColumn = originalColumn + 1 ;
69
+ firstSource = originalSourceNoScheme ;
70
+ // Show error in original source context to help user pinpoint it:
71
+ errorSource = getErrorSource ( firstSource , firstLine , firstColumn ) ;
72
+ }
73
+ // Show both original and transpiled stack trace information:
74
+ str += `\n -> ${ originalSourceNoScheme } :${ originalLine + 1 } :` +
75
+ `${ originalColumn + 1 } ` ;
54
76
}
55
77
}
56
78
} catch ( err ) {
57
79
debug ( err . stack ) ;
58
80
}
59
81
return str ;
60
82
} ) ;
61
- return `${ errorString } \n at ${ preparedTrace . join ( '' ) } ` ;
83
+ return `${ errorSource } ${ errorString } \n at ${ preparedTrace . join ( '' ) } ` ;
62
84
} ;
63
85
86
+ // Places a snippet of code from where the exception was originally thrown
87
+ // above the stack trace. This logic is modeled after GetErrorSource in
88
+ // node_errors.cc.
89
+ function getErrorSource ( firstSource , firstLine , firstColumn ) {
90
+ let exceptionLine = '' ;
91
+ let source ;
92
+ try {
93
+ source = readFileSync ( firstSource , 'utf8' ) ;
94
+ } catch ( err ) {
95
+ debug ( err ) ;
96
+ return exceptionLine ;
97
+ }
98
+ const lines = source . split ( / \r ? \n / , firstLine ) ;
99
+ const line = lines [ firstLine - 1 ] ;
100
+ if ( ! line ) return exceptionLine ;
101
+
102
+ // Display ^ in appropriate position, regardless of whether tabs or
103
+ // spaces are used:
104
+ let prefix = '' ;
105
+ for ( const character of line . slice ( 0 , firstColumn ) ) {
106
+ prefix += ( character === '\t' ) ? '\t' :
107
+ ' ' . repeat ( getStringWidth ( character ) ) ;
108
+ }
109
+ prefix = prefix . slice ( 0 , - 1 ) ; // The last character is the '^'.
110
+
111
+ exceptionLine = `${ firstSource } :${ firstLine } \n${ line } \n${ prefix } ^\n\n` ;
112
+ return exceptionLine ;
113
+ }
114
+
64
115
module . exports = {
65
116
prepareStackTrace,
66
117
} ;
0 commit comments