@@ -11,6 +11,7 @@ const {
1111 ErrorPrototypeToString,
1212 JSONStringify,
1313 Map,
14+ MapPrototype,
1415 MapPrototypeEntries,
1516 MathFloor,
1617 MathMax,
@@ -22,10 +23,8 @@ const {
2223 NumberPrototypeValueOf,
2324 ObjectAssign,
2425 ObjectCreate,
25- ObjectDefineProperties,
2626 ObjectDefineProperty,
2727 ObjectGetOwnPropertyDescriptor,
28- ObjectGetOwnPropertyDescriptors,
2928 ObjectGetOwnPropertyNames,
3029 ObjectGetOwnPropertySymbols,
3130 ObjectGetPrototypeOf,
@@ -36,6 +35,7 @@ const {
3635 ObjectSeal,
3736 RegExpPrototypeToString,
3837 Set,
38+ SetPrototype,
3939 SetPrototypeValues,
4040 StringPrototypeValueOf,
4141 SymbolPrototypeToString,
@@ -115,6 +115,11 @@ const assert = require('internal/assert');
115115
116116const { NativeModule } = require ( 'internal/bootstrap/loaders' ) ;
117117
118+ const setSizeGetter = uncurryThis (
119+ ObjectGetOwnPropertyDescriptor ( SetPrototype , 'size' ) . get ) ;
120+ const mapSizeGetter = uncurryThis (
121+ ObjectGetOwnPropertyDescriptor ( MapPrototype , 'size' ) . get ) ;
122+
118123let hexSlice ;
119124
120125const builtInObjects = new Set (
@@ -648,51 +653,6 @@ function findTypedConstructor(value) {
648653 }
649654}
650655
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-
696656// Note: using `formatValue` directly requires the indentation level to be
697657// corrected by setting `ctx.indentationLvL += diff` and then to decrease the
698658// value afterwards again.
@@ -795,7 +755,9 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
795755 let extrasType = kObjectType ;
796756
797757 // 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 ) {
799761 noIterator = false ;
800762 if ( ArrayIsArray ( value ) ) {
801763 keys = getOwnNonIndexProperties ( value , filter ) ;
@@ -807,37 +769,66 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
807769 extrasType = kArrayExtrasType ;
808770 formatter = formatArray ;
809771 } else if ( isSet ( value ) ) {
772+ const size = setSizeGetter ( value ) ;
810773 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 )
813785 return `${ prefix } {}` ;
814786 braces = [ `${ prefix } {` , '}' ] ;
815- formatter = formatSet ;
816787 } else if ( isMap ( value ) ) {
788+ const size = mapSizeGetter ( value ) ;
817789 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 )
820801 return `${ prefix } {}` ;
821802 braces = [ `${ prefix } {` , '}' ] ;
822- formatter = formatMap ;
823803 } else if ( isTypedArray ( value ) ) {
824804 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+ }
828815 braces = [ `${ prefix } [` , ']' ] ;
829816 if ( value . length === 0 && keys . length === 0 && ! ctx . showHidden )
830817 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 ) ;
832821 extrasType = kArrayExtrasType ;
833822 } else if ( isMapIterator ( value ) ) {
834823 keys = getKeys ( value , ctx . showHidden ) ;
835824 braces = getIteratorBraces ( 'Map' , tag ) ;
836- formatter = formatIterator ;
825+ // Add braces to the formatter parameters.
826+ formatter = formatIterator . bind ( null , braces ) ;
837827 } else if ( isSetIterator ( value ) ) {
838828 keys = getKeys ( value , ctx . showHidden ) ;
839829 braces = getIteratorBraces ( 'Set' , tag ) ;
840- formatter = formatIterator ;
830+ // Add braces to the formatter parameters.
831+ formatter = formatIterator . bind ( null , braces ) ;
841832 } else {
842833 noIterator = true ;
843834 }
@@ -915,36 +906,20 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
915906 formatter = ctx . showHidden ? formatWeakMap : formatWeakCollection ;
916907 } else if ( isModuleNamespaceObject ( value ) ) {
917908 braces [ 0 ] = `[${ tag } ] {` ;
918- formatter = formatNamespaceObject ;
909+ // Special handle keys for namespace objects.
910+ formatter = formatNamespaceObject . bind ( null , keys ) ;
919911 } else if ( isBoxedPrimitive ( value ) ) {
920912 base = getBoxedBase ( value , ctx , keys , constructor , tag ) ;
921913 if ( keys . length === 0 && protoProps === undefined ) {
922914 return base ;
923915 }
924916 } 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 ) } {}` ;
947921 }
922+ braces [ 0 ] = `${ getCtxStyle ( value , constructor , tag ) } {` ;
948923 }
949924 }
950925
@@ -961,7 +936,7 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
961936 let output ;
962937 const indentationLvl = ctx . indentationLvl ;
963938 try {
964- output = formatter ( ctx , value , recurseTimes , keys , braces ) ;
939+ output = formatter ( ctx , value , recurseTimes ) ;
965940 for ( i = 0 ; i < keys . length ; i ++ ) {
966941 output . push (
967942 formatProperty ( ctx , value , recurseTimes , keys [ i ] , extrasType ) ) ;
@@ -1316,7 +1291,7 @@ function formatPrimitive(fn, value, ctx) {
13161291 return fn ( SymbolPrototypeToString ( value ) , 'symbol' ) ;
13171292}
13181293
1319- function formatNamespaceObject ( ctx , value , recurseTimes , keys ) {
1294+ function formatNamespaceObject ( keys , ctx , value , recurseTimes ) {
13201295 const output = new Array ( keys . length ) ;
13211296 for ( let i = 0 ; i < keys . length ; i ++ ) {
13221297 try {
@@ -1418,7 +1393,7 @@ function formatArray(ctx, value, recurseTimes) {
14181393 return output ;
14191394}
14201395
1421- function formatTypedArray ( ctx , value , recurseTimes ) {
1396+ function formatTypedArray ( value , ctx , ignored , recurseTimes ) {
14221397 const maxLength = MathMin ( MathMax ( 0 , ctx . maxArrayLength ) , value . length ) ;
14231398 const remaining = value . length - maxLength ;
14241399 const output = new Array ( maxLength ) ;
@@ -1449,7 +1424,7 @@ function formatTypedArray(ctx, value, recurseTimes) {
14491424 return output ;
14501425}
14511426
1452- function formatSet ( ctx , value , recurseTimes ) {
1427+ function formatSet ( value , size , ctx , ignored , recurseTimes ) {
14531428 const output = [ ] ;
14541429 ctx . indentationLvl += 2 ;
14551430 for ( const v of value ) {
@@ -1460,11 +1435,11 @@ function formatSet(ctx, value, recurseTimes) {
14601435 // arrays. For consistency's sake, do the same for `size`, even though this
14611436 // property isn't selected by ObjectGetOwnPropertyNames().
14621437 if ( ctx . showHidden )
1463- output . push ( `[size]: ${ ctx . stylize ( `${ value . size } ` , 'number' ) } ` ) ;
1438+ output . push ( `[size]: ${ ctx . stylize ( `${ size } ` , 'number' ) } ` ) ;
14641439 return output ;
14651440}
14661441
1467- function formatMap ( ctx , value , recurseTimes ) {
1442+ function formatMap ( value , size , ctx , ignored , recurseTimes ) {
14681443 const output = [ ] ;
14691444 ctx . indentationLvl += 2 ;
14701445 for ( const [ k , v ] of value ) {
@@ -1474,7 +1449,7 @@ function formatMap(ctx, value, recurseTimes) {
14741449 ctx . indentationLvl -= 2 ;
14751450 // See comment in formatSet
14761451 if ( ctx . showHidden )
1477- output . push ( `[size]: ${ ctx . stylize ( `${ value . size } ` , 'number' ) } ` ) ;
1452+ output . push ( `[size]: ${ ctx . stylize ( `${ size } ` , 'number' ) } ` ) ;
14781453 return output ;
14791454}
14801455
@@ -1552,7 +1527,7 @@ function formatWeakMap(ctx, value, recurseTimes) {
15521527 return formatMapIterInner ( ctx , recurseTimes , entries , kWeak ) ;
15531528}
15541529
1555- function formatIterator ( ctx , value , recurseTimes , keys , braces ) {
1530+ function formatIterator ( braces , ctx , value , recurseTimes ) {
15561531 const [ entries , isKeyValue ] = previewEntries ( value , true ) ;
15571532 if ( isKeyValue ) {
15581533 // Mark entry iterators as such.
@@ -1587,7 +1562,7 @@ function formatProperty(ctx, value, recurseTimes, key, type, desc) {
15871562 desc = desc || ObjectGetOwnPropertyDescriptor ( value , key ) ||
15881563 { value : value [ key ] , enumerable : true } ;
15891564 if ( desc . value !== undefined ) {
1590- const diff = ( type !== kObjectType || ctx . compact !== true ) ? 2 : 3 ;
1565+ const diff = ( ctx . compact !== true || type !== kObjectType ) ? 2 : 3 ;
15911566 ctx . indentationLvl += diff ;
15921567 str = formatValue ( ctx , desc . value , recurseTimes ) ;
15931568 if ( diff === 3 ) {
0 commit comments