Skip to content

Commit

Permalink
Fix: prefer-numeric-literals invalid autofix with adjacent tokens (#1…
Browse files Browse the repository at this point in the history
  • Loading branch information
mdjermanovic authored and platinumazure committed Oct 20, 2019
1 parent 6e7c18d commit a102eaa
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 4 deletions.
36 changes: 32 additions & 4 deletions lib/rules/prefer-numeric-literals.js
Expand Up @@ -5,6 +5,12 @@

"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const astUtils = require("./utils/ast-utils");

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
Expand Down Expand Up @@ -94,21 +100,43 @@ module.exports = {
functionName: sourceCode.getText(node.callee)
},
fix(fixer) {
const newPrefix = prefixMap[node.arguments[1].value];

if (sourceCode.getCommentsInside(node).length) {
return null;
}

if (+(newPrefix + node.arguments[0].value) !== parseInt(node.arguments[0].value, node.arguments[1].value)) {
const replacement = `${prefixMap[node.arguments[1].value]}${node.arguments[0].value}`;

if (+replacement !== parseInt(node.arguments[0].value, node.arguments[1].value)) {

/*
* 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.
*/
return null;
}
return fixer.replaceText(node, prefixMap[node.arguments[1].value] + node.arguments[0].value);

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}`);
}
});
}
Expand Down
98 changes: 98 additions & 0 deletions tests/lib/rules/prefer-numeric-literals.js
Expand Up @@ -92,6 +92,104 @@ ruleTester.run("prefer-numeric-literals", rule, {
errors: [{ message: "Use hexadecimal literals instead of Number.parseInt()." }]
},

// Adjacent tokens tests
{
code: "parseInt('11', 2)",
output: "0b11",
errors: [{ message: "Use binary literals instead of parseInt()." }]
},
{
code: "Number.parseInt('67', 8)",
output: "0o67",
errors: [{ message: "Use octal literals instead of Number.parseInt()." }]
},
{
code: "5+parseInt('A', 16)",
output: "5+0xA",
errors: [{ message: "Use hexadecimal literals instead of parseInt()." }]
},
{
code: "function *f(){ yield(Number).parseInt('11', 2) }",
output: "function *f(){ yield 0b11 }",
parserOptions: { ecmaVersion: 6 },
errors: [{ message: "Use binary literals instead of (Number).parseInt()." }]
},
{
code: "function *f(){ yield(Number.parseInt)('67', 8) }",
output: "function *f(){ yield 0o67 }",
parserOptions: { ecmaVersion: 6 },
errors: [{ message: "Use octal literals instead of Number.parseInt()." }]
},
{
code: "function *f(){ yield(parseInt)('A', 16) }",
output: "function *f(){ yield 0xA }",
parserOptions: { ecmaVersion: 6 },
errors: [{ message: "Use hexadecimal literals instead of parseInt()." }]
},
{
code: "function *f(){ yield Number.parseInt('11', 2) }",
output: "function *f(){ yield 0b11 }",
parserOptions: { ecmaVersion: 6 },
errors: [{ message: "Use binary literals instead of Number.parseInt()." }]
},
{
code: "function *f(){ yield/**/Number.parseInt('67', 8) }",
output: "function *f(){ yield/**/0o67 }",
parserOptions: { ecmaVersion: 6 },
errors: [{ message: "Use octal literals instead of Number.parseInt()." }]
},
{
code: "function *f(){ yield(parseInt('A', 16)) }",
output: "function *f(){ yield(0xA) }",
parserOptions: { ecmaVersion: 6 },
errors: [{ message: "Use hexadecimal literals instead of parseInt()." }]
},
{
code: "parseInt('11', 2)+5",
output: "0b11+5",
errors: [{ message: "Use binary literals instead of parseInt()." }]
},
{
code: "Number.parseInt('17', 8)+5",
output: "0o17+5",
errors: [{ message: "Use octal literals instead of Number.parseInt()." }]
},
{
code: "parseInt('A', 16)+5",
output: "0xA+5",
errors: [{ message: "Use hexadecimal literals instead of parseInt()." }]
},
{
code: "parseInt('11', 2)in foo",
output: "0b11 in foo",
errors: [{ message: "Use binary literals instead of parseInt()." }]
},
{
code: "Number.parseInt('17', 8)in foo",
output: "0o17 in foo",
errors: [{ message: "Use octal literals instead of Number.parseInt()." }]
},
{
code: "parseInt('A', 16)in foo",
output: "0xA in foo",
errors: [{ message: "Use hexadecimal literals instead of parseInt()." }]
},
{
code: "parseInt('11', 2) in foo",
output: "0b11 in foo",
errors: [{ message: "Use binary literals instead of parseInt()." }]
},
{
code: "Number.parseInt('17', 8)/**/in foo",
output: "0o17/**/in foo",
errors: [{ message: "Use octal literals instead of Number.parseInt()." }]
},
{
code: "(parseInt('A', 16))in foo",
output: "(0xA)in foo",
errors: [{ message: "Use hexadecimal literals instead of parseInt()." }]
},

// Should not autofix if it would remove comments
{
code: "/* comment */Number.parseInt('11', 2);",
Expand Down

0 comments on commit a102eaa

Please sign in to comment.