Repository: eslint/eslint
Pull request #14291 (2021-04-02 17:51:16)

Update: Add automated suggestion to `radix` rule for parsing decimal numbers
<!--
    Thank you for contributing!

    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
-->

#### Prerequisites checklist

- [X] I have read the [contributing guidelines](https://github.com/eslint/eslint/blob/master/CONTRIBUTING.md).

#### What is the purpose of this pull request? (put an "X" next to an item)

[ ] Documentation update
[ ] Bug fix ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/bug-report.md))
[ ] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-proposal.md))
[X] Changes an existing rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-change-proposal.md))
[ ] Add autofixing to a rule
[ ] Add a CLI option
[ ] Add something to the core
[ ] Other, please explain:

**What rule do you want to change?**

[radix](https://eslint.org/docs/rules/radix)

**Does this change cause the rule to produce more or fewer warnings?**

No.

**How will the change be implemented? (New option, new default behavior, etc.)?**

New automated suggestion.

**What does the rule currently do for this code?**

Does not provide an automated suggestion nor autofix.

**What will the rule do after it's changed?**

Provide an automated suggestion to change 

```js
parseInt('123');
```

to

```js
parseInt('123', 10);
```

because parsing decimal numbers is the most common use case.

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (https://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

#### What changes did you make? (Give an overview)

Added a suggestion fixer function and tests.

#### Is there anything you'd like reviewers to focus on?

No.

eslint-github-bot[bot]: Hi @bmish!, thanks for the Pull Request

The first commit message isn't properly formatted. We ask that you update the message to match this format, as we use it to generate changelogs and automate releases.

- The length of the commit message must be less than or equal to 72

Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/)

eslint-github-bot[bot]: Hi @bmish!, thanks for the Pull Request

The first commit message isn't properly formatted. We ask that you update the message to match this format, as we use it to generate changelogs and automate releases.

- The length of the commit message must be less than or equal to 72

Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/)

eslint-github-bot[bot]: Hi @bmish!, thanks for the Pull Request

The first commit message isn't properly formatted. We ask that you update the message to match this format, as we use it to generate changelogs and automate releases.

- The length of the commit message must be less than or equal to 72

Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/)

mdjermanovic: Thanks for the PR! I support this enhancement :+1: 
fisker: Is trailing comma case tested? `parserInt(10,)`
eslint-github-bot[bot]: Hi @bmish!, thanks for the Pull Request

The pull request title isn't properly formatted. We ask that you update the message to match this format, as we use it to generate changelogs and automate releases.

- The length of the commit message must be less than or equal to 72

Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/)

eslint-github-bot[bot]: Hi @bmish!, thanks for the Pull Request

The pull request title isn't properly formatted. We ask that you update the message to match this format, as we use it to generate changelogs and automate releases.

- The length of the commit message must be less than or equal to 72

Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/)

bmish: > Is trailing comma case tested? `parserInt(10,)`

@fisker good idea, added that test case.
fisker: Edge case `parseInt(  (0, 10)  )` will fail.
nzakas: @fisker can you provide what it would be fixed to as well?
fisker: I think a better fix should check the penultimate token, if it's a comma token, insert `10,`, if not insert `10`, both insert before the last token `)`
bmish: I'll give that a try.

One other question, does it sound good for me to add suggestions for other common radix parameters? I think octal (8) and hexadecimal (16) are the other common ones.
fisker: Oh , I'm sorry, I fogot the second argument maybe already exists, maybe just check that  fist argument `isParenthesized` is simplier.
fisker: > add suggestions for other common radix

I don't think that will be useful, if it's missing most time its's just forgot `10`, but if it's not a valid `radix` I think most time it's just typo. My suggestion a little different https://github.com/eslint/eslint/issues/14356
eslint-github-bot[bot]: Hi @bmish!, thanks for the Pull Request

The pull request title isn't properly formatted. We ask that you update the message to match this format, as we use it to generate changelogs and automate releases.

- The length of the commit message must be less than or equal to 72

Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/)

bmish: @fisker I added handling for the sequence expression. Good catch on that.

For now, I'll keep only one suggestion.
fisker: LGTM
nzakas: @eslint/eslint-tsc can I get another pair of eyes on this?

Patch:
diff --git a/lib/rules/radix.js b/lib/rules/radix.js
index e32256623..d1b67e5e2 100644
--- a/lib/rules/radix.js
+++ b/lib/rules/radix.js
@@ -82,7 +82,8 @@ module.exports = {
             description: "enforce the consistent use of the radix argument when using `parseInt()`",
             category: "Best Practices",
             recommended: false,
-            url: "https://eslint.org/docs/rules/radix"
+            url: "https://eslint.org/docs/rules/radix",
+            suggestion: true
         },
 
         schema: [
@@ -95,7 +96,8 @@ module.exports = {
             missingParameters: "Missing parameters.",
             redundantRadix: "Redundant radix parameter.",
             missingRadix: "Missing radix parameter.",
-            invalidRadix: "Invalid radix parameter, must be an integer between 2 and 36."
+            invalidRadix: "Invalid radix parameter, must be an integer between 2 and 36.",
+            addRadixParameter10: "Add radix parameter `10` for parsing decimal numbers."
         }
     },
 
@@ -123,7 +125,21 @@ module.exports = {
                     if (mode === MODE_ALWAYS) {
                         context.report({
                             node,
-                            messageId: "missingRadix"
+                            messageId: "missingRadix",
+                            suggest: [
+                                {
+                                    messageId: "addRadixParameter10",
+                                    fix(fixer) {
+                                        const sourceCode = context.getSourceCode();
+                                        const tokens = sourceCode.getTokens(node);
+                                        const lastToken = tokens[tokens.length - 1]; // Parenthesis.
+                                        const secondToLastToken = tokens[tokens.length - 2]; // May or may not be a comma.
+                                        const hasTrailingComma = secondToLastToken.type === "Punctuator" && secondToLastToken.value === ",";
+
+                                        return fixer.insertTextBefore(lastToken, hasTrailingComma ? " 10," : ", 10");
+                                    }
+                                }
+                            ]
                         });
                     }
                     break;


Test patch:
diff --git a/tests/lib/rules/radix.js b/tests/lib/rules/radix.js
index 52801c3d1..ddb8363c1 100644
--- a/tests/lib/rules/radix.js
+++ b/tests/lib/rules/radix.js
@@ -76,7 +76,34 @@ ruleTester.run("radix", rule, {
             code: "parseInt(\"10\");",
             errors: [{
                 messageId: "missingRadix",
-                type: "CallExpression"
+                type: "CallExpression",
+                suggestions: [{ messageId: "addRadixParameter10", output: "parseInt(\"10\", 10);" }]
+            }]
+        },
+        {
+            code: "parseInt(\"10\",);", // Function parameter with trailing comma
+            parserOptions: { ecmaVersion: 2017 },
+            errors: [{
+                messageId: "missingRadix",
+                type: "CallExpression",
+                suggestions: [{ messageId: "addRadixParameter10", output: "parseInt(\"10\", 10,);" }]
+            }]
+        },
+        {
+            code: "parseInt((0, \"10\"));", // Sequence expression (no trailing comma).
+            errors: [{
+                messageId: "missingRadix",
+                type: "CallExpression",
+                suggestions: [{ messageId: "addRadixParameter10", output: "parseInt((0, \"10\"), 10);" }]
+            }]
+        },
+        {
+            code: "parseInt((0, \"10\"),);", // Sequence expression (with trailing comma).
+            parserOptions: { ecmaVersion: 2017 },
+            errors: [{
+                messageId: "missingRadix",
+                type: "CallExpression",
+                suggestions: [{ messageId: "addRadixParameter10", output: "parseInt((0, \"10\"), 10,);" }]
             }]
         },
         {
@@ -154,7 +181,8 @@ ruleTester.run("radix", rule, {
             code: "Number.parseInt(\"10\");",
             errors: [{
                 messageId: "missingRadix",
-                type: "CallExpression"
+                type: "CallExpression",
+                suggestions: [{ messageId: "addRadixParameter10", output: "Number.parseInt(\"10\", 10);" }]
             }]
         },
         {
@@ -191,22 +219,46 @@ ruleTester.run("radix", rule, {
         {
             code: "parseInt?.(\"10\");",
             parserOptions: { ecmaVersion: 2020 },
-            errors: [{ messageId: "missingRadix" }]
+            errors: [
+                {
+                    messageId: "missingRadix",
+                    type: "CallExpression",
+                    suggestions: [{ messageId: "addRadixParameter10", output: "parseInt?.(\"10\", 10);" }]
+                }
+            ]
         },
         {
             code: "Number.parseInt?.(\"10\");",
             parserOptions: { ecmaVersion: 2020 },
-            errors: [{ messageId: "missingRadix" }]
+            errors: [
+                {
+                    messageId: "missingRadix",
+                    type: "CallExpression",
+                    suggestions: [{ messageId: "addRadixParameter10", output: "Number.parseInt?.(\"10\", 10);" }]
+                }
+            ]
         },
         {
             code: "Number?.parseInt(\"10\");",
             parserOptions: { ecmaVersion: 2020 },
-            errors: [{ messageId: "missingRadix" }]
+            errors: [
+                {
+                    messageId: "missingRadix",
+                    type: "CallExpression",
+                    suggestions: [{ messageId: "addRadixParameter10", output: "Number?.parseInt(\"10\", 10);" }]
+                }
+            ]
         },
         {
             code: "(Number?.parseInt)(\"10\");",
             parserOptions: { ecmaVersion: 2020 },
-            errors: [{ messageId: "missingRadix" }]
+            errors: [
+                {
+                    messageId: "missingRadix",
+                    type: "CallExpression",
+                    suggestions: [{ messageId: "addRadixParameter10", output: "(Number?.parseInt)(\"10\", 10);" }]
+                }
+            ]
         }
     ]
 });