@@ -10,6 +10,7 @@ const {
10
10
DatePrototypeToString,
11
11
ErrorPrototypeToString,
12
12
JSONStringify,
13
+ MapPrototype,
13
14
MapPrototypeEntries,
14
15
MathFloor,
15
16
MathMax,
@@ -21,10 +22,8 @@ const {
21
22
NumberPrototypeValueOf,
22
23
ObjectAssign,
23
24
ObjectCreate,
24
- ObjectDefineProperties,
25
25
ObjectDefineProperty,
26
26
ObjectGetOwnPropertyDescriptor,
27
- ObjectGetOwnPropertyDescriptors,
28
27
ObjectGetOwnPropertyNames,
29
28
ObjectGetOwnPropertySymbols,
30
29
ObjectGetPrototypeOf,
@@ -34,6 +33,7 @@ const {
34
33
ObjectPrototypePropertyIsEnumerable,
35
34
ObjectSeal,
36
35
RegExpPrototypeToString,
36
+ SetPrototype,
37
37
SetPrototypeValues,
38
38
StringPrototypeValueOf,
39
39
SymbolPrototypeToString,
@@ -113,6 +113,11 @@ const assert = require('internal/assert');
113
113
114
114
const { NativeModule } = require ( 'internal/bootstrap/loaders' ) ;
115
115
116
+ const setSizeGetter = uncurryThis (
117
+ ObjectGetOwnPropertyDescriptor ( SetPrototype , 'size' ) . get ) ;
118
+ const mapSizeGetter = uncurryThis (
119
+ ObjectGetOwnPropertyDescriptor ( MapPrototype , 'size' ) . get ) ;
120
+
116
121
let hexSlice ;
117
122
118
123
const builtInObjects = new Set (
@@ -651,51 +656,6 @@ function findTypedConstructor(value) {
651
656
}
652
657
}
653
658
654
- let lazyNullPrototypeCache ;
655
- // Creates a subclass and name
656
- // the constructor as `${clazz} : null prototype`
657
- function clazzWithNullPrototype ( clazz , name ) {
658
- if ( lazyNullPrototypeCache === undefined ) {
659
- lazyNullPrototypeCache = new Map ( ) ;
660
- } else {
661
- const cachedClass = lazyNullPrototypeCache . get ( clazz ) ;
662
- if ( cachedClass !== undefined ) {
663
- return cachedClass ;
664
- }
665
- }
666
- class NullPrototype extends clazz {
667
- get [ SymbolToStringTag ] ( ) {
668
- return '' ;
669
- }
670
- }
671
- ObjectDefineProperty ( NullPrototype . prototype . constructor , 'name' ,
672
- { value : `[${ name } : null prototype]` } ) ;
673
- lazyNullPrototypeCache . set ( clazz , NullPrototype ) ;
674
- return NullPrototype ;
675
- }
676
-
677
- function noPrototypeIterator ( ctx , value , recurseTimes ) {
678
- let newVal ;
679
- if ( isSet ( value ) ) {
680
- const clazz = clazzWithNullPrototype ( Set , 'Set' ) ;
681
- newVal = new clazz ( SetPrototypeValues ( value ) ) ;
682
- } else if ( isMap ( value ) ) {
683
- const clazz = clazzWithNullPrototype ( Map , 'Map' ) ;
684
- newVal = new clazz ( MapPrototypeEntries ( value ) ) ;
685
- } else if ( ArrayIsArray ( value ) ) {
686
- const clazz = clazzWithNullPrototype ( Array , 'Array' ) ;
687
- newVal = new clazz ( value . length ) ;
688
- } else if ( isTypedArray ( value ) ) {
689
- const constructor = findTypedConstructor ( value ) ;
690
- const clazz = clazzWithNullPrototype ( constructor , constructor . name ) ;
691
- newVal = new clazz ( value ) ;
692
- }
693
- if ( newVal !== undefined ) {
694
- ObjectDefineProperties ( newVal , ObjectGetOwnPropertyDescriptors ( value ) ) ;
695
- return formatRaw ( ctx , newVal , recurseTimes ) ;
696
- }
697
- }
698
-
699
659
// Note: using `formatValue` directly requires the indentation level to be
700
660
// corrected by setting `ctx.indentationLvL += diff` and then to decrease the
701
661
// value afterwards again.
@@ -798,7 +758,9 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
798
758
let extrasType = kObjectType ;
799
759
800
760
// Iterators and the rest are split to reduce checks.
801
- if ( value [ SymbolIterator ] ) {
761
+ // We have to check all values in case the constructor is set to null.
762
+ // Otherwise it would not possible to identify all types properly.
763
+ if ( value [ SymbolIterator ] || constructor === null ) {
802
764
noIterator = false ;
803
765
if ( ArrayIsArray ( value ) ) {
804
766
keys = getOwnNonIndexProperties ( value , filter ) ;
@@ -810,37 +772,66 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
810
772
extrasType = kArrayExtrasType ;
811
773
formatter = formatArray ;
812
774
} else if ( isSet ( value ) ) {
775
+ const size = setSizeGetter ( value ) ;
813
776
keys = getKeys ( value , ctx . showHidden ) ;
814
- const prefix = getPrefix ( constructor , tag , 'Set' ) ;
815
- if ( value . size === 0 && keys . length === 0 && protoProps === undefined )
777
+ let prefix = '' ;
778
+ if ( constructor !== null ) {
779
+ if ( constructor === tag )
780
+ tag = '' ;
781
+ prefix = getPrefix ( `${ constructor } ` , tag , '' ) ;
782
+ formatter = formatSet . bind ( null , value , size ) ;
783
+ } else {
784
+ prefix = getPrefix ( constructor , tag , 'Set' ) ;
785
+ formatter = formatSet . bind ( null , SetPrototypeValues ( value ) , size ) ;
786
+ }
787
+ if ( size === 0 && keys . length === 0 && protoProps === undefined )
816
788
return `${ prefix } {}` ;
817
789
braces = [ `${ prefix } {` , '}' ] ;
818
- formatter = formatSet ;
819
790
} else if ( isMap ( value ) ) {
791
+ const size = mapSizeGetter ( value ) ;
820
792
keys = getKeys ( value , ctx . showHidden ) ;
821
- const prefix = getPrefix ( constructor , tag , 'Map' ) ;
822
- if ( value . size === 0 && keys . length === 0 && protoProps === undefined )
793
+ let prefix = '' ;
794
+ if ( constructor !== null ) {
795
+ if ( constructor === tag )
796
+ tag = '' ;
797
+ prefix = getPrefix ( `${ constructor } ` , tag , '' ) ;
798
+ formatter = formatMap . bind ( null , value , size ) ;
799
+ } else {
800
+ prefix = getPrefix ( constructor , tag , 'Map' ) ;
801
+ formatter = formatMap . bind ( null , MapPrototypeEntries ( value ) , size ) ;
802
+ }
803
+ if ( size === 0 && keys . length === 0 && protoProps === undefined )
823
804
return `${ prefix } {}` ;
824
805
braces = [ `${ prefix } {` , '}' ] ;
825
- formatter = formatMap ;
826
806
} else if ( isTypedArray ( value ) ) {
827
807
keys = getOwnNonIndexProperties ( value , filter ) ;
828
- const prefix = constructor !== null ?
829
- getPrefix ( constructor , tag ) :
830
- getPrefix ( constructor , tag , findTypedConstructor ( value ) . name ) ;
808
+ let bound = value ;
809
+ let prefix = '' ;
810
+ if ( constructor === null ) {
811
+ const constr = findTypedConstructor ( value ) ;
812
+ prefix = getPrefix ( constructor , tag , constr . name ) ;
813
+ // Reconstruct the array information.
814
+ bound = new constr ( value ) ;
815
+ } else {
816
+ prefix = getPrefix ( constructor , tag ) ;
817
+ }
831
818
braces = [ `${ prefix } [` , ']' ] ;
832
819
if ( value . length === 0 && keys . length === 0 && ! ctx . showHidden )
833
820
return `${ braces [ 0 ] } ]` ;
834
- formatter = formatTypedArray ;
821
+ // Special handle the value. The original value is required below. The
822
+ // bound function is required to reconstruct missing information.
823
+ formatter = formatTypedArray . bind ( null , bound ) ;
835
824
extrasType = kArrayExtrasType ;
836
825
} else if ( isMapIterator ( value ) ) {
837
826
keys = getKeys ( value , ctx . showHidden ) ;
838
827
braces = getIteratorBraces ( 'Map' , tag ) ;
839
- formatter = formatIterator ;
828
+ // Add braces to the formatter parameters.
829
+ formatter = formatIterator . bind ( null , braces ) ;
840
830
} else if ( isSetIterator ( value ) ) {
841
831
keys = getKeys ( value , ctx . showHidden ) ;
842
832
braces = getIteratorBraces ( 'Set' , tag ) ;
843
- formatter = formatIterator ;
833
+ // Add braces to the formatter parameters.
834
+ formatter = formatIterator . bind ( null , braces ) ;
844
835
} else {
845
836
noIterator = true ;
846
837
}
@@ -918,36 +909,20 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
918
909
formatter = ctx . showHidden ? formatWeakMap : formatWeakCollection ;
919
910
} else if ( isModuleNamespaceObject ( value ) ) {
920
911
braces [ 0 ] = `[${ tag } ] {` ;
921
- formatter = formatNamespaceObject ;
912
+ // Special handle keys for namespace objects.
913
+ formatter = formatNamespaceObject . bind ( null , keys ) ;
922
914
} else if ( isBoxedPrimitive ( value ) ) {
923
915
base = getBoxedBase ( value , ctx , keys , constructor , tag ) ;
924
916
if ( keys . length === 0 && protoProps === undefined ) {
925
917
return base ;
926
918
}
927
919
} else {
928
- // The input prototype got manipulated. Special handle these. We have to
929
- // rebuild the information so we are able to display everything.
930
- if ( constructor === null ) {
931
- const specialIterator = noPrototypeIterator ( ctx , value , recurseTimes ) ;
932
- if ( specialIterator ) {
933
- return specialIterator ;
934
- }
935
- }
936
- if ( isMapIterator ( value ) ) {
937
- braces = getIteratorBraces ( 'Map' , tag ) ;
938
- formatter = formatIterator ;
939
- } else if ( isSetIterator ( value ) ) {
940
- braces = getIteratorBraces ( 'Set' , tag ) ;
941
- formatter = formatIterator ;
942
- // Handle other regular objects again.
943
- } else {
944
- if ( keys . length === 0 && protoProps === undefined ) {
945
- if ( isExternal ( value ) )
946
- return ctx . stylize ( '[External]' , 'special' ) ;
947
- return `${ getCtxStyle ( value , constructor , tag ) } {}` ;
948
- }
949
- braces [ 0 ] = `${ getCtxStyle ( value , constructor , tag ) } {` ;
920
+ if ( keys . length === 0 && protoProps === undefined ) {
921
+ if ( isExternal ( value ) )
922
+ return ctx . stylize ( '[External]' , 'special' ) ;
923
+ return `${ getCtxStyle ( value , constructor , tag ) } {}` ;
950
924
}
925
+ braces [ 0 ] = `${ getCtxStyle ( value , constructor , tag ) } {` ;
951
926
}
952
927
}
953
928
@@ -964,7 +939,7 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
964
939
let output ;
965
940
const indentationLvl = ctx . indentationLvl ;
966
941
try {
967
- output = formatter ( ctx , value , recurseTimes , keys , braces ) ;
942
+ output = formatter ( ctx , value , recurseTimes ) ;
968
943
for ( i = 0 ; i < keys . length ; i ++ ) {
969
944
output . push (
970
945
formatProperty ( ctx , value , recurseTimes , keys [ i ] , extrasType ) ) ;
@@ -1322,7 +1297,7 @@ function formatPrimitive(fn, value, ctx) {
1322
1297
return fn ( SymbolPrototypeToString ( value ) , 'symbol' ) ;
1323
1298
}
1324
1299
1325
- function formatNamespaceObject ( ctx , value , recurseTimes , keys ) {
1300
+ function formatNamespaceObject ( keys , ctx , value , recurseTimes ) {
1326
1301
const output = new Array ( keys . length ) ;
1327
1302
for ( let i = 0 ; i < keys . length ; i ++ ) {
1328
1303
try {
@@ -1424,7 +1399,7 @@ function formatArray(ctx, value, recurseTimes) {
1424
1399
return output ;
1425
1400
}
1426
1401
1427
- function formatTypedArray ( ctx , value , recurseTimes ) {
1402
+ function formatTypedArray ( value , ctx , ignored , recurseTimes ) {
1428
1403
const maxLength = MathMin ( MathMax ( 0 , ctx . maxArrayLength ) , value . length ) ;
1429
1404
const remaining = value . length - maxLength ;
1430
1405
const output = new Array ( maxLength ) ;
@@ -1455,7 +1430,7 @@ function formatTypedArray(ctx, value, recurseTimes) {
1455
1430
return output ;
1456
1431
}
1457
1432
1458
- function formatSet ( ctx , value , recurseTimes ) {
1433
+ function formatSet ( value , size , ctx , ignored , recurseTimes ) {
1459
1434
const output = [ ] ;
1460
1435
ctx . indentationLvl += 2 ;
1461
1436
for ( const v of value ) {
@@ -1466,11 +1441,11 @@ function formatSet(ctx, value, recurseTimes) {
1466
1441
// arrays. For consistency's sake, do the same for `size`, even though this
1467
1442
// property isn't selected by ObjectGetOwnPropertyNames().
1468
1443
if ( ctx . showHidden )
1469
- output . push ( `[size]: ${ ctx . stylize ( `${ value . size } ` , 'number' ) } ` ) ;
1444
+ output . push ( `[size]: ${ ctx . stylize ( `${ size } ` , 'number' ) } ` ) ;
1470
1445
return output ;
1471
1446
}
1472
1447
1473
- function formatMap ( ctx , value , recurseTimes ) {
1448
+ function formatMap ( value , size , ctx , ignored , recurseTimes ) {
1474
1449
const output = [ ] ;
1475
1450
ctx . indentationLvl += 2 ;
1476
1451
for ( const [ k , v ] of value ) {
@@ -1480,7 +1455,7 @@ function formatMap(ctx, value, recurseTimes) {
1480
1455
ctx . indentationLvl -= 2 ;
1481
1456
// See comment in formatSet
1482
1457
if ( ctx . showHidden )
1483
- output . push ( `[size]: ${ ctx . stylize ( `${ value . size } ` , 'number' ) } ` ) ;
1458
+ output . push ( `[size]: ${ ctx . stylize ( `${ size } ` , 'number' ) } ` ) ;
1484
1459
return output ;
1485
1460
}
1486
1461
@@ -1558,7 +1533,7 @@ function formatWeakMap(ctx, value, recurseTimes) {
1558
1533
return formatMapIterInner ( ctx , recurseTimes , entries , kWeak ) ;
1559
1534
}
1560
1535
1561
- function formatIterator ( ctx , value , recurseTimes , keys , braces ) {
1536
+ function formatIterator ( braces , ctx , value , recurseTimes ) {
1562
1537
const [ entries , isKeyValue ] = previewEntries ( value , true ) ;
1563
1538
if ( isKeyValue ) {
1564
1539
// Mark entry iterators as such.
@@ -1593,7 +1568,7 @@ function formatProperty(ctx, value, recurseTimes, key, type, desc) {
1593
1568
desc = desc || ObjectGetOwnPropertyDescriptor ( value , key ) ||
1594
1569
{ value : value [ key ] , enumerable : true } ;
1595
1570
if ( desc . value !== undefined ) {
1596
- const diff = ( type !== kObjectType || ctx . compact !== true ) ? 2 : 3 ;
1571
+ const diff = ( ctx . compact !== true || type !== kObjectType ) ? 2 : 3 ;
1597
1572
ctx . indentationLvl += diff ;
1598
1573
str = formatValue ( ctx , desc . value , recurseTimes ) ;
1599
1574
if ( diff === 3 ) {
0 commit comments