@@ -406,24 +406,27 @@ function inspect(value, opts) {
406406 maxArrayLength : inspectDefaultOptions . maxArrayLength ,
407407 breakLength : inspectDefaultOptions . breakLength ,
408408 indentationLvl : 0 ,
409- compact : inspectDefaultOptions . compact
409+ compact : inspectDefaultOptions . compact ,
410+ budget : { }
410411 } ;
411- // Legacy...
412- if ( arguments . length > 2 ) {
413- if ( arguments [ 2 ] !== undefined ) {
414- ctx . depth = arguments [ 2 ] ;
415- }
416- if ( arguments . length > 3 && arguments [ 3 ] !== undefined ) {
417- ctx . colors = arguments [ 3 ] ;
412+ if ( arguments . length > 1 ) {
413+ // Legacy...
414+ if ( arguments . length > 2 ) {
415+ if ( arguments [ 2 ] !== undefined ) {
416+ ctx . depth = arguments [ 2 ] ;
417+ }
418+ if ( arguments . length > 3 && arguments [ 3 ] !== undefined ) {
419+ ctx . colors = arguments [ 3 ] ;
420+ }
418421 }
419- }
420- // Set user-specified options
421- if ( typeof opts === 'boolean' ) {
422- ctx . showHidden = opts ;
423- } else if ( opts ) {
424- const optKeys = Object . keys ( opts ) ;
425- for ( var i = 0 ; i < optKeys . length ; i ++ ) {
426- ctx [ optKeys [ i ] ] = opts [ optKeys [ i ] ] ;
422+ // Set user-specified options
423+ if ( typeof opts === 'boolean' ) {
424+ ctx . showHidden = opts ;
425+ } else if ( opts ) {
426+ const optKeys = Object . keys ( opts ) ;
427+ for ( var i = 0 ; i < optKeys . length ; i ++ ) {
428+ ctx [ optKeys [ i ] ] = opts [ optKeys [ i ] ] ;
429+ }
427430 }
428431 }
429432 if ( ctx . colors ) ctx . stylize = stylizeWithColor ;
@@ -623,14 +626,19 @@ function noPrototypeIterator(ctx, value, recurseTimes) {
623626// corrected by setting `ctx.indentationLvL += diff` and then to decrease the
624627// value afterwards again.
625628function formatValue ( ctx , value , recurseTimes ) {
626- // Primitive types cannot have properties
629+ // Primitive types cannot have properties.
627630 if ( typeof value !== 'object' && typeof value !== 'function' ) {
628631 return formatPrimitive ( ctx . stylize , value , ctx ) ;
629632 }
630633 if ( value === null ) {
631634 return ctx . stylize ( 'null' , 'null' ) ;
632635 }
633636
637+ if ( ctx . stop !== undefined ) {
638+ const name = getConstructorName ( value ) || value [ Symbol . toStringTag ] ;
639+ return ctx . stylize ( `[${ name || 'Object' } ]` , 'special' ) ;
640+ }
641+
634642 if ( ctx . showProxy ) {
635643 const proxy = getProxyDetails ( value ) ;
636644 if ( proxy !== undefined ) {
@@ -639,11 +647,11 @@ function formatValue(ctx, value, recurseTimes) {
639647 }
640648
641649 // Provide a hook for user-specified inspect functions.
642- // Check that value is an object with an inspect function on it
650+ // Check that value is an object with an inspect function on it.
643651 if ( ctx . customInspect ) {
644652 const maybeCustom = value [ customInspectSymbol ] ;
645653 if ( typeof maybeCustom === 'function' &&
646- // Filter out the util module, its inspect function is special
654+ // Filter out the util module, its inspect function is special.
647655 maybeCustom !== exports . inspect &&
648656 // Also filter out any prototype objects using the circular check.
649657 ! ( value . constructor && value . constructor . prototype === value ) ) {
@@ -685,7 +693,7 @@ function formatRaw(ctx, value, recurseTimes) {
685693
686694 let extrasType = kObjectType ;
687695
688- // Iterators and the rest are split to reduce checks
696+ // Iterators and the rest are split to reduce checks.
689697 if ( value [ Symbol . iterator ] ) {
690698 noIterator = false ;
691699 if ( Array . isArray ( value ) ) {
@@ -766,7 +774,7 @@ function formatRaw(ctx, value, recurseTimes) {
766774 }
767775 base = dateToISOString ( value ) ;
768776 } else if ( isError ( value ) ) {
769- // Make error with message first say the error
777+ // Make error with message first say the error.
770778 base = formatError ( value ) ;
771779 // Wrap the error in brackets in case it has no stack trace.
772780 const stackStart = base . indexOf ( '\n at' ) ;
@@ -885,7 +893,21 @@ function formatRaw(ctx, value, recurseTimes) {
885893 }
886894 ctx . seen . pop ( ) ;
887895
888- return reduceToSingleString ( ctx , output , base , braces ) ;
896+ const res = reduceToSingleString ( ctx , output , base , braces ) ;
897+ const budget = ctx . budget [ ctx . indentationLvl ] || 0 ;
898+ const newLength = budget + res . length ;
899+ ctx . budget [ ctx . indentationLvl ] = newLength ;
900+ // If any indentationLvl exceeds this limit, limit further inspecting to the
901+ // minimum. Otherwise the recursive algorithm might continue inspecting the
902+ // object even though the maximum string size (~2 ** 28 on 32 bit systems and
903+ // ~2 ** 30 on 64 bit systems) exceeded. The actual output is not limited at
904+ // exactly 2 ** 27 but a bit higher. This depends on the object shape.
905+ // This limit also makes sure that huge objects don't block the event loop
906+ // significantly.
907+ if ( newLength > 2 ** 27 ) {
908+ ctx . stop = true ;
909+ }
910+ return res ;
889911}
890912
891913function handleMaxCallStackSize ( ctx , err , constructor , tag ) {
@@ -1057,8 +1079,9 @@ function formatTypedArray(ctx, value, recurseTimes) {
10571079 formatBigInt ;
10581080 for ( var i = 0 ; i < maxLength ; ++ i )
10591081 output [ i ] = elementFormatter ( ctx . stylize , value [ i ] ) ;
1060- if ( remaining > 0 )
1082+ if ( remaining > 0 ) {
10611083 output [ i ] = `... ${ remaining } more item${ remaining > 1 ? 's' : '' } ` ;
1084+ }
10621085 if ( ctx . showHidden ) {
10631086 // .buffer goes last, it's not a primitive like the others.
10641087 ctx . indentationLvl += 2 ;
0 commit comments