@@ -11,6 +11,7 @@ const {
11
11
ErrorPrototypeToString,
12
12
JSONStringify,
13
13
Map,
14
+ MapPrototype,
14
15
MapPrototypeEntries,
15
16
MathFloor,
16
17
MathMax,
@@ -22,10 +23,8 @@ const {
22
23
NumberPrototypeValueOf,
23
24
ObjectAssign,
24
25
ObjectCreate,
25
- ObjectDefineProperties,
26
26
ObjectDefineProperty,
27
27
ObjectGetOwnPropertyDescriptor,
28
- ObjectGetOwnPropertyDescriptors,
29
28
ObjectGetOwnPropertyNames,
30
29
ObjectGetOwnPropertySymbols,
31
30
ObjectGetPrototypeOf,
@@ -36,6 +35,7 @@ const {
36
35
ObjectSeal,
37
36
RegExpPrototypeToString,
38
37
Set,
38
+ SetPrototype,
39
39
SetPrototypeValues,
40
40
StringPrototypeValueOf,
41
41
SymbolPrototypeToString,
@@ -115,6 +115,11 @@ const assert = require('internal/assert');
115
115
116
116
const { NativeModule } = require ( 'internal/bootstrap/loaders' ) ;
117
117
118
+ const setSizeGetter = uncurryThis (
119
+ ObjectGetOwnPropertyDescriptor ( SetPrototype , 'size' ) . get ) ;
120
+ const mapSizeGetter = uncurryThis (
121
+ ObjectGetOwnPropertyDescriptor ( MapPrototype , 'size' ) . get ) ;
122
+
118
123
let hexSlice ;
119
124
120
125
const builtInObjects = new Set (
@@ -648,51 +653,6 @@ function findTypedConstructor(value) {
648
653
}
649
654
}
650
655
651
- let lazyNullPrototypeCache ;
652
- // Creates a subclass and name
653
- // the constructor as `${clazz} : null prototype`
654
- function clazzWithNullPrototype ( clazz , name ) {
655
- if ( lazyNullPrototypeCache === undefined ) {
656
- lazyNullPrototypeCache = new Map ( ) ;
657
- } else {
658
- const cachedClass = lazyNullPrototypeCache . get ( clazz ) ;
659
- if ( cachedClass !== undefined ) {
660
- return cachedClass ;
661
- }
662
- }
663
- class NullPrototype extends clazz {
664
- get [ SymbolToStringTag ] ( ) {
665
- return '' ;
666
- }
667
- }
668
- ObjectDefineProperty ( NullPrototype . prototype . constructor , 'name' ,
669
- { value : `[${ name } : null prototype]` } ) ;
670
- lazyNullPrototypeCache . set ( clazz , NullPrototype ) ;
671
- return NullPrototype ;
672
- }
673
-
674
- function noPrototypeIterator ( ctx , value , recurseTimes ) {
675
- let newVal ;
676
- if ( isSet ( value ) ) {
677
- const clazz = clazzWithNullPrototype ( Set , 'Set' ) ;
678
- newVal = new clazz ( SetPrototypeValues ( value ) ) ;
679
- } else if ( isMap ( value ) ) {
680
- const clazz = clazzWithNullPrototype ( Map , 'Map' ) ;
681
- newVal = new clazz ( MapPrototypeEntries ( value ) ) ;
682
- } else if ( ArrayIsArray ( value ) ) {
683
- const clazz = clazzWithNullPrototype ( Array , 'Array' ) ;
684
- newVal = new clazz ( value . length ) ;
685
- } else if ( isTypedArray ( value ) ) {
686
- const constructor = findTypedConstructor ( value ) ;
687
- const clazz = clazzWithNullPrototype ( constructor , constructor . name ) ;
688
- newVal = new clazz ( value ) ;
689
- }
690
- if ( newVal !== undefined ) {
691
- ObjectDefineProperties ( newVal , ObjectGetOwnPropertyDescriptors ( value ) ) ;
692
- return formatRaw ( ctx , newVal , recurseTimes ) ;
693
- }
694
- }
695
-
696
656
// Note: using `formatValue` directly requires the indentation level to be
697
657
// corrected by setting `ctx.indentationLvL += diff` and then to decrease the
698
658
// value afterwards again.
@@ -795,7 +755,9 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
795
755
let extrasType = kObjectType ;
796
756
797
757
// Iterators and the rest are split to reduce checks.
798
- if ( value [ SymbolIterator ] ) {
758
+ // We have to check all values in case the constructor is set to null.
759
+ // Otherwise it would not possible to identify all types properly.
760
+ if ( value [ SymbolIterator ] || constructor === null ) {
799
761
noIterator = false ;
800
762
if ( ArrayIsArray ( value ) ) {
801
763
keys = getOwnNonIndexProperties ( value , filter ) ;
@@ -807,37 +769,66 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
807
769
extrasType = kArrayExtrasType ;
808
770
formatter = formatArray ;
809
771
} else if ( isSet ( value ) ) {
772
+ const size = setSizeGetter ( value ) ;
810
773
keys = getKeys ( value , ctx . showHidden ) ;
811
- const prefix = getPrefix ( constructor , tag , 'Set' ) ;
812
- if ( value . size === 0 && keys . length === 0 && protoProps === undefined )
774
+ let prefix = '' ;
775
+ if ( constructor !== null ) {
776
+ if ( constructor === tag )
777
+ tag = '' ;
778
+ prefix = getPrefix ( `${ constructor } ` , tag , '' ) ;
779
+ formatter = formatSet . bind ( null , value , size ) ;
780
+ } else {
781
+ prefix = getPrefix ( constructor , tag , 'Set' ) ;
782
+ formatter = formatSet . bind ( null , SetPrototypeValues ( value ) , size ) ;
783
+ }
784
+ if ( size === 0 && keys . length === 0 && protoProps === undefined )
813
785
return `${ prefix } {}` ;
814
786
braces = [ `${ prefix } {` , '}' ] ;
815
- formatter = formatSet ;
816
787
} else if ( isMap ( value ) ) {
788
+ const size = mapSizeGetter ( value ) ;
817
789
keys = getKeys ( value , ctx . showHidden ) ;
818
- const prefix = getPrefix ( constructor , tag , 'Map' ) ;
819
- if ( value . size === 0 && keys . length === 0 && protoProps === undefined )
790
+ let prefix = '' ;
791
+ if ( constructor !== null ) {
792
+ if ( constructor === tag )
793
+ tag = '' ;
794
+ prefix = getPrefix ( `${ constructor } ` , tag , '' ) ;
795
+ formatter = formatMap . bind ( null , value , size ) ;
796
+ } else {
797
+ prefix = getPrefix ( constructor , tag , 'Map' ) ;
798
+ formatter = formatMap . bind ( null , MapPrototypeEntries ( value ) , size ) ;
799
+ }
800
+ if ( size === 0 && keys . length === 0 && protoProps === undefined )
820
801
return `${ prefix } {}` ;
821
802
braces = [ `${ prefix } {` , '}' ] ;
822
- formatter = formatMap ;
823
803
} else if ( isTypedArray ( value ) ) {
824
804
keys = getOwnNonIndexProperties ( value , filter ) ;
825
- const prefix = constructor !== null ?
826
- getPrefix ( constructor , tag ) :
827
- getPrefix ( constructor , tag , findTypedConstructor ( value ) . name ) ;
805
+ let bound = value ;
806
+ let prefix = '' ;
807
+ if ( constructor === null ) {
808
+ const constr = findTypedConstructor ( value ) ;
809
+ prefix = getPrefix ( constructor , tag , constr . name ) ;
810
+ // Reconstruct the array information.
811
+ bound = new constr ( value ) ;
812
+ } else {
813
+ prefix = getPrefix ( constructor , tag ) ;
814
+ }
828
815
braces = [ `${ prefix } [` , ']' ] ;
829
816
if ( value . length === 0 && keys . length === 0 && ! ctx . showHidden )
830
817
return `${ braces [ 0 ] } ]` ;
831
- formatter = formatTypedArray ;
818
+ // Special handle the value. The original value is required below. The
819
+ // bound function is required to reconstruct missing information.
820
+ formatter = formatTypedArray . bind ( null , bound ) ;
832
821
extrasType = kArrayExtrasType ;
833
822
} else if ( isMapIterator ( value ) ) {
834
823
keys = getKeys ( value , ctx . showHidden ) ;
835
824
braces = getIteratorBraces ( 'Map' , tag ) ;
836
- formatter = formatIterator ;
825
+ // Add braces to the formatter parameters.
826
+ formatter = formatIterator . bind ( null , braces ) ;
837
827
} else if ( isSetIterator ( value ) ) {
838
828
keys = getKeys ( value , ctx . showHidden ) ;
839
829
braces = getIteratorBraces ( 'Set' , tag ) ;
840
- formatter = formatIterator ;
830
+ // Add braces to the formatter parameters.
831
+ formatter = formatIterator . bind ( null , braces ) ;
841
832
} else {
842
833
noIterator = true ;
843
834
}
@@ -915,36 +906,20 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
915
906
formatter = ctx . showHidden ? formatWeakMap : formatWeakCollection ;
916
907
} else if ( isModuleNamespaceObject ( value ) ) {
917
908
braces [ 0 ] = `[${ tag } ] {` ;
918
- formatter = formatNamespaceObject ;
909
+ // Special handle keys for namespace objects.
910
+ formatter = formatNamespaceObject . bind ( null , keys ) ;
919
911
} else if ( isBoxedPrimitive ( value ) ) {
920
912
base = getBoxedBase ( value , ctx , keys , constructor , tag ) ;
921
913
if ( keys . length === 0 && protoProps === undefined ) {
922
914
return base ;
923
915
}
924
916
} else {
925
- // The input prototype got manipulated. Special handle these. We have to
926
- // rebuild the information so we are able to display everything.
927
- if ( constructor === null ) {
928
- const specialIterator = noPrototypeIterator ( ctx , value , recurseTimes ) ;
929
- if ( specialIterator ) {
930
- return specialIterator ;
931
- }
932
- }
933
- if ( isMapIterator ( value ) ) {
934
- braces = getIteratorBraces ( 'Map' , tag ) ;
935
- formatter = formatIterator ;
936
- } else if ( isSetIterator ( value ) ) {
937
- braces = getIteratorBraces ( 'Set' , tag ) ;
938
- formatter = formatIterator ;
939
- // Handle other regular objects again.
940
- } else {
941
- if ( keys . length === 0 && protoProps === undefined ) {
942
- if ( isExternal ( value ) )
943
- return ctx . stylize ( '[External]' , 'special' ) ;
944
- return `${ getCtxStyle ( value , constructor , tag ) } {}` ;
945
- }
946
- braces [ 0 ] = `${ getCtxStyle ( value , constructor , tag ) } {` ;
917
+ if ( keys . length === 0 && protoProps === undefined ) {
918
+ if ( isExternal ( value ) )
919
+ return ctx . stylize ( '[External]' , 'special' ) ;
920
+ return `${ getCtxStyle ( value , constructor , tag ) } {}` ;
947
921
}
922
+ braces [ 0 ] = `${ getCtxStyle ( value , constructor , tag ) } {` ;
948
923
}
949
924
}
950
925
@@ -961,7 +936,7 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
961
936
let output ;
962
937
const indentationLvl = ctx . indentationLvl ;
963
938
try {
964
- output = formatter ( ctx , value , recurseTimes , keys , braces ) ;
939
+ output = formatter ( ctx , value , recurseTimes ) ;
965
940
for ( i = 0 ; i < keys . length ; i ++ ) {
966
941
output . push (
967
942
formatProperty ( ctx , value , recurseTimes , keys [ i ] , extrasType ) ) ;
@@ -1316,7 +1291,7 @@ function formatPrimitive(fn, value, ctx) {
1316
1291
return fn ( SymbolPrototypeToString ( value ) , 'symbol' ) ;
1317
1292
}
1318
1293
1319
- function formatNamespaceObject ( ctx , value , recurseTimes , keys ) {
1294
+ function formatNamespaceObject ( keys , ctx , value , recurseTimes ) {
1320
1295
const output = new Array ( keys . length ) ;
1321
1296
for ( let i = 0 ; i < keys . length ; i ++ ) {
1322
1297
try {
@@ -1418,7 +1393,7 @@ function formatArray(ctx, value, recurseTimes) {
1418
1393
return output ;
1419
1394
}
1420
1395
1421
- function formatTypedArray ( ctx , value , recurseTimes ) {
1396
+ function formatTypedArray ( value , ctx , ignored , recurseTimes ) {
1422
1397
const maxLength = MathMin ( MathMax ( 0 , ctx . maxArrayLength ) , value . length ) ;
1423
1398
const remaining = value . length - maxLength ;
1424
1399
const output = new Array ( maxLength ) ;
@@ -1449,7 +1424,7 @@ function formatTypedArray(ctx, value, recurseTimes) {
1449
1424
return output ;
1450
1425
}
1451
1426
1452
- function formatSet ( ctx , value , recurseTimes ) {
1427
+ function formatSet ( value , size , ctx , ignored , recurseTimes ) {
1453
1428
const output = [ ] ;
1454
1429
ctx . indentationLvl += 2 ;
1455
1430
for ( const v of value ) {
@@ -1460,11 +1435,11 @@ function formatSet(ctx, value, recurseTimes) {
1460
1435
// arrays. For consistency's sake, do the same for `size`, even though this
1461
1436
// property isn't selected by ObjectGetOwnPropertyNames().
1462
1437
if ( ctx . showHidden )
1463
- output . push ( `[size]: ${ ctx . stylize ( `${ value . size } ` , 'number' ) } ` ) ;
1438
+ output . push ( `[size]: ${ ctx . stylize ( `${ size } ` , 'number' ) } ` ) ;
1464
1439
return output ;
1465
1440
}
1466
1441
1467
- function formatMap ( ctx , value , recurseTimes ) {
1442
+ function formatMap ( value , size , ctx , ignored , recurseTimes ) {
1468
1443
const output = [ ] ;
1469
1444
ctx . indentationLvl += 2 ;
1470
1445
for ( const [ k , v ] of value ) {
@@ -1474,7 +1449,7 @@ function formatMap(ctx, value, recurseTimes) {
1474
1449
ctx . indentationLvl -= 2 ;
1475
1450
// See comment in formatSet
1476
1451
if ( ctx . showHidden )
1477
- output . push ( `[size]: ${ ctx . stylize ( `${ value . size } ` , 'number' ) } ` ) ;
1452
+ output . push ( `[size]: ${ ctx . stylize ( `${ size } ` , 'number' ) } ` ) ;
1478
1453
return output ;
1479
1454
}
1480
1455
@@ -1552,7 +1527,7 @@ function formatWeakMap(ctx, value, recurseTimes) {
1552
1527
return formatMapIterInner ( ctx , recurseTimes , entries , kWeak ) ;
1553
1528
}
1554
1529
1555
- function formatIterator ( ctx , value , recurseTimes , keys , braces ) {
1530
+ function formatIterator ( braces , ctx , value , recurseTimes ) {
1556
1531
const [ entries , isKeyValue ] = previewEntries ( value , true ) ;
1557
1532
if ( isKeyValue ) {
1558
1533
// Mark entry iterators as such.
@@ -1587,7 +1562,7 @@ function formatProperty(ctx, value, recurseTimes, key, type, desc) {
1587
1562
desc = desc || ObjectGetOwnPropertyDescriptor ( value , key ) ||
1588
1563
{ value : value [ key ] , enumerable : true } ;
1589
1564
if ( desc . value !== undefined ) {
1590
- const diff = ( type !== kObjectType || ctx . compact !== true ) ? 2 : 3 ;
1565
+ const diff = ( ctx . compact !== true || type !== kObjectType ) ? 2 : 3 ;
1591
1566
ctx . indentationLvl += diff ;
1592
1567
str = formatValue ( ctx , desc . value , recurseTimes ) ;
1593
1568
if ( diff === 3 ) {
0 commit comments