@@ -26,7 +26,9 @@ const {
2626 MathMin,
2727 MathRound,
2828 MathSqrt,
29+ MathTrunc,
2930 Number,
31+ NumberIsFinite,
3032 NumberIsNaN,
3133 NumberParseFloat,
3234 NumberParseInt,
@@ -168,7 +170,8 @@ const inspectDefaultOptions = ObjectSeal({
168170 breakLength : 80 ,
169171 compact : 3 ,
170172 sorted : false ,
171- getters : false
173+ getters : false ,
174+ numericSeparator : false ,
172175} ) ;
173176
174177const kObjectType = 0 ;
@@ -244,6 +247,7 @@ function getUserOptions(ctx, isCrossContext) {
244247 compact : ctx . compact ,
245248 sorted : ctx . sorted ,
246249 getters : ctx . getters ,
250+ numericSeparator : ctx . numericSeparator ,
247251 ...ctx . userOptions
248252 } ;
249253
@@ -301,7 +305,8 @@ function inspect(value, opts) {
301305 breakLength : inspectDefaultOptions . breakLength ,
302306 compact : inspectDefaultOptions . compact ,
303307 sorted : inspectDefaultOptions . sorted ,
304- getters : inspectDefaultOptions . getters
308+ getters : inspectDefaultOptions . getters ,
309+ numericSeparator : inspectDefaultOptions . numericSeparator ,
305310 } ;
306311 if ( arguments . length > 1 ) {
307312 // Legacy...
@@ -949,7 +954,7 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
949954 formatter = formatArrayBuffer ;
950955 } else if ( keys . length === 0 && protoProps === undefined ) {
951956 return prefix +
952- `{ byteLength: ${ formatNumber ( ctx . stylize , value . byteLength ) } }` ;
957+ `{ byteLength: ${ formatNumber ( ctx . stylize , value . byteLength , false ) } }` ;
953958 }
954959 braces [ 0 ] = `${ prefix } {` ;
955960 ArrayPrototypeUnshift ( keys , 'byteLength' ) ;
@@ -1434,13 +1439,61 @@ function handleMaxCallStackSize(ctx, err, constructorName, indentationLvl) {
14341439 assert . fail ( err . stack ) ;
14351440}
14361441
1437- function formatNumber ( fn , value ) {
1438- // Format -0 as '-0'. Checking `value === -0` won't distinguish 0 from -0.
1439- return fn ( ObjectIs ( value , - 0 ) ? '-0' : `${ value } ` , 'number' ) ;
1442+ function addNumericSeparator ( integerString ) {
1443+ let result = '' ;
1444+ let i = integerString . length ;
1445+ const start = integerString . startsWith ( '-' ) ? 1 : 0 ;
1446+ for ( ; i >= start + 4 ; i -= 3 ) {
1447+ result = `_${ integerString . slice ( i - 3 , i ) } ${ result } ` ;
1448+ }
1449+ return i === integerString . length ?
1450+ integerString :
1451+ `${ integerString . slice ( 0 , i ) } ${ result } ` ;
1452+ }
1453+
1454+ function addNumericSeparatorEnd ( integerString ) {
1455+ let result = '' ;
1456+ let i = 0 ;
1457+ for ( ; i < integerString . length - 3 ; i += 3 ) {
1458+ result += `${ integerString . slice ( i , i + 3 ) } _` ;
1459+ }
1460+ return i === 0 ?
1461+ integerString :
1462+ `${ result } ${ integerString . slice ( i ) } ` ;
1463+ }
1464+
1465+ function formatNumber ( fn , number , numericSeparator ) {
1466+ if ( ! numericSeparator ) {
1467+ // Format -0 as '-0'. Checking `number === -0` won't distinguish 0 from -0.
1468+ if ( ObjectIs ( number , - 0 ) ) {
1469+ return fn ( '-0' , 'number' ) ;
1470+ }
1471+ return fn ( `${ number } ` , 'number' ) ;
1472+ }
1473+ const integer = MathTrunc ( number ) ;
1474+ const string = String ( integer ) ;
1475+ if ( integer === number ) {
1476+ if ( ! NumberIsFinite ( number ) || string . includes ( 'e' ) ) {
1477+ return fn ( string , 'number' ) ;
1478+ }
1479+ return fn ( `${ addNumericSeparator ( string ) } ` , 'number' ) ;
1480+ }
1481+ if ( NumberIsNaN ( number ) ) {
1482+ return fn ( string , 'number' ) ;
1483+ }
1484+ return fn ( `${
1485+ addNumericSeparator ( string )
1486+ } .${
1487+ addNumericSeparatorEnd ( String ( number ) . slice ( string . length + 1 ) )
1488+ } `, 'number' ) ;
14401489}
14411490
1442- function formatBigInt ( fn , value ) {
1443- return fn ( `${ value } n` , 'bigint' ) ;
1491+ function formatBigInt ( fn , bigint , numericSeparator ) {
1492+ const string = String ( bigint ) ;
1493+ if ( ! numericSeparator ) {
1494+ return fn ( `${ string } n` , 'bigint' ) ;
1495+ }
1496+ return fn ( `${ addNumericSeparator ( string ) } n` , 'bigint' ) ;
14441497}
14451498
14461499function formatPrimitive ( fn , value , ctx ) {
@@ -1464,9 +1517,9 @@ function formatPrimitive(fn, value, ctx) {
14641517 return fn ( strEscape ( value ) , 'string' ) + trailer ;
14651518 }
14661519 if ( typeof value === 'number' )
1467- return formatNumber ( fn , value ) ;
1520+ return formatNumber ( fn , value , ctx . numericSeparator ) ;
14681521 if ( typeof value === 'bigint' )
1469- return formatBigInt ( fn , value ) ;
1522+ return formatBigInt ( fn , value , ctx . numericSeparator ) ;
14701523 if ( typeof value === 'boolean' )
14711524 return fn ( `${ value } ` , 'boolean' ) ;
14721525 if ( typeof value === 'undefined' )
@@ -1583,8 +1636,9 @@ function formatTypedArray(value, length, ctx, ignored, recurseTimes) {
15831636 const elementFormatter = value . length > 0 && typeof value [ 0 ] === 'number' ?
15841637 formatNumber :
15851638 formatBigInt ;
1586- for ( let i = 0 ; i < maxLength ; ++ i )
1587- output [ i ] = elementFormatter ( ctx . stylize , value [ i ] ) ;
1639+ for ( let i = 0 ; i < maxLength ; ++ i ) {
1640+ output [ i ] = elementFormatter ( ctx . stylize , value [ i ] , ctx . numericSeparator ) ;
1641+ }
15881642 if ( remaining > 0 ) {
15891643 output [ maxLength ] = `... ${ remaining } more item${ remaining > 1 ? 's' : '' } ` ;
15901644 }
@@ -1928,8 +1982,8 @@ function tryStringify(arg) {
19281982 if ( ! CIRCULAR_ERROR_MESSAGE ) {
19291983 try {
19301984 const a = { } ; a . a = a ; JSONStringify ( a ) ;
1931- } catch ( err ) {
1932- CIRCULAR_ERROR_MESSAGE = firstErrorLine ( err ) ;
1985+ } catch ( circularError ) {
1986+ CIRCULAR_ERROR_MESSAGE = firstErrorLine ( circularError ) ;
19331987 }
19341988 }
19351989 if ( err . name === 'TypeError' &&
@@ -1952,6 +2006,22 @@ function formatWithOptions(inspectOptions, ...args) {
19522006 return formatWithOptionsInternal ( inspectOptions , args ) ;
19532007}
19542008
2009+ function formatNumberNoColor ( number , options ) {
2010+ return formatNumber (
2011+ stylizeNoColor ,
2012+ number ,
2013+ options ?. numericSeparator ?? inspectDefaultOptions . numericSeparator
2014+ ) ;
2015+ }
2016+
2017+ function formatBigIntNoColor ( bigint , options ) {
2018+ return formatBigInt (
2019+ stylizeNoColor ,
2020+ bigint ,
2021+ options ?. numericSeparator ?? inspectDefaultOptions . numericSeparator
2022+ ) ;
2023+ }
2024+
19552025function formatWithOptionsInternal ( inspectOptions , args ) {
19562026 const first = args [ 0 ] ;
19572027 let a = 0 ;
@@ -1973,9 +2043,9 @@ function formatWithOptionsInternal(inspectOptions, args) {
19732043 case 115 : // 's'
19742044 const tempArg = args [ ++ a ] ;
19752045 if ( typeof tempArg === 'number' ) {
1976- tempStr = formatNumber ( stylizeNoColor , tempArg ) ;
2046+ tempStr = formatNumberNoColor ( tempArg , inspectOptions ) ;
19772047 } else if ( typeof tempArg === 'bigint' ) {
1978- tempStr = ` ${ tempArg } n` ;
2048+ tempStr = formatBigIntNoColor ( tempArg , inspectOptions ) ;
19792049 } else if ( typeof tempArg !== 'object' ||
19802050 tempArg === null ||
19812051 ! hasBuiltInToString ( tempArg ) ) {
@@ -1995,11 +2065,11 @@ function formatWithOptionsInternal(inspectOptions, args) {
19952065 case 100 : // 'd'
19962066 const tempNum = args [ ++ a ] ;
19972067 if ( typeof tempNum === 'bigint' ) {
1998- tempStr = ` ${ tempNum } n` ;
2068+ tempStr = formatBigIntNoColor ( tempNum , inspectOptions ) ;
19992069 } else if ( typeof tempNum === 'symbol' ) {
20002070 tempStr = 'NaN' ;
20012071 } else {
2002- tempStr = formatNumber ( stylizeNoColor , Number ( tempNum ) ) ;
2072+ tempStr = formatNumberNoColor ( Number ( tempNum ) , inspectOptions ) ;
20032073 }
20042074 break ;
20052075 case 79 : // 'O'
@@ -2016,21 +2086,21 @@ function formatWithOptionsInternal(inspectOptions, args) {
20162086 case 105 : // 'i'
20172087 const tempInteger = args [ ++ a ] ;
20182088 if ( typeof tempInteger === 'bigint' ) {
2019- tempStr = ` ${ tempInteger } n` ;
2089+ tempStr = formatBigIntNoColor ( tempInteger , inspectOptions ) ;
20202090 } else if ( typeof tempInteger === 'symbol' ) {
20212091 tempStr = 'NaN' ;
20222092 } else {
2023- tempStr = formatNumber ( stylizeNoColor ,
2024- NumberParseInt ( tempInteger ) ) ;
2093+ tempStr = formatNumberNoColor (
2094+ NumberParseInt ( tempInteger ) , inspectOptions ) ;
20252095 }
20262096 break ;
20272097 case 102 : // 'f'
20282098 const tempFloat = args [ ++ a ] ;
20292099 if ( typeof tempFloat === 'symbol' ) {
20302100 tempStr = 'NaN' ;
20312101 } else {
2032- tempStr = formatNumber ( stylizeNoColor ,
2033- NumberParseFloat ( tempFloat ) ) ;
2102+ tempStr = formatNumberNoColor (
2103+ NumberParseFloat ( tempFloat ) , inspectOptions ) ;
20342104 }
20352105 break ;
20362106 case 99 : // 'c'
0 commit comments