github-pages-deploy-action/node_modules/eslint/lib/rules/prefer-numeric-literals.js

149 lines
5.7 KiB
JavaScript
Raw Permalink Normal View History

2020-03-07 11:45:40 +08:00
/**
* @fileoverview Rule to disallow `parseInt()` in favor of binary, octal, and hexadecimal literals
* @author Annie Zhang, Henry Zhu
*/
"use strict";
2020-03-31 20:40:00 +08:00
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
2020-03-07 11:45:40 +08:00
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
2020-03-31 20:40:00 +08:00
const radixMap = new Map([
[2, { system: "binary", literalPrefix: "0b" }],
[8, { system: "octal", literalPrefix: "0o" }],
[16, { system: "hexadecimal", literalPrefix: "0x" }]
]);
2020-03-07 11:45:40 +08:00
/**
* Checks to see if a CallExpression's callee node is `parseInt` or
* `Number.parseInt`.
* @param {ASTNode} calleeNode The callee node to evaluate.
* @returns {boolean} True if the callee is `parseInt` or `Number.parseInt`,
* false otherwise.
*/
function isParseInt(calleeNode) {
2020-09-13 06:19:45 +08:00
return (
astUtils.isSpecificId(calleeNode, "parseInt") ||
astUtils.isSpecificMemberAccess(calleeNode, "Number", "parseInt")
);
2020-03-07 11:45:40 +08:00
}
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "disallow `parseInt()` and `Number.parseInt()` in favor of binary, octal, and hexadecimal literals",
category: "ECMAScript 6",
recommended: false,
url: "https://eslint.org/docs/rules/prefer-numeric-literals"
},
schema: [],
2020-03-31 20:40:00 +08:00
messages: {
useLiteral: "Use {{system}} literals instead of {{functionName}}()."
},
2020-03-07 11:45:40 +08:00
fixable: "code"
},
create(context) {
const sourceCode = context.getSourceCode();
//----------------------------------------------------------------------
// Public
//----------------------------------------------------------------------
return {
2020-03-31 20:40:00 +08:00
"CallExpression[arguments.length=2]"(node) {
const [strNode, radixNode] = node.arguments,
2020-05-15 05:33:08 +08:00
str = astUtils.getStaticStringValue(strNode),
2020-03-31 20:40:00 +08:00
radix = radixNode.value;
if (
2020-05-15 05:33:08 +08:00
str !== null &&
astUtils.isStringLiteral(strNode) &&
2020-03-31 20:40:00 +08:00
radixNode.type === "Literal" &&
typeof radix === "number" &&
radixMap.has(radix) &&
isParseInt(node.callee)
) {
2020-03-07 11:45:40 +08:00
2020-03-31 20:40:00 +08:00
const { system, literalPrefix } = radixMap.get(radix);
2020-03-07 11:45:40 +08:00
context.report({
node,
2020-03-31 20:40:00 +08:00
messageId: "useLiteral",
2020-03-07 11:45:40 +08:00
data: {
2020-03-31 20:40:00 +08:00
system,
2020-03-07 11:45:40 +08:00
functionName: sourceCode.getText(node.callee)
},
fix(fixer) {
2020-03-31 20:40:00 +08:00
if (sourceCode.getCommentsInside(node).length) {
return null;
}
2020-03-07 11:45:40 +08:00
2020-03-31 20:40:00 +08:00
const replacement = `${literalPrefix}${str}`;
if (+replacement !== parseInt(str, radix)) {
2020-03-07 11:45:40 +08:00
/*
* If the newly-produced literal would be invalid, (e.g. 0b1234),
* or it would yield an incorrect parseInt result for some other reason, don't make a fix.
2020-09-13 06:19:45 +08:00
*
* If `str` had numeric separators, `+replacement` will evaluate to `NaN` because unary `+`
* per the specification doesn't support numeric separators. Thus, the above condition will be `true`
* (`NaN !== anything` is always `true`) regardless of the `parseInt(str, radix)` value.
* Consequently, no autofixes will be made. This is correct behavior because `parseInt` also
* doesn't support numeric separators, but it does parse part of the string before the first `_`,
* so the autofix would be invalid:
*
* parseInt("1_1", 2) // === 1
* 0b1_1 // === 3
2020-03-07 11:45:40 +08:00
*/
return null;
}
2020-03-31 20:40:00 +08:00
const tokenBefore = sourceCode.getTokenBefore(node),
tokenAfter = sourceCode.getTokenAfter(node);
let prefix = "",
suffix = "";
if (
tokenBefore &&
tokenBefore.range[1] === node.range[0] &&
!astUtils.canTokensBeAdjacent(tokenBefore, replacement)
) {
prefix = " ";
}
if (
tokenAfter &&
node.range[1] === tokenAfter.range[0] &&
!astUtils.canTokensBeAdjacent(replacement, tokenAfter)
) {
suffix = " ";
}
return fixer.replaceText(node, `${prefix}${replacement}${suffix}`);
2020-03-07 11:45:40 +08:00
}
});
}
}
};
}
};