@@ -10,6 +10,7 @@ const {
1010 DatePrototypeToString,
1111 ErrorPrototypeToString,
1212 JSONStringify,
13+ MapPrototype,
1314 MapPrototypeEntries,
1415 MathFloor,
1516 MathMax,
@@ -21,10 +22,8 @@ const {
2122 NumberPrototypeValueOf,
2223 ObjectAssign,
2324 ObjectCreate,
24- ObjectDefineProperties,
2525 ObjectDefineProperty,
2626 ObjectGetOwnPropertyDescriptor,
27- ObjectGetOwnPropertyDescriptors,
2827 ObjectGetOwnPropertyNames,
2928 ObjectGetOwnPropertySymbols,
3029 ObjectGetPrototypeOf,
@@ -34,6 +33,7 @@ const {
3433 ObjectPrototypePropertyIsEnumerable,
3534 ObjectSeal,
3635 RegExpPrototypeToString,
36+ SetPrototype,
3737 SetPrototypeValues,
3838 StringPrototypeValueOf,
3939 SymbolPrototypeToString,
@@ -113,6 +113,11 @@ const assert = require('internal/assert');
113113
114114const { NativeModule } = require ( 'internal/bootstrap/loaders' ) ;
115115
116+ const setSizeGetter = uncurryThis (
117+ ObjectGetOwnPropertyDescriptor ( SetPrototype , 'size' ) . get ) ;
118+ const mapSizeGetter = uncurryThis (
119+ ObjectGetOwnPropertyDescriptor ( MapPrototype , 'size' ) . get ) ;
120+
116121let hexSlice ;
117122
118123const builtInObjects = new Set (
@@ -646,51 +651,6 @@ function findTypedConstructor(value) {
646651 }
647652}
648653
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-
694654// Note: using `formatValue` directly requires the indentation level to be
695655// corrected by setting `ctx.indentationLvL += diff` and then to decrease the
696656// value afterwards again.
@@ -793,7 +753,9 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
793753 let extrasType = kObjectType ;
794754
795755 // 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 ) {
797759 noIterator = false ;
798760 if ( ArrayIsArray ( value ) ) {
799761 keys = getOwnNonIndexProperties ( value , filter ) ;
@@ -805,37 +767,66 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
805767 extrasType = kArrayExtrasType ;
806768 formatter = formatArray ;
807769 } else if ( isSet ( value ) ) {
770+ const size = setSizeGetter ( value ) ;
808771 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 )
811783 return `${ prefix } {}` ;
812784 braces = [ `${ prefix } {` , '}' ] ;
813- formatter = formatSet ;
814785 } else if ( isMap ( value ) ) {
786+ const size = mapSizeGetter ( value ) ;
815787 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 )
818799 return `${ prefix } {}` ;
819800 braces = [ `${ prefix } {` , '}' ] ;
820- formatter = formatMap ;
821801 } else if ( isTypedArray ( value ) ) {
822802 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+ }
826813 braces = [ `${ prefix } [` , ']' ] ;
827814 if ( value . length === 0 && keys . length === 0 && ! ctx . showHidden )
828815 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 ) ;
830819 extrasType = kArrayExtrasType ;
831820 } else if ( isMapIterator ( value ) ) {
832821 keys = getKeys ( value , ctx . showHidden ) ;
833822 braces = getIteratorBraces ( 'Map' , tag ) ;
834- formatter = formatIterator ;
823+ // Add braces to the formatter parameters.
824+ formatter = formatIterator . bind ( null , braces ) ;
835825 } else if ( isSetIterator ( value ) ) {
836826 keys = getKeys ( value , ctx . showHidden ) ;
837827 braces = getIteratorBraces ( 'Set' , tag ) ;
838- formatter = formatIterator ;
828+ // Add braces to the formatter parameters.
829+ formatter = formatIterator . bind ( null , braces ) ;
839830 } else {
840831 noIterator = true ;
841832 }
@@ -913,36 +904,20 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
913904 formatter = ctx . showHidden ? formatWeakMap : formatWeakCollection ;
914905 } else if ( isModuleNamespaceObject ( value ) ) {
915906 braces [ 0 ] = `[${ tag } ] {` ;
916- formatter = formatNamespaceObject ;
907+ // Special handle keys for namespace objects.
908+ formatter = formatNamespaceObject . bind ( null , keys ) ;
917909 } else if ( isBoxedPrimitive ( value ) ) {
918910 base = getBoxedBase ( value , ctx , keys , constructor , tag ) ;
919911 if ( keys . length === 0 && protoProps === undefined ) {
920912 return base ;
921913 }
922914 } 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 ) } {}` ;
945919 }
920+ braces [ 0 ] = `${ getCtxStyle ( value , constructor , tag ) } {` ;
946921 }
947922 }
948923
@@ -959,7 +934,7 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
959934 let output ;
960935 const indentationLvl = ctx . indentationLvl ;
961936 try {
962- output = formatter ( ctx , value , recurseTimes , keys , braces ) ;
937+ output = formatter ( ctx , value , recurseTimes ) ;
963938 for ( i = 0 ; i < keys . length ; i ++ ) {
964939 output . push (
965940 formatProperty ( ctx , value , recurseTimes , keys [ i ] , extrasType ) ) ;
@@ -1317,7 +1292,7 @@ function formatPrimitive(fn, value, ctx) {
13171292 return fn ( SymbolPrototypeToString ( value ) , 'symbol' ) ;
13181293}
13191294
1320- function formatNamespaceObject ( ctx , value , recurseTimes , keys ) {
1295+ function formatNamespaceObject ( keys , ctx , value , recurseTimes ) {
13211296 const output = new Array ( keys . length ) ;
13221297 for ( let i = 0 ; i < keys . length ; i ++ ) {
13231298 try {
@@ -1419,7 +1394,7 @@ function formatArray(ctx, value, recurseTimes) {
14191394 return output ;
14201395}
14211396
1422- function formatTypedArray ( ctx , value , recurseTimes ) {
1397+ function formatTypedArray ( value , ctx , ignored , recurseTimes ) {
14231398 const maxLength = MathMin ( MathMax ( 0 , ctx . maxArrayLength ) , value . length ) ;
14241399 const remaining = value . length - maxLength ;
14251400 const output = new Array ( maxLength ) ;
@@ -1450,7 +1425,7 @@ function formatTypedArray(ctx, value, recurseTimes) {
14501425 return output ;
14511426}
14521427
1453- function formatSet ( ctx , value , recurseTimes ) {
1428+ function formatSet ( value , size , ctx , ignored , recurseTimes ) {
14541429 const output = [ ] ;
14551430 ctx . indentationLvl += 2 ;
14561431 for ( const v of value ) {
@@ -1461,11 +1436,11 @@ function formatSet(ctx, value, recurseTimes) {
14611436 // arrays. For consistency's sake, do the same for `size`, even though this
14621437 // property isn't selected by ObjectGetOwnPropertyNames().
14631438 if ( ctx . showHidden )
1464- output . push ( `[size]: ${ ctx . stylize ( `${ value . size } ` , 'number' ) } ` ) ;
1439+ output . push ( `[size]: ${ ctx . stylize ( `${ size } ` , 'number' ) } ` ) ;
14651440 return output ;
14661441}
14671442
1468- function formatMap ( ctx , value , recurseTimes ) {
1443+ function formatMap ( value , size , ctx , ignored , recurseTimes ) {
14691444 const output = [ ] ;
14701445 ctx . indentationLvl += 2 ;
14711446 for ( const [ k , v ] of value ) {
@@ -1475,7 +1450,7 @@ function formatMap(ctx, value, recurseTimes) {
14751450 ctx . indentationLvl -= 2 ;
14761451 // See comment in formatSet
14771452 if ( ctx . showHidden )
1478- output . push ( `[size]: ${ ctx . stylize ( `${ value . size } ` , 'number' ) } ` ) ;
1453+ output . push ( `[size]: ${ ctx . stylize ( `${ size } ` , 'number' ) } ` ) ;
14791454 return output ;
14801455}
14811456
@@ -1553,7 +1528,7 @@ function formatWeakMap(ctx, value, recurseTimes) {
15531528 return formatMapIterInner ( ctx , recurseTimes , entries , kWeak ) ;
15541529}
15551530
1556- function formatIterator ( ctx , value , recurseTimes , keys , braces ) {
1531+ function formatIterator ( braces , ctx , value , recurseTimes ) {
15571532 const [ entries , isKeyValue ] = previewEntries ( value , true ) ;
15581533 if ( isKeyValue ) {
15591534 // Mark entry iterators as such.
@@ -1588,7 +1563,7 @@ function formatProperty(ctx, value, recurseTimes, key, type, desc) {
15881563 desc = desc || ObjectGetOwnPropertyDescriptor ( value , key ) ||
15891564 { value : value [ key ] , enumerable : true } ;
15901565 if ( desc . value !== undefined ) {
1591- const diff = ( type !== kObjectType || ctx . compact !== true ) ? 2 : 3 ;
1566+ const diff = ( ctx . compact !== true || type !== kObjectType ) ? 2 : 3 ;
15921567 ctx . indentationLvl += diff ;
15931568 str = formatValue ( ctx , desc . value , recurseTimes ) ;
15941569 if ( diff === 3 ) {
0 commit comments