@@ -26,7 +26,9 @@ const {
26
26
MathMin,
27
27
MathRound,
28
28
MathSqrt,
29
+ MathTrunc,
29
30
Number,
31
+ NumberIsFinite,
30
32
NumberIsNaN,
31
33
NumberParseFloat,
32
34
NumberParseInt,
@@ -168,7 +170,8 @@ const inspectDefaultOptions = ObjectSeal({
168
170
breakLength : 80 ,
169
171
compact : 3 ,
170
172
sorted : false ,
171
- getters : false
173
+ getters : false ,
174
+ numericSeparator : false ,
172
175
} ) ;
173
176
174
177
const kObjectType = 0 ;
@@ -244,6 +247,7 @@ function getUserOptions(ctx, isCrossContext) {
244
247
compact : ctx . compact ,
245
248
sorted : ctx . sorted ,
246
249
getters : ctx . getters ,
250
+ numericSeparator : ctx . numericSeparator ,
247
251
...ctx . userOptions
248
252
} ;
249
253
@@ -301,7 +305,8 @@ function inspect(value, opts) {
301
305
breakLength : inspectDefaultOptions . breakLength ,
302
306
compact : inspectDefaultOptions . compact ,
303
307
sorted : inspectDefaultOptions . sorted ,
304
- getters : inspectDefaultOptions . getters
308
+ getters : inspectDefaultOptions . getters ,
309
+ numericSeparator : inspectDefaultOptions . numericSeparator ,
305
310
} ;
306
311
if ( arguments . length > 1 ) {
307
312
// Legacy...
@@ -949,7 +954,7 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
949
954
formatter = formatArrayBuffer ;
950
955
} else if ( keys . length === 0 && protoProps === undefined ) {
951
956
return prefix +
952
- `{ byteLength: ${ formatNumber ( ctx . stylize , value . byteLength ) } }` ;
957
+ `{ byteLength: ${ formatNumber ( ctx . stylize , value . byteLength , false ) } }` ;
953
958
}
954
959
braces [ 0 ] = `${ prefix } {` ;
955
960
ArrayPrototypeUnshift ( keys , 'byteLength' ) ;
@@ -1434,13 +1439,61 @@ function handleMaxCallStackSize(ctx, err, constructorName, indentationLvl) {
1434
1439
assert . fail ( err . stack ) ;
1435
1440
}
1436
1441
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' ) ;
1440
1489
}
1441
1490
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' ) ;
1444
1497
}
1445
1498
1446
1499
function formatPrimitive ( fn , value , ctx ) {
@@ -1464,9 +1517,9 @@ function formatPrimitive(fn, value, ctx) {
1464
1517
return fn ( strEscape ( value ) , 'string' ) + trailer ;
1465
1518
}
1466
1519
if ( typeof value === 'number' )
1467
- return formatNumber ( fn , value ) ;
1520
+ return formatNumber ( fn , value , ctx . numericSeparator ) ;
1468
1521
if ( typeof value === 'bigint' )
1469
- return formatBigInt ( fn , value ) ;
1522
+ return formatBigInt ( fn , value , ctx . numericSeparator ) ;
1470
1523
if ( typeof value === 'boolean' )
1471
1524
return fn ( `${ value } ` , 'boolean' ) ;
1472
1525
if ( typeof value === 'undefined' )
@@ -1583,8 +1636,9 @@ function formatTypedArray(value, length, ctx, ignored, recurseTimes) {
1583
1636
const elementFormatter = value . length > 0 && typeof value [ 0 ] === 'number' ?
1584
1637
formatNumber :
1585
1638
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
+ }
1588
1642
if ( remaining > 0 ) {
1589
1643
output [ maxLength ] = `... ${ remaining } more item${ remaining > 1 ? 's' : '' } ` ;
1590
1644
}
@@ -1928,8 +1982,8 @@ function tryStringify(arg) {
1928
1982
if ( ! CIRCULAR_ERROR_MESSAGE ) {
1929
1983
try {
1930
1984
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 ) ;
1933
1987
}
1934
1988
}
1935
1989
if ( err . name === 'TypeError' &&
@@ -1952,6 +2006,22 @@ function formatWithOptions(inspectOptions, ...args) {
1952
2006
return formatWithOptionsInternal ( inspectOptions , args ) ;
1953
2007
}
1954
2008
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
+
1955
2025
function formatWithOptionsInternal ( inspectOptions , args ) {
1956
2026
const first = args [ 0 ] ;
1957
2027
let a = 0 ;
@@ -1973,9 +2043,9 @@ function formatWithOptionsInternal(inspectOptions, args) {
1973
2043
case 115 : // 's'
1974
2044
const tempArg = args [ ++ a ] ;
1975
2045
if ( typeof tempArg === 'number' ) {
1976
- tempStr = formatNumber ( stylizeNoColor , tempArg ) ;
2046
+ tempStr = formatNumberNoColor ( tempArg , inspectOptions ) ;
1977
2047
} else if ( typeof tempArg === 'bigint' ) {
1978
- tempStr = ` ${ tempArg } n` ;
2048
+ tempStr = formatBigIntNoColor ( tempArg , inspectOptions ) ;
1979
2049
} else if ( typeof tempArg !== 'object' ||
1980
2050
tempArg === null ||
1981
2051
! hasBuiltInToString ( tempArg ) ) {
@@ -1995,11 +2065,11 @@ function formatWithOptionsInternal(inspectOptions, args) {
1995
2065
case 100 : // 'd'
1996
2066
const tempNum = args [ ++ a ] ;
1997
2067
if ( typeof tempNum === 'bigint' ) {
1998
- tempStr = ` ${ tempNum } n` ;
2068
+ tempStr = formatBigIntNoColor ( tempNum , inspectOptions ) ;
1999
2069
} else if ( typeof tempNum === 'symbol' ) {
2000
2070
tempStr = 'NaN' ;
2001
2071
} else {
2002
- tempStr = formatNumber ( stylizeNoColor , Number ( tempNum ) ) ;
2072
+ tempStr = formatNumberNoColor ( Number ( tempNum ) , inspectOptions ) ;
2003
2073
}
2004
2074
break ;
2005
2075
case 79 : // 'O'
@@ -2016,21 +2086,21 @@ function formatWithOptionsInternal(inspectOptions, args) {
2016
2086
case 105 : // 'i'
2017
2087
const tempInteger = args [ ++ a ] ;
2018
2088
if ( typeof tempInteger === 'bigint' ) {
2019
- tempStr = ` ${ tempInteger } n` ;
2089
+ tempStr = formatBigIntNoColor ( tempInteger , inspectOptions ) ;
2020
2090
} else if ( typeof tempInteger === 'symbol' ) {
2021
2091
tempStr = 'NaN' ;
2022
2092
} else {
2023
- tempStr = formatNumber ( stylizeNoColor ,
2024
- NumberParseInt ( tempInteger ) ) ;
2093
+ tempStr = formatNumberNoColor (
2094
+ NumberParseInt ( tempInteger ) , inspectOptions ) ;
2025
2095
}
2026
2096
break ;
2027
2097
case 102 : // 'f'
2028
2098
const tempFloat = args [ ++ a ] ;
2029
2099
if ( typeof tempFloat === 'symbol' ) {
2030
2100
tempStr = 'NaN' ;
2031
2101
} else {
2032
- tempStr = formatNumber ( stylizeNoColor ,
2033
- NumberParseFloat ( tempFloat ) ) ;
2102
+ tempStr = formatNumberNoColor (
2103
+ NumberParseFloat ( tempFloat ) , inspectOptions ) ;
2034
2104
}
2035
2105
break ;
2036
2106
case 99 : // 'c'
0 commit comments