Skip to content

Commit

Permalink
Update: Add for-in and for-of checks for props in no-param-reassign (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mdjermanovic authored and mysticatea committed Jul 17, 2019
1 parent e4c450f commit 222d27c
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 1 deletion.
32 changes: 32 additions & 0 deletions docs/rules/no-param-reassign.md
Expand Up @@ -20,6 +20,14 @@ function foo(bar) {
function foo(bar) {
bar++;
}

function foo(bar) {
for (bar in baz) {}
}

function foo(bar) {
for (bar of baz) {}
}
```

Examples of **correct** code for this rule:
Expand Down Expand Up @@ -54,6 +62,14 @@ function foo(bar) {
function foo(bar) {
bar.aaa++;
}

function foo(bar) {
for (bar.aaa in baz) {}
}

function foo(bar) {
for (bar.aaa of baz) {}
}
```

Examples of **incorrect** code for the `{ "props": true }` option:
Expand All @@ -72,6 +88,14 @@ function foo(bar) {
function foo(bar) {
bar.aaa++;
}

function foo(bar) {
for (bar.aaa in baz) {}
}

function foo(bar) {
for (bar.aaa of baz) {}
}
```

Examples of **correct** code for the `{ "props": true }` option with `"ignorePropertyModificationsFor"` set:
Expand All @@ -90,6 +114,14 @@ function foo(bar) {
function foo(bar) {
bar.aaa++;
}

function foo(bar) {
for (bar.aaa in baz) {}
}

function foo(bar) {
for (bar.aaa of baz) {}
}
```


Expand Down
13 changes: 12 additions & 1 deletion lib/rules/no-param-reassign.js
Expand Up @@ -67,7 +67,8 @@ module.exports = {
let node = reference.identifier;
let parent = node.parent;

while (parent && !stopNodePattern.test(parent.type)) {
while (parent && (!stopNodePattern.test(parent.type) ||
parent.type === "ForInStatement" || parent.type === "ForOfStatement")) {
switch (parent.type) {

// e.g. foo.a = 0;
Expand All @@ -85,6 +86,16 @@ module.exports = {
}
break;

// e.g. for (foo.a in b) {}
case "ForInStatement":
case "ForOfStatement":
if (parent.left === node) {
return true;
}

// this is a stop node for parent.right and parent.body
return false;

// EXCLUDES: e.g. cache.get(foo.a).b = 0;
case "CallExpression":
if (parent.callee !== node) {
Expand Down
58 changes: 58 additions & 0 deletions tests/lib/rules/no-param-reassign.js
Expand Up @@ -21,7 +21,11 @@ ruleTester.run("no-param-reassign", rule, {

valid: [
"function foo(a) { var b = a; }",
"function foo(a) { for (b in a); }",
{ code: "function foo(a) { for (b of a); }", parserOptions: { ecmaVersion: 6 } },
"function foo(a) { a.prop = 'value'; }",
"function foo(a) { for (a.prop in obj); }",
{ code: "function foo(a) { for (a.prop of arr); }", parserOptions: { ecmaVersion: 6 } },
"function foo(a) { (function() { var a = 12; a++; })(); }",
"function foo() { someGlobal = 13; }",
{ code: "function foo() { someGlobal = 13; }", globals: { someGlobal: false } },
Expand All @@ -37,6 +41,8 @@ ruleTester.run("no-param-reassign", rule, {
{ code: "function foo(a) { a.b = 0; }", options: [{ props: true, ignorePropertyModificationsFor: ["a"] }] },
{ code: "function foo(a) { ++a.b; }", options: [{ props: true, ignorePropertyModificationsFor: ["a"] }] },
{ code: "function foo(a) { delete a.b; }", options: [{ props: true, ignorePropertyModificationsFor: ["a"] }] },
{ code: "function foo(a) { for (a.b in obj); }", options: [{ props: true, ignorePropertyModificationsFor: ["a"] }] },
{ code: "function foo(a) { for (a.b of arr); }", options: [{ props: true, ignorePropertyModificationsFor: ["a"] }], parserOptions: { ecmaVersion: 6 } },
{ code: "function foo(a, z) { a.b = 0; x.y = 0; }", options: [{ props: true, ignorePropertyModificationsFor: ["a", "x"] }] },
{ code: "function foo(a) { a.b.c = 0;}", options: [{ props: true, ignorePropertyModificationsFor: ["a"] }] },
{
Expand All @@ -53,6 +59,33 @@ ruleTester.run("no-param-reassign", rule, {
code: "function foo(a) { ({...a.b} = obj); }",
options: [{ props: false }],
parserOptions: { ecmaVersion: 2018 }
},
{
code: "function foo(a) { for (obj[a.b] in obj); }",
options: [{ props: true }]
},
{
code: "function foo(a) { for (obj[a.b] of arr); }",
options: [{ props: true }],
parserOptions: { ecmaVersion: 6 }
},
{
code: "function foo(a) { for (bar in a.b); }",
options: [{ props: true }]
},
{
code: "function foo(a) { for (bar of a.b); }",
options: [{ props: true }],
parserOptions: { ecmaVersion: 6 }
},
{
code: "function foo(a) { for (bar in baz) a.b; }",
options: [{ props: true }]
},
{
code: "function foo(a) { for (bar of baz) a.b; }",
options: [{ props: true }],
parserOptions: { ecmaVersion: 6 }
}
],

Expand All @@ -68,6 +101,8 @@ ruleTester.run("no-param-reassign", rule, {
{ code: "function foo([, {bar}]) { bar = 13; }", parserOptions: { ecmaVersion: 6 }, errors: [{ message: "Assignment to function parameter 'bar'." }] },
{ code: "function foo(bar) { ({bar} = {}); }", parserOptions: { ecmaVersion: 6 }, errors: [{ message: "Assignment to function parameter 'bar'." }] },
{ code: "function foo(bar) { ({x: [, bar = 0]} = {}); }", parserOptions: { ecmaVersion: 6 }, errors: [{ message: "Assignment to function parameter 'bar'." }] },
{ code: "function foo(bar) { for (bar in baz); }", errors: [{ message: "Assignment to function parameter 'bar'." }] },
{ code: "function foo(bar) { for (bar of baz); }", parserOptions: { ecmaVersion: 6 }, errors: [{ message: "Assignment to function parameter 'bar'." }] },

{
code: "function foo(bar) { bar.a = 0; }",
Expand All @@ -89,6 +124,17 @@ ruleTester.run("no-param-reassign", rule, {
options: [{ props: true }],
errors: [{ message: "Assignment to property of function parameter 'bar'." }]
},
{
code: "function foo(bar) { for (bar.a in {}); }",
options: [{ props: true }],
errors: [{ message: "Assignment to property of function parameter 'bar'." }]
},
{
code: "function foo(bar) { for (bar.a of []); }",
options: [{ props: true }],
parserOptions: { ecmaVersion: 6 },
errors: [{ message: "Assignment to property of function parameter 'bar'." }]
},
{
code: "function foo(bar) { (bar ? bar : [])[0] = 1; }",
options: [{ props: true }],
Expand Down Expand Up @@ -139,6 +185,18 @@ ruleTester.run("no-param-reassign", rule, {
options: [{ props: true }],
parserOptions: { ecmaVersion: 2018 },
errors: [{ message: "Assignment to property of function parameter 'a'." }]
},
{
code: "function foo(a) { for ({bar: a.b} in {}); }",
options: [{ props: true }],
parserOptions: { ecmaVersion: 6 },
errors: [{ message: "Assignment to property of function parameter 'a'." }]
},
{
code: "function foo(a) { for ([a.b] of []); }",
options: [{ props: true }],
parserOptions: { ecmaVersion: 6 },
errors: [{ message: "Assignment to property of function parameter 'a'." }]
}
]
});

0 comments on commit 222d27c

Please sign in to comment.