@@ -406,24 +406,27 @@ function inspect(value, opts) {
406
406
maxArrayLength : inspectDefaultOptions . maxArrayLength ,
407
407
breakLength : inspectDefaultOptions . breakLength ,
408
408
indentationLvl : 0 ,
409
- compact : inspectDefaultOptions . compact
409
+ compact : inspectDefaultOptions . compact ,
410
+ budget : { }
410
411
} ;
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
+ }
418
421
}
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
+ }
427
430
}
428
431
}
429
432
if ( ctx . colors ) ctx . stylize = stylizeWithColor ;
@@ -623,14 +626,19 @@ function noPrototypeIterator(ctx, value, recurseTimes) {
623
626
// corrected by setting `ctx.indentationLvL += diff` and then to decrease the
624
627
// value afterwards again.
625
628
function formatValue ( ctx , value , recurseTimes ) {
626
- // Primitive types cannot have properties
629
+ // Primitive types cannot have properties.
627
630
if ( typeof value !== 'object' && typeof value !== 'function' ) {
628
631
return formatPrimitive ( ctx . stylize , value , ctx ) ;
629
632
}
630
633
if ( value === null ) {
631
634
return ctx . stylize ( 'null' , 'null' ) ;
632
635
}
633
636
637
+ if ( ctx . stop !== undefined ) {
638
+ const name = getConstructorName ( value ) || value [ Symbol . toStringTag ] ;
639
+ return ctx . stylize ( `[${ name || 'Object' } ]` , 'special' ) ;
640
+ }
641
+
634
642
if ( ctx . showProxy ) {
635
643
const proxy = getProxyDetails ( value ) ;
636
644
if ( proxy !== undefined ) {
@@ -639,11 +647,11 @@ function formatValue(ctx, value, recurseTimes) {
639
647
}
640
648
641
649
// 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.
643
651
if ( ctx . customInspect ) {
644
652
const maybeCustom = value [ customInspectSymbol ] ;
645
653
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.
647
655
maybeCustom !== exports . inspect &&
648
656
// Also filter out any prototype objects using the circular check.
649
657
! ( value . constructor && value . constructor . prototype === value ) ) {
@@ -685,7 +693,7 @@ function formatRaw(ctx, value, recurseTimes) {
685
693
686
694
let extrasType = kObjectType ;
687
695
688
- // Iterators and the rest are split to reduce checks
696
+ // Iterators and the rest are split to reduce checks.
689
697
if ( value [ Symbol . iterator ] ) {
690
698
noIterator = false ;
691
699
if ( Array . isArray ( value ) ) {
@@ -766,7 +774,7 @@ function formatRaw(ctx, value, recurseTimes) {
766
774
}
767
775
base = dateToISOString ( value ) ;
768
776
} else if ( isError ( value ) ) {
769
- // Make error with message first say the error
777
+ // Make error with message first say the error.
770
778
base = formatError ( value ) ;
771
779
// Wrap the error in brackets in case it has no stack trace.
772
780
const stackStart = base . indexOf ( '\n at' ) ;
@@ -885,7 +893,21 @@ function formatRaw(ctx, value, recurseTimes) {
885
893
}
886
894
ctx . seen . pop ( ) ;
887
895
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 ;
889
911
}
890
912
891
913
function handleMaxCallStackSize ( ctx , err , constructor , tag ) {
@@ -1057,8 +1079,9 @@ function formatTypedArray(ctx, value, recurseTimes) {
1057
1079
formatBigInt ;
1058
1080
for ( var i = 0 ; i < maxLength ; ++ i )
1059
1081
output [ i ] = elementFormatter ( ctx . stylize , value [ i ] ) ;
1060
- if ( remaining > 0 )
1082
+ if ( remaining > 0 ) {
1061
1083
output [ i ] = `... ${ remaining } more item${ remaining > 1 ? 's' : '' } ` ;
1084
+ }
1062
1085
if ( ctx . showHidden ) {
1063
1086
// .buffer goes last, it's not a primitive like the others.
1064
1087
ctx . indentationLvl += 2 ;
0 commit comments