Skip to content

Commit

Permalink
Update: Add ignored prop regex no-param-reassign (#11275)
Browse files Browse the repository at this point in the history
Uses new `ignoredPropertyAssignmentsRegex` option.
  • Loading branch information
lbennett-stacki authored and ilyavolodin committed Oct 24, 2019
1 parent e5382d6 commit aac3be4
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 2 deletions.
20 changes: 19 additions & 1 deletion docs/rules/no-param-reassign.md
Expand Up @@ -42,7 +42,7 @@ function foo(bar) {

## Options

This rule takes one option, an object, with a boolean property `"props"` and an array `"ignorePropertyModificationsFor"`. `"props"` is `false` by default. If `"props"` is set to `true`, this rule warns against the modification of parameter properties unless they're included in `"ignorePropertyModificationsFor"`, which is an empty array by default.
This rule takes one option, an object, with a boolean property `"props"`, and arrays `"ignorePropertyModificationsFor"` and `"ignorePropertyModificationsForRegex"`. `"props"` is `false` by default. If `"props"` is set to `true`, this rule warns against the modification of parameter properties unless they're included in `"ignorePropertyModificationsFor"` or `"ignorePropertyModificationsForRegex"`, which is an empty array by default.

### props

Expand Down Expand Up @@ -124,6 +124,24 @@ function foo(bar) {
}
```

Examples of **correct** code for the `{ "props": true }` option with `"ignorePropertyModificationsForRegex"` set:

```js
/*eslint no-param-reassign: ["error", { "props": true, "ignorePropertyModificationsForRegex": ["^bar"] }]*/

function foo(bar) {
barVar.prop = "value";
}

function foo(bar) {
delete barrito.aaa;
}

function foo(bar) {
bar_.aaa++;
}
```


## When Not To Use It

Expand Down
23 changes: 22 additions & 1 deletion lib/rules/no-param-reassign.js
Expand Up @@ -45,6 +45,13 @@ module.exports = {
type: "string"
},
uniqueItems: true
},
ignorePropertyModificationsForRegex: {
type: "array",
items: {
type: "string"
},
uniqueItems: true
}
},
additionalProperties: false
Expand All @@ -57,6 +64,7 @@ module.exports = {
create(context) {
const props = context.options[0] && context.options[0].props;
const ignoredPropertyAssignmentsFor = context.options[0] && context.options[0].ignorePropertyModificationsFor || [];
const ignoredPropertyAssignmentsForRegex = context.options[0] && context.options[0].ignorePropertyModificationsForRegex || [];

/**
* Checks whether or not the reference modifies properties of its variable.
Expand Down Expand Up @@ -136,6 +144,19 @@ module.exports = {
return false;
}

/**
* Tests that an identifier name matches any of the ignored property assignments.
* First we test strings in ignoredPropertyAssignmentsFor.
* Then we instantiate and test RegExp objects from ignoredPropertyAssignmentsForRegex strings.
* @param {string} identifierName - A string that describes the name of an identifier to
* ignore property assignments for.
* @returns {boolean} Whether the string matches an ignored property assignment regular expression or not.
*/
function isIgnoredPropertyAssignment(identifierName) {
return ignoredPropertyAssignmentsFor.includes(identifierName) ||
ignoredPropertyAssignmentsForRegex.some(ignored => new RegExp(ignored, "u").test(identifierName));
}

/**
* Reports a reference if is non initializer and writable.
* @param {Reference} reference A reference to check.
Expand All @@ -157,7 +178,7 @@ module.exports = {
) {
if (reference.isWrite()) {
context.report({ node: identifier, message: "Assignment to function parameter '{{name}}'.", data: { name: identifier.name } });
} else if (props && isModifyingProp(reference) && ignoredPropertyAssignmentsFor.indexOf(identifier.name) === -1) {
} else if (props && isModifyingProp(reference) && !isIgnoredPropertyAssignment(identifier.name)) {
context.report({ node: identifier, message: "Assignment to property of function parameter '{{name}}'.", data: { name: identifier.name } });
}
}
Expand Down
17 changes: 17 additions & 0 deletions tests/lib/rules/no-param-reassign.js
Expand Up @@ -45,6 +45,11 @@ ruleTester.run("no-param-reassign", rule, {
{ 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"] }] },
{ code: "function foo(aFoo) { aFoo.b = 0; }", options: [{ props: true, ignorePropertyModificationsForRegex: ["^a.*$"] }] },
{ code: "function foo(aFoo) { ++aFoo.b; }", options: [{ props: true, ignorePropertyModificationsForRegex: ["^a.*$"] }] },
{ code: "function foo(aFoo) { delete aFoo.b; }", options: [{ props: true, ignorePropertyModificationsForRegex: ["^a.*$"] }] },
{ code: "function foo(a, z) { aFoo.b = 0; x.y = 0; }", options: [{ props: true, ignorePropertyModificationsForRegex: ["^a.*$", "^x.*$"] }] },
{ code: "function foo(aFoo) { aFoo.b.c = 0;}", options: [{ props: true, ignorePropertyModificationsForRegex: ["^a.*$"] }] },
{
code: "function foo(a) { ({ [a]: variable } = value) }",
options: [{ props: true }],
Expand Down Expand Up @@ -152,6 +157,18 @@ ruleTester.run("no-param-reassign", rule, {
parserOptions: { ecmaVersion: 6 },
errors: [{ message: "Assignment to property of function parameter 'bar'." }]
},
{
code: "function foo(bar) { [bar.a] = []; }",
options: [{ props: true, ignorePropertyModificationsForRegex: ["^a.*$"] }],
parserOptions: { ecmaVersion: 6 },
errors: [{ message: "Assignment to property of function parameter 'bar'." }]
},
{
code: "function foo(bar) { [bar.a] = []; }",
options: [{ props: true, ignorePropertyModificationsForRegex: ["^B.*$"] }],
parserOptions: { ecmaVersion: 6 },
errors: [{ message: "Assignment to property of function parameter 'bar'." }]
},
{
code: "function foo(bar) { ({foo: bar.a} = {}); }",
options: [{ props: true }],
Expand Down

0 comments on commit aac3be4

Please sign in to comment.