New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update: support more options in prefer-destructuring #8796
Update: support more options in prefer-destructuring #8796
Conversation
LGTM |
@VictorHom, thanks for your PR! By analyzing the history of the files in this pull request, we identified @alexlafroscia, @not-an-aardvark and @flowmemo to be potential reviewers. |
LGTM |
1 similar comment
LGTM |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR! I left a few comments.
docs/rules/prefer-destructuring.md
Outdated
@@ -33,7 +33,9 @@ This rule takes two sets of configuration objects; the first controls the types | |||
|
|||
The first has two properties, `array` and `object`, which can be used to turn on or off the destructuring requirement for each of those types independently. By default, both are `true`. | |||
|
|||
The second has a single property, `enforceForRenamedProperties`, that controls whether or not the `object` destructuring rules are applied in cases where the variable requires the property being access to be renamed. | |||
The first has two properties, `VariableDeclarator` and `AssignmentExpression`, which can be used to turn on or off the destructuring requirement for each of those types independently. Each property accepts an object that accpets two properties, `array` and `object`, which can be used to turn on or off the destructuring requirement for each of those types independently for variable declarations and assignment expressions. By default, `array` and `object` are set to true for both `VariableDeclarator` and `AssignmentExpression`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry if this was unclear before, but I think we should continue to allow the array
and object
top-level options. Making breaking changes to rule schemas is generally a pretty big deal -- in addition to breaking users, it also tends to make shareable configs invalid, which makes upgrading very tedious -- so we try to almost never do it. (Changing the default behavior of a rule schema while keeping all previous schemas valid is a bit better, but that's a separate topic.)
To avoid extra complexity, we can disallow mixing the old and new behaviors -- for example, this would still be an illegal config:
rules:
prefer-destructuring: [error, {array: true, VariableDeclarator: {array: false}}]
docs/rules/prefer-destructuring.md
Outdated
The second has a single property, `enforceForRenamedProperties`, that controls whether or not the `object` destructuring rules are applied in cases where the variable requires the property being access to be renamed. | ||
The first has two properties, `VariableDeclarator` and `AssignmentExpression`, which can be used to turn on or off the destructuring requirement for each of those types independently. Each property accepts an object that accpets two properties, `array` and `object`, which can be used to turn on or off the destructuring requirement for each of those types independently for variable declarations and assignment expressions. By default, `array` and `object` are set to true for both `VariableDeclarator` and `AssignmentExpression`. | ||
|
||
The second has a single property, `enforceForRenamedProperties`, that controls whether or not the `object` destructuring rules are applied in cases where the variable requires the property being access to be renamed. If `object` in `AssignmentExpression` is set to false, `enforceForRenamedProperties` property is ignored. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is enforceForRenamedProperties
ignored in this case? It seems like it would still be useful in variable declarations for something like
var foo = bar.baz
// ->
var {baz: foo} = bar;
lib/rules/prefer-destructuring.js
Outdated
report(reportNode, "object"); | ||
return; | ||
} | ||
|
||
if (checkObjects) { | ||
if ((checkObjectsInVariableDeclarator && reportNode.type === "VariableDeclarator") || (checkObjectsInAssignmentExpression && reportNode.type === "AssignmentExpression")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the value in this if
statement is redundant, because reportNode.type
will always be either "VariableDeclarator"
or "AssignmentExpression"
. It can be simplified to
if (checkObjectsInVariableDeclarator || checkObjectsInAssignmentExpression) {
// ...
}
lib/rules/prefer-destructuring.js
Outdated
const assignmentExpression = enabledTypes.AssignmentExpression; | ||
|
||
checkArraysInAssignmentExpression = assignmentExpression.hasOwnProperty("array") ? assignmentExpression.array : checkArraysInAssignmentExpression; | ||
checkObjectsInAssignmentExpression = assignmentExpression.hasOwnProperty("object") ? assignmentExpression.object : checkObjectsInAssignmentExpression; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This config-checking logic is getting kind of complicated. I think having a variable for each config case won't scale very well as more options are added, especially if we restore support for the old top-level "array" option. Can we extract this into a function instead? For example:
/**
* @param {string} nodeType "AssignmentExpression" or "VariableDeclaration"
* @param {string} destructuringType "array" or "object"
* @returns {boolean} `true` if the destructuring type should be checked for the given node
*/
function shouldCheck(nodeType, destructuringType) {
return context.options[0] &&
context.options[0][nodeType] &&
context.options[0][nodeType][destructuringType] === false;
}
Then rather than handling four different variables, the performCheck
function, it could just use something like
if (isArrayIndexAccess(node) && shouldCheck(reportNode.type, "array")) {
// ...
}
// ...
LGTM |
9ac42a3
to
08db36e
Compare
LGTM |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for contributing! I have a few questions.
Also, I know this is from the proposal, but I wonder if VariableDeclaration
might make more sense as an option instead of VariableDeclarator
. @not-an-aardvark I know you proposed this originally - what do you think?
docs/rules/prefer-destructuring.md
Outdated
{ | ||
"rules": { | ||
"prefer-destructuring": ["error", { | ||
"VariableDeclaration": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be VariableDeclarator
to match the other uses? I actually think VariableDeclaration
might make more sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just want to make sure - you mean that you would prefer the attribute to be named VariableDeclaration?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like it makes more sense to someone who's not familiar with ESTree and node types, but let's see what others say. I don't want to hold this up over a naming thing, but wanted to bring it up since it is more difficult to change things once they're merged!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like VariableDeclarator because I feel it's a closer parallel to AssignmentExpression, but I can see the potential for confusion. No strong opinion from me, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's leave it as VariableDeclarator - I don't want to hold this PR up over a naming thing, especially since I was late to the game in the disxussion. Sorry @VictorHom, looks like you already changed it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
totally fine! I'm sure there's a few more things that could use some cleaning up too.
docs/rules/prefer-destructuring.md
Outdated
@@ -62,6 +62,45 @@ An example configuration, with the defaults filled in, looks like this: | |||
} | |||
``` | |||
|
|||
Alternatively, you can use a different set of configuration objects to have more control on what to enforce destructuring. It also takes two sets of configuration objects. | |||
|
|||
The first has two properties, `VariableDeclarator` and `AssignmentExpression`, which can be used to turn on or off the destructuring requirement for each of those types independently. Each property accepts an object that accpets two properties, `array` and `object`, which can be used to turn on or off the destructuring requirement for each of those types independently for variable declarations and assignment expressions. By default, `array` and `object` are set to true for both `VariableDeclarator` and `AssignmentExpression`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: accpets
-> accepts
lib/rules/prefer-destructuring.js
Outdated
@@ -110,22 +167,21 @@ module.exports = { | |||
} | |||
|
|||
if (isArrayIndexAccess(rightNode)) { | |||
if (checkArrays) { | |||
if (shouldCheck("VariableDeclarator", "array") || shouldCheck("AssignmentExpression", "array") || checkArrays) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies if I'm misunderstanding something here, but I'm curious what happens for all these checks when the node being evaluated is either a VariableDeclarator
or AssignmentExpression
and the configuration is set to true
for the other node type.
Some example test cases to illustrate what I mean:
{
code: "foo = object.foo;",
options: [{ VariableDeclarator: { object: true }, AssignmentExpression: { object: false } }]
},
{
code: "var foo = object.foo;",
options: [{ VariableDeclarator: { object: false }, AssignmentExpression: { object: true } }]
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. With this configuration, both of these are valid cases, along with a few more cases that I added
LGTM |
1 similar comment
LGTM |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry about the delay. This looks mostly good, I just have a few small suggestions.
docs/rules/prefer-destructuring.md
Outdated
|
||
The second has a single property, `enforceForRenamedProperties`, that controls whether or not the `object` destructuring rules are applied in cases where the variable requires the property being access to be renamed. | ||
The second has a single property, enforceForRenamedProperties, that controls whether or not the object destructuring rules are applied in cases where the variable requires the property being access to be renamed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you surround enforceForRenamedProperties
in backticks?
docs/rules/prefer-destructuring.md
Outdated
|
||
The first has two properties, `VariableDeclarator` and `AssignmentExpression`, which can be used to turn on or off the destructuring requirement for each of those types independently. Each property accepts an object that accepts two properties, `array` and `object`, which can be used to turn on or off the destructuring requirement for each of those types independently for variable declarations and assignment expressions. By default, `array` and `object` are set to true for both `VariableDeclarator` and `AssignmentExpression`. | ||
|
||
The second has a single property, `enforceForRenamedProperties`, that controls whether or not the `object` destructuring rules are applied in cases where the variable requires the property being access to be renamed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this documentation can be simplified because the enforceForRenamedProperties
option is the same in either case. It seems a bit confusing that the description of that option is duplicated.
I'm picturing the documentation looking like this, but feel free to organize it differently:
This rule accepts an object as the first option, which determines what types of destructuring the rule applies to. (...more description about
array
andobject
options)
Alternatively, you can use separate configurations for different assignment types. (...more description aboutVariableDeclarator
andAssignmentExpression
options)
The rule also has a second object option with a single key ,enforceForRenamedProperties
, which determines whether theobject
destructuring rule applies to renamed variables.
lib/rules/prefer-destructuring.js
Outdated
properties: { | ||
array: { | ||
type: "boolean", | ||
default: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the default
property have any effect? I hadn't been aware it exists 😃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it for the clarity, but it has no visible effect from running tests.
I used after checking the examples in https://github.com/json-schema-org/json-schema-org.github.io/search?utf8=%E2%9C%93&q=default%3A&type=
let me know if that’s okay. otherwise, I’m not tied to it and if removing makes more sense, then I can remove.
lib/rules/prefer-destructuring.js
Outdated
if (typeof enabledTypes.VariableDeclarator !== "undefined" || typeof enabledTypes.AssignmentExpression !== "undefined") { | ||
checkArrays = false; | ||
checkObjects = false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not a blocker for this PR, but having two separate methods of checking the options depending on the type of configuration used seems like a bug hazard if something changes later on. Maybe the old config-checking variables could be eliminated too with something like
const normalizedOptions = typeof enabledTypes.array !== "undefined" || typeof context.options[0].object !== "undefined"
? { VariableDeclarator: enabledTypes, AssignmentExpression: enabledTypes }
: enabledTypes
In other words, the old array
and object
schema would basically be transformed into a special case of the VariableDeclarator
/AssignmentExpression
schema where both assignment types happen to have the same configured options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated to using a normalizedOptions
lib/rules/prefer-destructuring.js
Outdated
@@ -110,22 +167,27 @@ module.exports = { | |||
} | |||
|
|||
if (isArrayIndexAccess(rightNode)) { | |||
if (checkArrays) { | |||
if ((shouldCheck("VariableDeclarator", "array") && reportNode.type === "VariableDeclarator") || | |||
(shouldCheck("AssignmentExpression", "array") && reportNode.type === "AssignmentExpression") || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this could be simplified by just using if (shouldCheck(reportNode.type, "array"))
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The main reason why I added the reportNode.type check is to handle cases
{
code: "foo = array[0];",
options: [{ VariableDeclarator: { array: true }, AssignmentExpression: { array: false } }, { enforceForRenamedProperties: false }]
},
{
code: "var foo = array[0];",
options: [{ VariableDeclarator: { array: false }, AssignmentExpression: { array: true } }, { enforceForRenamedProperties: false }]
},
where the check for array/object is swapped between variabledeclarator and assignmentexpression
}, | ||
{ | ||
code: "var foo = object[bar];", | ||
code: "var foo = object['bar'];", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this change necessary? (I don't mind the new version, I'm just sometimes worried about changing old tests because that can prevent regressions from being caught.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed back. not sure why I updated to add quotes.
}] | ||
}, | ||
{ | ||
code: "var foo = object[bar];", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add some additional invalid tests? It would be nice to see:
- A test for the
array
option with theVariableDeclarator
/AssignmentExpression
option style - A test with the
AssignmentExpression
option - A test where the
VariableDeclarator
andAssignmentExpression
options are different (e.g. if the code has an object property access without destructuring in an assignment expression, and the options are{AssignmentExpression: {object: true}, VariableDeclarator: {object: false}}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added more invalid tests
LGTM |
1 similar comment
LGTM |
@not-an-aardvark just want to bring this pr back up for review when you have some time |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I left a few more comments.
docs/rules/prefer-destructuring.md
Outdated
@@ -29,11 +29,15 @@ var foo = object.bar; | |||
|
|||
### Options | |||
|
|||
This rule takes two sets of configuration objects; the first controls the types that the rule is applied to, and the second controls the way those objects are evaluated. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you move this section to before the code samples?
lib/rules/prefer-destructuring.js
Outdated
const enabledTypes = context.options[0]; | ||
const additionalOptions = context.options[1]; | ||
let enforceForRenamedProperties = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: I think this can just be let enforceForRenamedProperties = context.options[1] && context.options[1].enforceForRenamedProperties;
lib/rules/prefer-destructuring.js
Outdated
@@ -110,22 +159,26 @@ module.exports = { | |||
} | |||
|
|||
if (isArrayIndexAccess(rightNode)) { | |||
if (checkArrays) { | |||
if ((shouldCheck("VariableDeclarator", "array") && reportNode.type === "VariableDeclarator") || | |||
(shouldCheck("AssignmentExpression", "array") && reportNode.type === "AssignmentExpression")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Continuing the discussion from #8796 (comment))
I'm not sure I understand -- wouldn't that result in the same behavior? Assuming reportNode.type
is always either VariableDeclarator
or AssignmentExpression
, it seems like shouldCheck(reportNode.type, "array")
would result in the same behavior. (The if
statement here has two cases, but only one of them is relevant at any given time, so shouldCheck(reportNode.type, "array")
would just combine the two cases.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see what you are saying now. I misinterpreted. sorry for the confusion.
lib/rules/prefer-destructuring.js
Outdated
properties: { | ||
array: { | ||
type: "boolean", | ||
default: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Continuing the discussion from #8796 (comment))
If it has no effects, then I think we should remove it, because it could be misleading and make people think that it does have an effect. If we want to indicate the default there, I think adding a comment would be better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally, we've let the documentation and code speak for itself in this area
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will remove in that case
docs/rules/prefer-destructuring.md
Outdated
|
||
The first has two properties, `array` and `object`, which can be used to turn on or off the destructuring requirement for each of those types independently. By default, both are `true`. | ||
The two properties, `array` and `object`, can be used to turn on or off the destructuring requirement for each of those types independently. By default, both are true. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be useful to give more examples for each option format after these descriptions, e.g.
The two properties, `array` and `object`, which can be used to turn on or off the destructuring requirement for each of those types independently. By default, both are true.
For example, the following configuration enforces only object destructuring, but not array destructuring:
```json
{
"rules": {
"prefer-destructuring": ["error", {"object": true, "array": false}]
}
}
```
docs/rules/prefer-destructuring.md
Outdated
The second has a single property, `enforceForRenamedProperties`, that controls whether or not the `object` destructuring rules are applied in cases where the variable requires the property being access to be renamed. | ||
Alternatively, you can use separate configurations for different assignment types. It accepts 2 other keys instead of `array` and `object`. | ||
|
||
One key is `VariableDeclarator` and the other is `AssignmentExpression`, which can be used to control the destructuring requirement for each of those types independently. Each property accepts an object that accepts two properties, `array` and `object`, which can be used to control the destructuring requirement for each of `array` and `object` independently for variable declarations and assignment expressions. By default, `array` and `object` are set to true for both `VariableDeclarator` and `AssignmentExpression`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add some code samples with the VariableDeclarator
and AssignmentExpression
options?
LGTM |
d871981
to
bf14aee
Compare
LGTM |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
I just have one nitpick with the docs, but it shouldn't block this from being merged.
|
||
Examples of **correct** code when array destructuring in `AssignmentExpression` is enforced: | ||
|
||
```javascript |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a configuration comment to this code block?
/* eslint prefer-destructuring: ["error", {VariableDeclarator: {array: true}}] */
LGTM |
Awesome! thanks for the code reviews. @kaicataldo can you also give a review as well? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks for contributing!
[X ] Changes an existing rule (template)
What rule do you want to change?
prefer-destructuring.js
This pr is in reference to the issue #7886
Does this change cause the rule to produce more or fewer warnings?
less warnings since you have more flexibility to control destructuring errors.
How will the change be implemented? (New option, new default behavior, etc.)?
The first parameter of destructuring has been updated to also take a VariableDeclarator value or an AssignmentExpression value. Each value takes an object that takes an object of optional keys array and/or object.
The old parameters of {object: Boolean, array: Boolean} is still supported
Please provide some example code that this change will affect:
What does the rule currently do for this code?
In the above example, prefer-destructuring will be enforced for variable declarations from objects but not from arrays. Prefer-destructuring will be enforced for assignment expressions for both arrays and objects
What will the rule do after it's changed?
It will let users have more flexibility and control over when prefer-destructuring should be enforced.