Skip to content

Commit c967000

Browse files
committed
feat: [destructuring-assignment] setting up never for sfc and class
1 parent a25003c commit c967000

File tree

3 files changed

+117
-30
lines changed

3 files changed

+117
-30
lines changed

docs/rules/destructuring-assignment.md

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# Enforce consostent usage of destructuring assignment of props, state and context (react/destructuring-assignment)
22

3-
Rule can be set to either of `always`, `never`, `ignore` for SFC and to `always` or `ignore` for class components.
4-
3+
Rule can be set to either of `always`, `never`, `ignore` for `class` and `SFC` components.
54
```js
65
"react/destructuring-assignment": [<enabled>, { "SFC": "always", "class": "always"}]
76
```
@@ -32,27 +31,57 @@ const MyComponent = ({id}) => {
3231
};
3332
```
3433

34+
```js
35+
const MyComponent = (props, context) => {
36+
const { id } = props;
37+
return (<div id={id} />)
38+
};
39+
```
40+
3541
```js
3642
const Foo = class extends React.PureComponent {
3743
render() {
38-
const { foo } = this.props;
39-
return <div>{foo}</div>;
44+
const { title } = this.context;
45+
return <div>{title}</div>;
4046
}
4147
};
4248
```
4349

44-
If rule option is set to `never` for SFC, the following pattern is considered warning:
50+
If rule option is set to `never`, the following patterns are considered warning:
4551

4652
```js
4753
const MyComponent = ({id}) => {
4854
return (<div id={id} />)
4955
};
5056
```
5157

58+
```js
59+
const MyComponent = (props) => {
60+
const { id } = props;
61+
return (<div id={id} />)
62+
};
63+
```
64+
65+
```js
66+
const Foo = class extends React.PureComponent {
67+
render() {
68+
const { title } = this.state;
69+
return <div>{title}</div>;
70+
}
71+
};
72+
```
73+
5274
and below pattern is correct:
5375

5476
```js
5577
const MyComponent = (props) => {
5678
return (<div id={props.id} />)
5779
};
5880
```
81+
82+
```js
83+
const Foo = class extends React.PureComponent {
84+
render() {
85+
return <div>{this.state.title}</div>;
86+
}
87+
};

lib/rules/destructuring-assignment.js

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,18 @@ module.exports = {
1919
},
2020
schema: [{
2121
definitions: {
22-
valueSFC: {
22+
value: {
2323
enum: [
2424
'always',
2525
'never',
2626
'ignore'
2727
]
28-
},
29-
valueClass: {
30-
enum: [
31-
'always',
32-
'ignore'
33-
]
3428
}
3529
},
3630
type: 'object',
3731
properties: {
38-
SFC: {$ref: '#/definitions/valueSFC'},
39-
class: {$ref: '#/definitions/valueClass'}
32+
SFC: {$ref: '#/definitions/value'},
33+
class: {$ref: '#/definitions/value'}
4034
},
4135
additionalProperties: false
4236
}]
@@ -127,6 +121,33 @@ module.exports = {
127121
if (classComponent) {
128122
handleClassUsage(node, classComponent);
129123
}
124+
},
125+
126+
VariableDeclarator: function(node) {
127+
const classComponent = utils.getParentComponent(node);
128+
const SFCComponent = components.get(context.getScope(node).block);
129+
130+
const destructuring = (node.init && node.id && node.id.type === 'ObjectPattern');
131+
// let {foo} = props;
132+
const destructuringSFC = destructuring && (node.init.name === 'props' || node.init.name === 'context');
133+
// let {foo} = this.props;
134+
const destructuringClass = destructuring && node.init.object && node.init.object.type === 'ThisExpression' && (
135+
node.init.property.name === 'props' || node.init.property.name === 'context' || node.init.property.name === 'state'
136+
);
137+
138+
if (SFCComponent && destructuringSFC && options.SFC === 'never') {
139+
context.report({
140+
node: node,
141+
message: `Must never use destructuring ${node.init.name} assignment`
142+
});
143+
}
144+
145+
if (classComponent && destructuringClass && options.class === 'never') {
146+
context.report({
147+
node: node,
148+
message: `Must never use destructuring ${node.init.property.name} assignment`
149+
});
150+
}
130151
}
131152
};
132153
})

tests/lib/rules/destructuring-assignment.js

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,24 @@ const parserOptions = {
2020
const ruleTester = new RuleTester({parserOptions});
2121
ruleTester.run('destructuring-assignment', rule, {
2222
valid: [{
23-
code: `const Foo = class extends React.PureComponent {
24-
render() {
25-
const { foo } = this.props;
26-
return <div>{foo}</div>;
27-
}
28-
};`
29-
}, {
3023
code: `const Foo = class extends React.PureComponent {
3124
render() {
3225
const { foo } = this.props;
3326
return <div>{foo}</div>;
3427
}
3528
};`,
36-
options: [{SFC: 'always', class: 'always'}]
29+
options: [{SFC: 'always', class: 'always'}],
30+
parser: 'babel-eslint'
3731
}, {
3832
code: `const MyComponent = ({ id, className }) => (
3933
<div id={id} className={className} />
4034
);`
35+
}, {
36+
code: `const MyComponent = (props) => {
37+
const { id, className } = props;
38+
return <div id={id} className={className} />
39+
};`,
40+
parser: 'babel-eslint'
4141
}, {
4242
code: `const MyComponent = ({ id, className }) => (
4343
<div id={id} className={className} />
@@ -72,12 +72,6 @@ ruleTester.run('destructuring-assignment', rule, {
7272
<div id={id} props={props} color={color} />
7373
);`,
7474
options: [{SFC: 'always', class: 'always'}]
75-
}, {
76-
code: `const MyComponent = (props) => {
77-
const { id, className } = props;
78-
return <div id={id} className={className} />
79-
};`,
80-
options: [{SFC: 'never'}]
8175
}, {
8276
code: `const Foo = class extends React.PureComponent {
8377
render() {
@@ -107,7 +101,8 @@ ruleTester.run('destructuring-assignment', rule, {
107101
return <div>{foo}</div>;
108102
}
109103
};`,
110-
options: [{SFC: 'always', class: 'always'}]
104+
options: [{SFC: 'always', class: 'always'}],
105+
parser: 'babel-eslint'
111106
}, {
112107
code: `const Foo = class extends React.PureComponent {
113108
render() {
@@ -122,7 +117,15 @@ ruleTester.run('destructuring-assignment', rule, {
122117
return <div>{foo}</div>;
123118
}
124119
};`,
125-
options: [{SFC: 'always', class: 'always'}]
120+
options: [{SFC: 'always', class: 'always'}],
121+
parser: 'babel-eslint'
122+
}, {
123+
code: `const MyComponent = (props) => {
124+
const { h, i } = hi;
125+
return <div id={props.id} className={props.className} />
126+
};`,
127+
options: [{SFC: 'never'}],
128+
parser: 'babel-eslint'
126129
}],
127130
invalid: [{
128131
code: `const MyComponent = (props) => {
@@ -203,5 +206,39 @@ ruleTester.run('destructuring-assignment', rule, {
203206
errors: [
204207
{message: 'Must use destructuring props assignment'}
205208
]
209+
}, {
210+
code: `const Foo = class extends React.PureComponent {
211+
render() {
212+
const { foo } = this.props;
213+
return <div>{foo}</div>;
214+
}
215+
};`,
216+
options: [{SFC: 'always', class: 'never'}],
217+
parser: 'babel-eslint',
218+
errors: [
219+
{message: 'Must never use destructuring props assignment'}
220+
]
221+
}, {
222+
code: `const MyComponent = (props) => {
223+
const { id, className } = props;
224+
return <div id={id} className={className} />
225+
};`,
226+
options: [{SFC: 'never'}],
227+
parser: 'babel-eslint',
228+
errors: [
229+
{message: 'Must never use destructuring props assignment'}
230+
]
231+
}, {
232+
code: `const Foo = class extends React.PureComponent {
233+
render() {
234+
const { foo } = this.state;
235+
return <div>{foo}</div>;
236+
}
237+
};`,
238+
options: [{SFC: 'always', class: 'never'}],
239+
parser: 'babel-eslint',
240+
errors: [
241+
{message: 'Must never use destructuring state assignment'}
242+
]
206243
}]
207244
});

0 commit comments

Comments
 (0)