UNPKG

3.81 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 type: "suggestion",
42
43 docs: {
44 description: "disallow `parseInt()` and `Number.parseInt()` in favor of binary, octal, and hexadecimal literals",
45 category: "ECMAScript 6",
46 recommended: false,
47 url: "https://eslint.org/docs/rules/prefer-numeric-literals"
48 },
49
50 schema: [],
51 fixable: "code"
52 },
53
54 create(context) {
55 const sourceCode = context.getSourceCode();
56
57 const radixMap = {
58 2: "binary",
59 8: "octal",
60 16: "hexadecimal"
61 };
62
63 const prefixMap = {
64 2: "0b",
65 8: "0o",
66 16: "0x"
67 };
68
69 //----------------------------------------------------------------------
70 // Public
71 //----------------------------------------------------------------------
72
73 return {
74
75 CallExpression(node) {
76
77 // doesn't check parseInt() if it doesn't have a radix argument
78 if (node.arguments.length !== 2) {
79 return;
80 }
81
82 // only error if the radix is 2, 8, or 16
83 const radixName = radixMap[node.arguments[1].value];
84
85 if (isParseInt(node.callee) &&
86 radixName &&
87 node.arguments[0].type === "Literal"
88 ) {
89 context.report({
90 node,
91 message: "Use {{radixName}} literals instead of {{functionName}}().",
92 data: {
93 radixName,
94 functionName: sourceCode.getText(node.callee)
95 },
96 fix(fixer) {
97 const newPrefix = prefixMap[node.arguments[1].value];
98
99 if (+(newPrefix + node.arguments[0].value) !== parseInt(node.arguments[0].value, node.arguments[1].value)) {
100
101 /*
102 * If the newly-produced literal would be invalid, (e.g. 0b1234),
103 * or it would yield an incorrect parseInt result for some other reason, don't make a fix.
104 */
105 return null;
106 }
107 return fixer.replaceText(node, prefixMap[node.arguments[1].value] + node.arguments[0].value);
108 }
109 });
110 }
111 }
112 };
113 }
114};