Skip to content

Commit

Permalink
feat!: add two more cases to no-implicit-coercion (#17832)
Browse files Browse the repository at this point in the history
* add two more cases

* fix comment

* docs

* add allow

* change operator

* change docs

* use - -

* add tests

* don't fix numbers

* Check type directly

Co-authored-by: Francesco Trotta <[email protected]>

* add examples

* Refactor implicit coercion check in no-implicit-coercion rule

* fix test

* fix test

* Revert "Refactor implicit coercion check in no-implicit-coercion rule"

* make non-fixable

* Revert "fix test"

* add back test

---------

Co-authored-by: Francesco Trotta <[email protected]>
  • Loading branch information
gurgunday and fasttime authored Dec 27, 2023
1 parent e6a91bd commit 0b21e1f
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 2 deletions.
8 changes: 7 additions & 1 deletion docs/src/rules/no-implicit-coercion.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Such as:
var b = !!foo;
var b = ~foo.indexOf(".");
var n = +foo;
var n = -(-foo);
var n = foo - 0;
var n = 1 * foo;
var s = "" + foo;
foo += ``;
Expand All @@ -26,6 +28,8 @@ var b = Boolean(foo);
var b = foo.indexOf(".") !== -1;
var n = Number(foo);
var n = Number(foo);
var n = Number(foo);
var n = Number(foo);
var s = String(foo);
foo = String(foo);
```
Expand All @@ -42,7 +46,7 @@ This rule has three main options and one override option to allow some coercions
* `"number"` (`true` by default) - When this is `true`, this rule warns shorter type conversions for `number` type.
* `"string"` (`true` by default) - When this is `true`, this rule warns shorter type conversions for `string` type.
* `"disallowTemplateShorthand"` (`false` by default) - When this is `true`, this rule warns `string` type conversions using `${expression}` form.
* `"allow"` (`empty` by default) - Each entry in this array can be one of `~`, `!!`, `+` or `*` that are to be allowed.
* `"allow"` (`empty` by default) - Each entry in this array can be one of `~`, `!!`, `+`, `- -`, `-`, or `*` that are to be allowed.

Note that operator `+` in `allow` list would allow `+foo` (number coercion) as well as `"" + foo` (string coercion).

Expand Down Expand Up @@ -87,6 +91,8 @@ Examples of **incorrect** code for the default `{ "number": true }` option:
/*eslint no-implicit-coercion: "error"*/

var n = +foo;
var n = -(-foo);
var n = foo - 0;
var n = 1 * foo;
```

Expand Down
18 changes: 17 additions & 1 deletion lib/rules/no-implicit-coercion.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------

const INDEX_OF_PATTERN = /^(?:i|lastI)ndexOf$/u;
const ALLOWABLE_OPERATORS = ["~", "!!", "+", "*"];
const ALLOWABLE_OPERATORS = ["~", "!!", "+", "- -", "-", "*"];

/**
* Parses and normalizes an option object.
Expand Down Expand Up @@ -300,6 +300,14 @@ module.exports = {

report(node, recommendation, true);
}

// -(-foo)
operatorAllowed = options.allow.includes("- -");
if (!operatorAllowed && options.number && node.operator === "-" && node.argument.type === "UnaryExpression" && node.argument.operator === "-" && !isNumeric(node.argument.argument)) {
const recommendation = `Number(${sourceCode.getText(node.argument.argument)})`;

report(node, recommendation, false);
}
},

// Use `:exit` to prevent double reporting
Expand All @@ -317,6 +325,14 @@ module.exports = {
report(node, recommendation, true);
}

// foo - 0
operatorAllowed = options.allow.includes("-");
if (!operatorAllowed && options.number && node.operator === "-" && node.right.type === "Literal" && node.right.value === 0 && !isNumeric(node.left)) {
const recommendation = `Number(${sourceCode.getText(node.left)})`;

report(node, recommendation, true);
}

// "" + foo
operatorAllowed = options.allow.includes("+");
if (!operatorAllowed && options.string && isConcatWithEmptyString(node)) {
Expand Down
28 changes: 28 additions & 0 deletions tests/lib/rules/no-implicit-coercion.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,23 @@ ruleTester.run("no-implicit-coercion", rule, {
"-foo",
"+1234",
"-1234",
"- -1234",
"+Number(lol)",
"-parseFloat(lol)",
"2 * foo",
"1 * 1234",
"123 - 0",
"1 * Number(foo)",
"1 * parseInt(foo)",
"1 * parseFloat(foo)",
"Number(foo) * 1",
"Number(foo) - 0",
"parseInt(foo) * 1",
"parseFloat(foo) * 1",
"- -Number(foo)",
"1 * 1234 * 678 * Number(foo)",
"1 * 1234 * 678 * parseInt(foo)",
"(1 - 0) * parseInt(foo)",
"1234 * 1 * 678 * Number(foo)",
"1234 * 1 * Number(foo) * Number(bar)",
"1234 * 1 * Number(foo) * parseInt(bar)",
Expand All @@ -54,6 +59,7 @@ ruleTester.run("no-implicit-coercion", rule, {
"1234 * parseInt(foo) * 1 * Number(bar)",
"1234 * parseFloat(foo) * 1 * parseInt(bar)",
"1234 * parseFloat(foo) * 1 * Number(bar)",
"(- -1234) * (parseFloat(foo) - 0) * (Number(bar) - 0)",
"1234*foo*1",
"1234*1*foo",
"1234*bar*1*foo",
Expand All @@ -69,13 +75,17 @@ ruleTester.run("no-implicit-coercion", rule, {
{ code: "!!foo", options: [{ boolean: false }] },
{ code: "~foo.indexOf(1)", options: [{ boolean: false }] },
{ code: "+foo", options: [{ number: false }] },
{ code: "-(-foo)", options: [{ number: false }] },
{ code: "foo - 0", options: [{ number: false }] },
{ code: "1*foo", options: [{ number: false }] },
{ code: "\"\"+foo", options: [{ string: false }] },
{ code: "foo += \"\"", options: [{ string: false }] },
{ code: "var a = !!foo", options: [{ boolean: true, allow: ["!!"] }] },
{ code: "var a = ~foo.indexOf(1)", options: [{ boolean: true, allow: ["~"] }] },
{ code: "var a = ~foo", options: [{ boolean: true }] },
{ code: "var a = 1 * foo", options: [{ boolean: true, allow: ["*"] }] },
{ code: "- -foo", options: [{ number: true, allow: ["- -"] }] },
{ code: "foo - 0", options: [{ number: true, allow: ["-"] }] },
{ code: "var a = +foo", options: [{ boolean: true, allow: ["+"] }] },
{ code: "var a = \"\" + foo", options: [{ boolean: true, string: true, allow: ["+"] }] },

Expand Down Expand Up @@ -157,6 +167,15 @@ ruleTester.run("no-implicit-coercion", rule, {
type: "UnaryExpression"
}]
},
{
code: "-(-foo)",
output: null,
errors: [{
messageId: "useRecommendation",
data: { recommendation: "Number(foo)" },
type: "UnaryExpression"
}]
},
{
code: "+foo.bar",
output: "Number(foo.bar)",
Expand Down Expand Up @@ -193,6 +212,15 @@ ruleTester.run("no-implicit-coercion", rule, {
type: "BinaryExpression"
}]
},
{
code: "foo.bar-0",
output: "Number(foo.bar)",
errors: [{
messageId: "useRecommendation",
data: { recommendation: "Number(foo.bar)" },
type: "BinaryExpression"
}]
},
{
code: "\"\"+foo",
output: "String(foo)",
Expand Down

0 comments on commit 0b21e1f

Please sign in to comment.