UNPKG

3.79 kBJavaScriptView Raw
1/**
2 * @fileoverview Rule to disallow `parseInt()` in favor of binary, octal, and hexadecimal literals
3 * @author Annie Zhang, Henry Zhu
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Helpers
10//------------------------------------------------------------------------------
11
12/**
13 * Checks to see if a CallExpression's callee node is `parseInt` or
14 * `Number.parseInt`.
15 * @param {ASTNode} calleeNode The callee node to evaluate.
16 * @returns {boolean} True if the callee is `parseInt` or `Number.parseInt`,
17 * false otherwise.
18 */
19function isParseInt(calleeNode) {
20 switch (calleeNode.type) {
21 case "Identifier":
22 return calleeNode.name === "parseInt";
23 case "MemberExpression":
24 return calleeNode.object.type === "Identifier" &&
25 calleeNode.object.name === "Number" &&
26 calleeNode.property.type === "Identifier" &&
27 calleeNode.property.name === "parseInt";
28
29 // no default
30 }
31
32 return false;
33}
34
35//------------------------------------------------------------------------------
36// Rule Definition
37//------------------------------------------------------------------------------
38
39module.exports = {
40 meta: {
41 docs: {
42 description: "disallow `parseInt()` and `Number.parseInt()` in favor of binary, octal, and hexadecimal literals",
43 category: "ECMAScript 6",
44 recommended: false,
45 url: "https://eslint.org/docs/rules/prefer-numeric-literals"
46 },
47
48 schema: [],
49
50 fixable: "code"
51 },
52
53 create(context) {
54 const sourceCode = context.getSourceCode();
55
56 const radixMap = {
57 2: "binary",
58 8: "octal",
59 16: "hexadecimal"
60 };
61
62 const prefixMap = {
63 2: "0b",
64 8: "0o",
65 16: "0x"
66 };
67
68 //----------------------------------------------------------------------
69 // Public
70 //----------------------------------------------------------------------
71
72 return {
73
74 CallExpression(node) {
75
76 // doesn't check parseInt() if it doesn't have a radix argument
77 if (node.arguments.length !== 2) {
78 return;
79 }
80
81 // only error if the radix is 2, 8, or 16
82 const radixName = radixMap[node.arguments[1].value];
83
84 if (isParseInt(node.callee) &&
85 radixName &&
86 node.arguments[0].type === "Literal"
87 ) {
88 context.report({
89 node,
90 message: "Use {{radixName}} literals instead of {{functionName}}().",
91 data: {
92 radixName,
93 functionName: sourceCode.getText(node.callee)
94 },
95 fix(fixer) {
96 const newPrefix = prefixMap[node.arguments[1].value];
97
98 if (+(newPrefix + node.arguments[0].value) !== parseInt(node.arguments[0].value, node.arguments[1].value)) {
99
100 /*
101 * If the newly-produced literal would be invalid, (e.g. 0b1234),
102 * or it would yield an incorrect parseInt result for some other reason, don't make a fix.
103 */
104 return null;
105 }
106 return fixer.replaceText(node, prefixMap[node.arguments[1].value] + node.arguments[0].value);
107 }
108 });
109 }
110 }
111 };
112 }
113};