]>
git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/no-loss-of-precision.js
2 * @fileoverview Rule to flag numbers that will lose significant figure precision at runtime
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
17 description
: "disallow literal numbers that lose precision",
18 category
: "Possible Errors",
20 url
: "https://eslint.org/docs/rules/no-loss-of-precision"
24 noLossOfPrecision
: "This number literal will lose precision at runtime."
31 * Returns whether the node is number literal
32 * @param {Node} node the node literal being evaluated
33 * @returns {boolean} true if the node is a number literal
35 function isNumber(node
) {
36 return typeof node
.value
=== "number";
41 * Checks whether the number is base ten
42 * @param {ASTNode} node the node being evaluated
43 * @returns {boolean} true if the node is in base ten
45 function isBaseTen(node
) {
46 const prefixes
= ["0x", "0X", "0b", "0B", "0o", "0O"];
48 return prefixes
.every(prefix
=> !node
.raw
.startsWith(prefix
)) &&
49 !/^0[0-7]+$/u.test(node
.raw
);
53 * Checks that the user-intended non-base ten number equals the actual number after is has been converted to the Number type
54 * @param {Node} node the node being evaluated
55 * @returns {boolean} true if they do not match
57 function notBaseTenLosesPrecision(node
) {
58 const rawString
= node
.raw
.toUpperCase();
61 if (rawString
.startsWith("0B")) {
63 } else if (rawString
.startsWith("0X")) {
69 return !rawString
.endsWith(node
.value
.toString(base
).toUpperCase());
73 * Adds a decimal point to the numeric string at index 1
74 * @param {string} stringNumber the numeric string without any decimal point
75 * @returns {string} the numeric string with a decimal point in the proper place
77 function addDecimalPointToNumber(stringNumber
) {
78 return `${stringNumber.slice(0, 1)}.${stringNumber.slice(1)}`;
82 * Returns the number stripped of leading zeros
83 * @param {string} numberAsString the string representation of the number
84 * @returns {string} the stripped string
86 function removeLeadingZeros(numberAsString
) {
87 return numberAsString
.replace(/^0*/u, "");
91 * Returns the number stripped of trailing zeros
92 * @param {string} numberAsString the string representation of the number
93 * @returns {string} the stripped string
95 function removeTrailingZeros(numberAsString
) {
96 return numberAsString
.replace(/0*$/u, "");
100 * Converts an integer to to an object containing the the integer's coefficient and order of magnitude
101 * @param {string} stringInteger the string representation of the integer being converted
102 * @returns {Object} the object containing the the integer's coefficient and order of magnitude
104 function normalizeInteger(stringInteger
) {
105 const significantDigits
= removeTrailingZeros(removeLeadingZeros(stringInteger
));
108 magnitude
: stringInteger
.startsWith("0") ? stringInteger
.length
- 2 : stringInteger
.length
- 1,
109 coefficient
: addDecimalPointToNumber(significantDigits
)
115 * Converts a float to to an object containing the the floats's coefficient and order of magnitude
116 * @param {string} stringFloat the string representation of the float being converted
117 * @returns {Object} the object containing the the integer's coefficient and order of magnitude
119 function normalizeFloat(stringFloat
) {
120 const trimmedFloat
= removeLeadingZeros(stringFloat
);
122 if (trimmedFloat
.startsWith(".")) {
123 const decimalDigits
= trimmedFloat
.split(".").pop();
124 const significantDigits
= removeLeadingZeros(decimalDigits
);
127 magnitude
: significantDigits
.length
- decimalDigits
.length
- 1,
128 coefficient
: addDecimalPointToNumber(significantDigits
)
133 magnitude
: trimmedFloat
.indexOf(".") - 1,
134 coefficient
: addDecimalPointToNumber(trimmedFloat
.replace(".", ""))
141 * Converts a base ten number to proper scientific notation
142 * @param {string} stringNumber the string representation of the base ten number to be converted
143 * @returns {string} the number converted to scientific notation
145 function convertNumberToScientificNotation(stringNumber
) {
146 const splitNumber
= stringNumber
.replace("E", "e").split("e");
147 const originalCoefficient
= splitNumber
[0];
148 const normalizedNumber
= stringNumber
.includes(".") ? normalizeFloat(originalCoefficient
)
149 : normalizeInteger(originalCoefficient
);
150 const normalizedCoefficient
= normalizedNumber
.coefficient
;
151 const magnitude
= splitNumber
.length
> 1 ? (parseInt(splitNumber
[1], 10) + normalizedNumber
.magnitude
)
152 : normalizedNumber
.magnitude
;
154 return `${normalizedCoefficient}e${magnitude}`;
159 * Checks that the user-intended base ten number equals the actual number after is has been converted to the Number type
160 * @param {Node} node the node being evaluated
161 * @returns {boolean} true if they do not match
163 function baseTenLosesPrecision(node
) {
164 const normalizedRawNumber
= convertNumberToScientificNotation(node
.raw
);
165 const requestedPrecision
= normalizedRawNumber
.split("e")[0].replace(".", "").length
;
167 if (requestedPrecision
> 100) {
170 const storedNumber
= node
.value
.toPrecision(requestedPrecision
);
171 const normalizedStoredNumber
= convertNumberToScientificNotation(storedNumber
);
173 return normalizedRawNumber
!== normalizedStoredNumber
;
178 * Checks that the user-intended number equals the actual number after is has been converted to the Number type
179 * @param {Node} node the node being evaluated
180 * @returns {boolean} true if they do not match
182 function losesPrecision(node
) {
183 return isBaseTen(node
) ? baseTenLosesPrecision(node
) : notBaseTenLosesPrecision(node
);
189 if (node
.value
&& isNumber(node
) && losesPrecision(node
)) {
191 messageId
: "noLossOfPrecision",