@@ -99,7 +99,8 @@ const inspectDefaultOptions = Object.seal({
99
99
showProxy : false ,
100
100
maxArrayLength : 100 ,
101
101
breakLength : 60 ,
102
- compact : true
102
+ compact : true ,
103
+ budget : Infinity
103
104
} ) ;
104
105
105
106
const kObjectType = 0 ;
@@ -406,24 +407,27 @@ function inspect(value, opts) {
406
407
maxArrayLength : inspectDefaultOptions . maxArrayLength ,
407
408
breakLength : inspectDefaultOptions . breakLength ,
408
409
indentationLvl : 0 ,
409
- compact : inspectDefaultOptions . compact
410
+ compact : inspectDefaultOptions . compact ,
411
+ budget : inspectDefaultOptions . budget
410
412
} ;
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 ] ;
413
+ if ( arguments . length > 1 ) {
414
+ // Legacy...
415
+ if ( arguments . length > 2 ) {
416
+ if ( arguments [ 2 ] !== undefined ) {
417
+ ctx . depth = arguments [ 2 ] ;
418
+ }
419
+ if ( arguments . length > 3 && arguments [ 3 ] !== undefined ) {
420
+ ctx . colors = arguments [ 3 ] ;
421
+ }
418
422
}
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 ] ] ;
423
+ // Set user-specified options
424
+ if ( typeof opts === 'boolean' ) {
425
+ ctx . showHidden = opts ;
426
+ } else if ( opts ) {
427
+ const optKeys = Object . keys ( opts ) ;
428
+ for ( var i = 0 ; i < optKeys . length ; i ++ ) {
429
+ ctx [ optKeys [ i ] ] = opts [ optKeys [ i ] ] ;
430
+ }
427
431
}
428
432
}
429
433
if ( ctx . colors ) ctx . stylize = stylizeWithColor ;
@@ -619,18 +623,45 @@ function noPrototypeIterator(ctx, value, recurseTimes) {
619
623
}
620
624
}
621
625
626
+ function getClockTime ( start ) {
627
+ const ts = process . hrtime ( start ) ;
628
+ return ts [ 0 ] * 1e3 + ts [ 1 ] / 1e6 ;
629
+ }
630
+
622
631
// Note: using `formatValue` directly requires the indentation level to be
623
632
// corrected by setting `ctx.indentationLvL += diff` and then to decrease the
624
633
// value afterwards again.
625
634
function formatValue ( ctx , value , recurseTimes ) {
626
- // Primitive types cannot have properties
635
+ // Primitive types cannot have properties.
627
636
if ( typeof value !== 'object' && typeof value !== 'function' ) {
628
637
return formatPrimitive ( ctx . stylize , value , ctx ) ;
629
638
}
630
639
if ( value === null ) {
631
640
return ctx . stylize ( 'null' , 'null' ) ;
632
641
}
633
642
643
+ if ( ctx . budget < 0 ) {
644
+ if ( ctx . stop === true ) {
645
+ const name = getConstructorName ( value ) || value [ Symbol . toStringTag ] ;
646
+ return ctx . stylize ( `[${ name || 'Object' } ]` , 'special' ) ;
647
+ }
648
+ if ( ctx . time === undefined ) {
649
+ ctx . time = process . hrtime ( ) ;
650
+ } else if ( getClockTime ( ctx . time ) > 1e3 ) {
651
+ process . emitWarning ( 'util.inspect took to long.' , {
652
+ code : 'INSPECTION_ABORTED' ,
653
+ detail : 'util.inspect() received an object that was very big and ' +
654
+ 'complex to inspect. Further inspection was limited to a ' +
655
+ 'minimum to stop blocking the event loop.'
656
+ } ) ;
657
+ // Since we only measure the time each 1e5 the output should be almost
658
+ // deterministic.
659
+ ctx . stop = true ;
660
+ }
661
+ // Subtract 1e5 to know when to check again.
662
+ ctx . budget += 1e5 ;
663
+ }
664
+
634
665
if ( ctx . showProxy ) {
635
666
const proxy = getProxyDetails ( value ) ;
636
667
if ( proxy !== undefined ) {
@@ -639,11 +670,11 @@ function formatValue(ctx, value, recurseTimes) {
639
670
}
640
671
641
672
// Provide a hook for user-specified inspect functions.
642
- // Check that value is an object with an inspect function on it
673
+ // Check that value is an object with an inspect function on it.
643
674
if ( ctx . customInspect ) {
644
675
const maybeCustom = value [ customInspectSymbol ] ;
645
676
if ( typeof maybeCustom === 'function' &&
646
- // Filter out the util module, its inspect function is special
677
+ // Filter out the util module, its inspect function is special.
647
678
maybeCustom !== exports . inspect &&
648
679
// Also filter out any prototype objects using the circular check.
649
680
! ( value . constructor && value . constructor . prototype === value ) ) {
@@ -685,7 +716,7 @@ function formatRaw(ctx, value, recurseTimes) {
685
716
686
717
let extrasType = kObjectType ;
687
718
688
- // Iterators and the rest are split to reduce checks
719
+ // Iterators and the rest are split to reduce checks.
689
720
if ( value [ Symbol . iterator ] ) {
690
721
noIterator = false ;
691
722
if ( Array . isArray ( value ) ) {
@@ -766,7 +797,9 @@ function formatRaw(ctx, value, recurseTimes) {
766
797
}
767
798
base = dateToISOString ( value ) ;
768
799
} else if ( isError ( value ) ) {
769
- // Make error with message first say the error
800
+ // Normalize budget because error inspection is very slow.
801
+ ctx . budget -= 5 ;
802
+ // Make error with message first say the error.
770
803
base = formatError ( value ) ;
771
804
// Wrap the error in brackets in case it has no stack trace.
772
805
const stackStart = base . indexOf ( '\n at' ) ;
@@ -885,6 +918,7 @@ function formatRaw(ctx, value, recurseTimes) {
885
918
}
886
919
ctx . seen . pop ( ) ;
887
920
921
+ ctx . budget += output . length ;
888
922
return reduceToSingleString ( ctx , output , base , braces ) ;
889
923
}
890
924
@@ -1057,8 +1091,9 @@ function formatTypedArray(ctx, value, recurseTimes) {
1057
1091
formatBigInt ;
1058
1092
for ( var i = 0 ; i < maxLength ; ++ i )
1059
1093
output [ i ] = elementFormatter ( ctx . stylize , value [ i ] ) ;
1060
- if ( remaining > 0 )
1094
+ if ( remaining > 0 ) {
1061
1095
output [ i ] = `... ${ remaining } more item${ remaining > 1 ? 's' : '' } ` ;
1096
+ }
1062
1097
if ( ctx . showHidden ) {
1063
1098
// .buffer goes last, it's not a primitive like the others.
1064
1099
ctx . indentationLvl += 2 ;
@@ -1247,6 +1282,8 @@ function formatProperty(ctx, value, recurseTimes, key, type) {
1247
1282
} else if ( keyStrRegExp . test ( key ) ) {
1248
1283
name = ctx . stylize ( key , 'name' ) ;
1249
1284
} else {
1285
+ // Normalize budget because replacing keys is slow.
1286
+ ctx . budget -= 3 ;
1250
1287
name = ctx . stylize ( strEscape ( key ) , 'string' ) ;
1251
1288
}
1252
1289
return `${ name } :${ extra } ${ str } ` ;
0 commit comments