]>
git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/radix.js
2 * @fileoverview Rule to flag use of parseInt without a radix argument
3 * @author James Allardice
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
12 const astUtils
= require("./utils/ast-utils");
14 //------------------------------------------------------------------------------
16 //------------------------------------------------------------------------------
18 const MODE_ALWAYS
= "always",
19 MODE_AS_NEEDED
= "as-needed";
21 const validRadixValues
= new Set(Array
.from({ length
: 37 - 2 }, (_
, index
) => index
+ 2));
24 * Checks whether a given variable is shadowed or not.
25 * @param {eslint-scope.Variable} variable A variable to check.
26 * @returns {boolean} `true` if the variable is shadowed.
28 function isShadowed(variable
) {
29 return variable
.defs
.length
>= 1;
33 * Checks whether a given node is a MemberExpression of `parseInt` method or not.
34 * @param {ASTNode} node A node to check.
35 * @returns {boolean} `true` if the node is a MemberExpression of `parseInt`
38 function isParseIntMethod(node
) {
40 node
.type
=== "MemberExpression" &&
42 node
.property
.type
=== "Identifier" &&
43 node
.property
.name
=== "parseInt"
48 * Checks whether a given node is a valid value of radix or not.
50 * The following values are invalid.
52 * - A literal except integers between 2 and 36.
54 * @param {ASTNode} radix A node of radix to check.
55 * @returns {boolean} `true` if the node is valid.
57 function isValidRadix(radix
) {
59 (radix
.type
=== "Literal" && !validRadixValues
.has(radix
.value
)) ||
60 (radix
.type
=== "Identifier" && radix
.name
=== "undefined")
65 * Checks whether a given node is a default value of radix or not.
66 * @param {ASTNode} radix A node of radix to check.
67 * @returns {boolean} `true` if the node is the literal node of `10`.
69 function isDefaultRadix(radix
) {
70 return radix
.type
=== "Literal" && radix
.value
=== 10;
73 //------------------------------------------------------------------------------
75 //------------------------------------------------------------------------------
82 description
: "enforce the consistent use of the radix argument when using `parseInt()`",
83 category
: "Best Practices",
85 url
: "https://eslint.org/docs/rules/radix",
91 enum: ["always", "as-needed"]
96 missingParameters
: "Missing parameters.",
97 redundantRadix
: "Redundant radix parameter.",
98 missingRadix
: "Missing radix parameter.",
99 invalidRadix
: "Invalid radix parameter, must be an integer between 2 and 36.",
100 addRadixParameter10
: "Add radix parameter `10` for parsing decimal numbers."
105 const mode
= context
.options
[0] || MODE_ALWAYS
;
108 * Checks the arguments of a given CallExpression node and reports it if it
110 * @param {ASTNode} node A CallExpression node to check.
113 function checkArguments(node
) {
114 const args
= node
.arguments
;
116 switch (args
.length
) {
120 messageId
: "missingParameters"
125 if (mode
=== MODE_ALWAYS
) {
128 messageId
: "missingRadix",
131 messageId
: "addRadixParameter10",
133 const sourceCode
= context
.getSourceCode();
134 const tokens
= sourceCode
.getTokens(node
);
135 const lastToken
= tokens
[tokens
.length
- 1]; // Parenthesis.
136 const secondToLastToken
= tokens
[tokens
.length
- 2]; // May or may not be a comma.
137 const hasTrailingComma
= secondToLastToken
.type
=== "Punctuator" && secondToLastToken
.value
=== ",";
139 return fixer
.insertTextBefore(lastToken
, hasTrailingComma
? " 10," : ", 10");
148 if (mode
=== MODE_AS_NEEDED
&& isDefaultRadix(args
[1])) {
151 messageId
: "redundantRadix"
153 } else if (!isValidRadix(args
[1])) {
156 messageId
: "invalidRadix"
165 const scope
= context
.getScope();
168 // Check `parseInt()`
169 variable
= astUtils
.getVariableByName(scope
, "parseInt");
170 if (variable
&& !isShadowed(variable
)) {
171 variable
.references
.forEach(reference
=> {
172 const node
= reference
.identifier
;
174 if (astUtils
.isCallee(node
)) {
175 checkArguments(node
.parent
);
180 // Check `Number.parseInt()`
181 variable
= astUtils
.getVariableByName(scope
, "Number");
182 if (variable
&& !isShadowed(variable
)) {
183 variable
.references
.forEach(reference
=> {
184 const node
= reference
.identifier
.parent
;
185 const maybeCallee
= node
.parent
.type
=== "ChainExpression"
189 if (isParseIntMethod(node
) && astUtils
.isCallee(maybeCallee
)) {
190 checkArguments(maybeCallee
.parent
);