@@ -1162,25 +1162,58 @@ function getFunctionBase(value, constructor, tag) {
11621162 return base ;
11631163}
11641164
1165- function formatError ( err , constructor , tag , ctx , keys ) {
1166- const name = err . name != null ? String ( err . name ) : 'Error' ;
1167- let len = name . length ;
1168- let stack = err . stack ? String ( err . stack ) : ErrorPrototypeToString ( err ) ;
1165+ function identicalSequenceRange ( a , b ) {
1166+ for ( let i = 0 ; i < a . length - 3 ; i ++ ) {
1167+ // Find the first entry of b that matches the current entry of a.
1168+ const pos = b . indexOf ( a [ i ] ) ;
1169+ if ( pos !== - 1 ) {
1170+ const rest = b . length - pos ;
1171+ if ( rest > 3 ) {
1172+ let len = 1 ;
1173+ const maxLen = MathMin ( a . length - i , rest ) ;
1174+ // Count the number of consecutive entries.
1175+ while ( maxLen > len && a [ i + len ] === b [ pos + len ] ) {
1176+ len ++ ;
1177+ }
1178+ if ( len > 3 ) {
1179+ return { len, offset : i } ;
1180+ }
1181+ }
1182+ }
1183+ }
11691184
1170- // Do not "duplicate" error properties that are already included in the output
1171- // otherwise.
1172- if ( ! ctx . showHidden && keys . length !== 0 ) {
1173- for ( const name of [ 'name' , 'message' , 'stack' ] ) {
1174- const index = keys . indexOf ( name ) ;
1175- // Only hide the property in case it's part of the original stack
1176- if ( index !== - 1 && stack . includes ( err [ name ] ) ) {
1177- keys . splice ( index , 1 ) ;
1185+ return { len : 0 , offset : 0 } ;
1186+ }
1187+
1188+ function getStackString ( error ) {
1189+ return error . stack ? String ( error . stack ) : ErrorPrototypeToString ( error ) ;
1190+ }
1191+
1192+ function getStackFrames ( ctx , err , stack ) {
1193+ const frames = stack . split ( '\n' ) ;
1194+
1195+ // Remove stack frames identical to frames in cause.
1196+ if ( err . cause ) {
1197+ const causeStack = getStackString ( err . cause ) ;
1198+ const causeStackStart = causeStack . indexOf ( '\n at' ) ;
1199+ if ( causeStackStart !== - 1 ) {
1200+ const causeFrames = causeStack . slice ( causeStackStart + 1 ) . split ( '\n' ) ;
1201+ const { len, offset } = identicalSequenceRange ( frames , causeFrames ) ;
1202+ if ( len > 0 ) {
1203+ const skipped = len - 2 ;
1204+ const msg = ` ... ${ skipped } lines matching cause stack trace ...` ;
1205+ frames . splice ( offset + 1 , skipped , ctx . stylize ( msg , 'undefined' ) ) ;
11781206 }
11791207 }
11801208 }
1209+ return frames ;
1210+ }
11811211
1212+ function improveStack ( stack , constructor , name , tag ) {
11821213 // A stack trace may contain arbitrary data. Only manipulate the output
11831214 // for "regular errors" (errors that "look normal") for now.
1215+ let len = name . length ;
1216+
11841217 if ( constructor === null ||
11851218 ( name . endsWith ( 'Error' ) &&
11861219 stack . startsWith ( name ) &&
@@ -1206,6 +1239,33 @@ function formatError(err, constructor, tag, ctx, keys) {
12061239 }
12071240 }
12081241 }
1242+ return stack ;
1243+ }
1244+
1245+ function removeDuplicateErrorKeys ( ctx , keys , err , stack ) {
1246+ if ( ! ctx . showHidden && keys . length !== 0 ) {
1247+ for ( const name of [ 'name' , 'message' , 'stack' ] ) {
1248+ const index = keys . indexOf ( name ) ;
1249+ // Only hide the property in case it's part of the original stack
1250+ if ( index !== - 1 && stack . includes ( err [ name ] ) ) {
1251+ keys . splice ( index , 1 ) ;
1252+ }
1253+ }
1254+ }
1255+ }
1256+
1257+ function formatError ( err , constructor , tag , ctx , keys ) {
1258+ const name = err . name != null ? String ( err . name ) : 'Error' ;
1259+ let stack = getStackString ( err ) ;
1260+
1261+ removeDuplicateErrorKeys ( ctx , keys , err , stack ) ;
1262+
1263+ if ( err . cause && ( keys . length === 0 || ! keys . includes ( 'cause' ) ) ) {
1264+ keys . push ( 'cause' ) ;
1265+ }
1266+
1267+ stack = improveStack ( stack , constructor , name , tag ) ;
1268+
12091269 // Ignore the error message if it's contained in the stack.
12101270 let pos = ( err . message && stack . indexOf ( err . message ) ) || - 1 ;
12111271 if ( pos !== - 1 )
@@ -1217,7 +1277,7 @@ function formatError(err, constructor, tag, ctx, keys) {
12171277 } else if ( ctx . colors ) {
12181278 // Highlight userland code and node modules.
12191279 let newStack = stack . slice ( 0 , stackStart ) ;
1220- const lines = stack . slice ( stackStart + 1 ) . split ( '\n' ) ;
1280+ const lines = getStackFrames ( ctx , err , stack . slice ( stackStart + 1 ) ) ;
12211281 for ( const line of lines ) {
12221282 const core = line . match ( coreModuleRegExp ) ;
12231283 if ( core !== null && NativeModule . exists ( core [ 1 ] ) ) {
0 commit comments