Skip to content

Commit 2c3d291

Browse files
authored
Extract numeric (sindresorhus#1237)
1 parent 1c78d0c commit 2c3d291

File tree

4 files changed

+63
-35
lines changed

4 files changed

+63
-35
lines changed

rules/number-literal-case.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22
const getDocumentationUrl = require('./utils/get-documentation-url');
3+
const {isNumber, isBigInt} = require('./utils/numeric');
34

45
const MESSAGE_ID = 'number-literal-case';
56
const messages = {
@@ -18,12 +19,12 @@ const fix = raw => {
1819
const create = context => {
1920
return {
2021
Literal: node => {
21-
const {value, raw, bigint} = node;
22+
const {raw} = node;
2223

2324
let fixed = raw;
24-
if (typeof value === 'number') {
25+
if (isNumber(node)) {
2526
fixed = fix(raw);
26-
} else if (bigint) {
27+
} else if (isBigInt(node)) {
2728
fixed = fix(raw.slice(0, -1)) + 'n';
2829
}
2930

rules/numeric-separators-style.js

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22
const getDocumentationUrl = require('./utils/get-documentation-url');
3+
const numeric = require('./utils/numeric');
34

45
const MESSAGE_ID = 'numeric-separators-style';
56
const messages = {
@@ -34,16 +35,8 @@ function addSeparatorFromLeft(value, options) {
3435
}
3536

3637
function formatNumber(value, options) {
37-
const parts = value.split('.');
38-
const [integer, fractional] = parts;
39-
40-
let formatted = addSeparator(integer, options);
41-
if (parts.length === 2) {
42-
formatted += '.';
43-
formatted += addSeparatorFromLeft(fractional, options);
44-
}
45-
46-
return formatted;
38+
const {integer, dot, fractional} = numeric.parseFloat(value);
39+
return addSeparator(integer, options) + dot + addSeparatorFromLeft(fractional, options);
4740
}
4841

4942
function format(value, {prefix, data}, options) {
@@ -55,10 +48,10 @@ function format(value, {prefix, data}, options) {
5548

5649
const {
5750
number,
58-
mark = '',
59-
sign = '',
60-
power = ''
61-
} = value.match(/^(?<number>.*?)(?:(?<mark>e)(?<sign>[+-])?(?<power>\d+))?$/i).groups;
51+
mark,
52+
sign,
53+
power
54+
} = numeric.parseNumber(value);
6255

6356
return formatNumber(number, formatOption) + mark + sign + addSeparator(power, options['']);
6457
}
@@ -106,23 +99,20 @@ const create = context => {
10699

107100
return {
108101
Literal: node => {
109-
const {value, bigint, raw} = node;
102+
if (!numeric.isNumberic(node) || numeric.isLegacyOctal(node)) {
103+
return;
104+
}
105+
106+
const {raw} = node;
110107
let number = raw;
111108
let suffix = '';
112-
if (typeof value === 'number') {
113-
// Legacy octal
114-
if (/^0\d+$/.test(raw)) {
115-
return;
116-
}
117-
} else if (bigint) {
109+
if (numeric.isBigInt(node)) {
118110
number = raw.slice(0, -1);
119111
suffix = 'n';
120-
} else {
121-
return;
122112
}
123113

124114
const strippedNumber = number.replace(/_/g, '');
125-
const {prefix = '', data} = strippedNumber.match(/^(?<prefix>0[box])?(?<data>.*)$/i).groups;
115+
const {prefix, data} = numeric.getPrefix(strippedNumber);
126116

127117
const {onlyIfContainsSeparator} = options[prefix.toLowerCase()];
128118
if (onlyIfContainsSeparator && !raw.includes('_')) {

rules/utils/numeric.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
'use strict';
2+
3+
// Determine whether this node is a decimal integer literal.
4+
// Copied from https://github.com/eslint/eslint/blob/cc4871369645c3409dc56ded7a555af8a9f63d51/lib/rules/utils/ast-utils.js#L1237
5+
const DECIMAL_INTEGER_PATTERN = /^(?:0|0[0-7]*[89]\d*|[1-9](?:_?\d)*)$/u;
6+
const isDecimalInteger = node => isNumber(node) && DECIMAL_INTEGER_PATTERN.test(node.raw);
7+
8+
const isNumber = node => typeof node.value === 'number';
9+
const isBigInt = node => Boolean(node.bigint);
10+
const isNumberic = node => isNumber(node) || isBigInt(node);
11+
const isLegacyOctal = node => isNumber(node) && /^0\d+$/.test(node.raw);
12+
13+
function getPrefix(text) {
14+
let prefix = '';
15+
let data = text;
16+
17+
if (/^0[box]/i.test(text)) {
18+
prefix = text.slice(0, 2);
19+
data = text.slice(2);
20+
}
21+
22+
return {prefix, data};
23+
}
24+
25+
function parseNumber(text) {
26+
const {
27+
number,
28+
mark = '',
29+
sign = '',
30+
power = ''
31+
} = text.match(/^(?<number>.*?)(?:(?<mark>e)(?<sign>[+-])?(?<power>\d+))?$/i).groups;
32+
33+
return {number, mark, sign, power};
34+
}
35+
36+
function parseFloat(text) {
37+
const parts = text.split('.');
38+
const [integer, fractional = ''] = parts;
39+
const dot = parts.length === 2 ? '.' : '';
40+
41+
return {integer, dot, fractional};
42+
}
43+
44+
module.exports = {isNumber, isBigInt, isNumberic, isLegacyOctal, getPrefix, parseNumber, parseFloat, isDecimalInteger};

rules/utils/should-add-parentheses-to-member-expression-object.js

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
'use strict';
22

33
const isNewExpressionWithParentheses = require('./is-new-expression-with-parentheses');
4-
5-
// Determine whether this node is a decimal integer literal.
6-
// Copied from https://github.com/eslint/eslint/blob/cc4871369645c3409dc56ded7a555af8a9f63d51/lib/rules/utils/ast-utils.js#L1237
7-
const DECIMAL_INTEGER_PATTERN = /^(?:0|0[0-7]*[89]\d*|[1-9](?:_?\d)*)$/u;
8-
const isDecimalInteger = node =>
9-
node.type === 'Literal' &&
10-
typeof node.value === 'number' &&
11-
DECIMAL_INTEGER_PATTERN.test(node.raw);
4+
const {isDecimalInteger} = require('./numeric');
125

136
/**
147
Check if parentheses should to be added to a `node` when it's used as an `object` of `MemberExpression`.

0 commit comments

Comments
 (0)