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