Skip to content

Commit 2d2d537

Browse files
committed
[New] add numericSeparator boolean option
node v17.3.0 adds this
1 parent a314ab8 commit 2d2d537

File tree

5 files changed

+95
-4
lines changed

5 files changed

+95
-4
lines changed

index.js

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ var booleanValueOf = Boolean.prototype.valueOf;
1616
var objectToString = Object.prototype.toString;
1717
var functionToString = Function.prototype.toString;
1818
var match = String.prototype.match;
19+
var $slice = String.prototype.slice;
20+
var $replace = String.prototype.replace;
1921
var test = RegExp.prototype.test;
22+
var $floor = Math.floor;
2023
var bigIntValueOf = typeof BigInt === 'function' ? BigInt.prototype.valueOf : null;
2124
var gOPS = Object.getOwnPropertySymbols;
2225
var symToString = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol' ? Symbol.prototype.toString : null;
@@ -35,6 +38,28 @@ var gPO = (typeof Reflect === 'function' ? Reflect.getPrototypeOf : Object.getPr
3538
: null
3639
);
3740

41+
function addNumericSeparator(num, str) {
42+
if (
43+
num === Infinity
44+
|| num === -Infinity
45+
|| num !== num
46+
|| (num && num > -1000 && num < 1000)
47+
|| test.call(/e/, str)
48+
) {
49+
return str;
50+
}
51+
var sepRegex = /[0-9](?=(?:[0-9]{3})+(?![0-9]))/g;
52+
if (typeof num === 'number') {
53+
var int = num < 0 ? -$floor(-num) : $floor(num); // trunc(num)
54+
if (int !== num) {
55+
var intStr = String(int);
56+
var dec = $slice.call(str, intStr.length + 1);
57+
return $replace.call(intStr, sepRegex, '$&_') + '.' + $replace.call($replace.call(dec, /([0-9]{3})/g, '$&_'), /_$/, '');
58+
}
59+
}
60+
return $replace.call(str, sepRegex, '$&_');
61+
}
62+
3863
var inspectCustom = require('./util.inspect').custom;
3964
var inspectSymbol = inspectCustom && isSymbol(inspectCustom) ? inspectCustom : null;
4065

@@ -63,8 +88,12 @@ module.exports = function inspect_(obj, options, depth, seen) {
6388
&& opts.indent !== '\t'
6489
&& !(parseInt(opts.indent, 10) === opts.indent && opts.indent > 0)
6590
) {
66-
throw new TypeError('options "indent" must be "\\t", an integer > 0, or `null`');
91+
throw new TypeError('option "indent" must be "\\t", an integer > 0, or `null`');
92+
}
93+
if (has(opts, 'numericSeparator') && typeof opts.numericSeparator !== 'boolean') {
94+
throw new TypeError('option "numericSeparator", if provided, must be `true` or `false`');
6795
}
96+
var numericSeparator = opts.numericSeparator;
6897

6998
if (typeof obj === 'undefined') {
7099
return 'undefined';
@@ -83,10 +112,12 @@ module.exports = function inspect_(obj, options, depth, seen) {
83112
if (obj === 0) {
84113
return Infinity / obj > 0 ? '0' : '-0';
85114
}
86-
return String(obj);
115+
var str = String(obj);
116+
return numericSeparator ? addNumericSeparator(obj, str) : str;
87117
}
88118
if (typeof obj === 'bigint') {
89-
return String(obj) + 'n';
119+
var bigIntStr = String(obj) + 'n';
120+
return numericSeparator ? addNumericSeparator(obj, bigIntStr) : bigIntStr;
90121
}
91122

92123
var maxDepth = typeof opts.depth === 'undefined' ? 5 : opts.depth;

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"aud": "^1.1.5",
1010
"auto-changelog": "^2.3.0",
1111
"core-js": "^2.6.12",
12+
"es-value-fixtures": "^1.2.1",
1213
"eslint": "^8.4.0",
1314
"for-each": "^0.3.3",
1415
"functions-have-names": "^1.2.2",

readme.markdown

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ Additional options:
5555
- `maxStringLength`: must be `0`, a positive integer, `Infinity`, or `null`, if present. Default `Infinity`.
5656
- `customInspect`: When `true`, a custom inspect method function will be invoked (either undere the `util.inspect.custom` symbol, or the `inspect` property). When the string `'symbol'`, only the symbol method will be invoked. Default `true`.
5757
- `indent`: must be "\t", `null`, or a positive integer. Default `null`.
58+
- `numericSeparator`: must be a boolean, if present. Default `false`. If `true`, all numbers will be printed with numeric separators (eg, `1234.5678` will be printed as `'1_234.567_8'`)
5859

5960
# install
6061

test/bigint.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,17 @@ test('bigint', { skip: typeof BigInt === 'undefined' }, function (t) {
4242
);
4343
});
4444

45+
t.test('numericSeparator', function (st) {
46+
st.equal(inspect(BigInt(0), { numericSeparator: false }), '0n', '0n, numericSeparator false');
47+
st.equal(inspect(BigInt(0), { numericSeparator: true }), '0n', '0n, numericSeparator true');
48+
49+
st.equal(inspect(BigInt(1234), { numericSeparator: false }), '1234n', '1234n, numericSeparator false');
50+
st.equal(inspect(BigInt(1234), { numericSeparator: true }), '1_234n', '1234n, numericSeparator true');
51+
st.equal(inspect(BigInt(-1234), { numericSeparator: false }), '-1234n', '1234n, numericSeparator false');
52+
st.equal(inspect(BigInt(-1234), { numericSeparator: true }), '-1_234n', '1234n, numericSeparator true');
53+
54+
st.end();
55+
});
56+
4557
t.end();
4658
});

test/number.js

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
var inspect = require('../');
21
var test = require('tape');
2+
var v = require('es-value-fixtures');
3+
var forEach = require('for-each');
4+
5+
var inspect = require('../');
36

47
test('negative zero', function (t) {
58
t.equal(inspect(0), '0', 'inspect(0) === "0"');
@@ -10,3 +13,46 @@ test('negative zero', function (t) {
1013

1114
t.end();
1215
});
16+
17+
test('numericSeparator', function (t) {
18+
forEach(v.nonBooleans, function (nonBoolean) {
19+
t['throws'](
20+
function () { inspect(true, { numericSeparator: nonBoolean }); },
21+
TypeError,
22+
inspect(nonBoolean) + ' is not a boolean'
23+
);
24+
});
25+
26+
t.test('3 digit numbers', function (st) {
27+
var failed = false;
28+
for (var i = -999; i < 1000; i += 1) {
29+
var actual = inspect(i);
30+
var actualSepNo = inspect(i, { numericSeparator: false });
31+
var actualSepYes = inspect(i, { numericSeparator: true });
32+
var expected = String(i);
33+
if (actual !== expected || actualSepNo !== expected || actualSepYes !== expected) {
34+
failed = true;
35+
t.equal(actual, expected);
36+
t.equal(actualSepNo, expected);
37+
t.equal(actualSepYes, expected);
38+
}
39+
}
40+
41+
st.notOk(failed, 'all 3 digit numbers passed');
42+
43+
st.end();
44+
});
45+
46+
t.equal(inspect(1e3), '1000', '1000');
47+
t.equal(inspect(1e3, { numericSeparator: false }), '1000', '1000, numericSeparator false');
48+
t.equal(inspect(1e3, { numericSeparator: true }), '1_000', '1000, numericSeparator true');
49+
t.equal(inspect(-1e3), '-1000', '-1000');
50+
t.equal(inspect(-1e3, { numericSeparator: false }), '-1000', '-1000, numericSeparator false');
51+
t.equal(inspect(-1e3, { numericSeparator: true }), '-1_000', '-1000, numericSeparator true');
52+
53+
t.equal(inspect(1234.5678, { numericSeparator: true }), '1_234.567_8', 'fractional numbers get separators');
54+
t.equal(inspect(1234.56789, { numericSeparator: true }), '1_234.567_89', 'fractional numbers get separators');
55+
t.equal(inspect(1234.567891, { numericSeparator: true }), '1_234.567_891', 'fractional numbers get separators');
56+
57+
t.end();
58+
});

0 commit comments

Comments
 (0)