Skip to content
This repository was archived by the owner on Oct 21, 2022. It is now read-only.

Commit d26c74c

Browse files
dentuzhikarturluik
authored andcommitted
feat: Add an option to allow retun value of bindActionCreators call
Fixes DianaSuvorova#30
1 parent cfffab2 commit d26c74c

File tree

5 files changed

+153
-4
lines changed

5 files changed

+153
-4
lines changed

.editorconfig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# EditorConfig helps developers define and maintain consistent
2+
# coding styles between different editors and IDEs
3+
# editorconfig.org
4+
5+
root = true
6+
7+
[*]
8+
end_of_line = lf
9+
charset = utf-8
10+
trim_trailing_whitespace = true
11+
insert_final_newline = true
12+
indent_style = space
13+
indent_size = 2
14+
15+
[*.{diff,md}]
16+
trim_trailing_whitespace = false

docs/rules/mapDispatchToProps-returns-object.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,30 @@ const mapDispatchToProps = {anAction: anAction}
3939
const mapDispatchToProps = (dispatch) => ({anAction: dispatch(anAction())})
4040
```
4141

42+
## Options
43+
44+
### allowReturnBindFn
45+
Rule example
46+
```js
47+
{
48+
'react-redux/mapDispatchToProps-returns-object': ['error', { allowReturnBindFn: true }],
49+
}
50+
```
51+
52+
If this option is set to true, return the result of `bindActionCreators` considered to be valid:
53+
54+
```js
55+
const mapDispatchToProps = (dispatch) => {
56+
return bindActionCreators(
57+
{
58+
requestFilteredItems,
59+
showAlert: showAlertAction,
60+
},
61+
dispatch
62+
);
63+
}
64+
```
65+
4266
## Not supported use cases.
4367

4468
#### mapDispatchToProps is a function but actions are not bound to dispatch

lib/rules/mapDispatchToProps-returns-object.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ const report = function (context, node) {
1010

1111

1212
module.exports = function (context) {
13+
const config = context.options[0] || {};
14+
15+
const shouldAllowBindActionCreators = returnNode =>
16+
config.allowReturnBindFn && utils.isReturnNodeBindActionCreatorsCall(returnNode);
17+
1318
return {
1419
VariableDeclaration(node) {
1520
node.declarations.forEach((decl) => {
@@ -19,7 +24,7 @@ module.exports = function (context) {
1924
decl.init.type === 'FunctionExpression'
2025
)) {
2126
const returnNode = utils.getReturnNode(decl.init);
22-
if (!utils.isObject(returnNode)) {
27+
if (!utils.isObject(returnNode) && !shouldAllowBindActionCreators(returnNode)) {
2328
report(context, node);
2429
}
2530
}
@@ -29,7 +34,8 @@ module.exports = function (context) {
2934
FunctionDeclaration(node) {
3035
if (node.id && node.id.name === 'mapDispatchToProps') {
3136
const returnNode = utils.getReturnNode(node.body);
32-
if (!utils.isObject(returnNode)) {
37+
38+
if (!utils.isObject(returnNode) && !shouldAllowBindActionCreators(returnNode)) {
3339
report(context, node);
3440
}
3541
}
@@ -42,7 +48,7 @@ module.exports = function (context) {
4248
mapDispatchToProps.type === 'FunctionExpression')
4349
) {
4450
const returnNode = utils.getReturnNode(mapDispatchToProps);
45-
if (!utils.isObject(returnNode)) {
51+
if (!utils.isObject(returnNode) && !shouldAllowBindActionCreators(returnNode)) {
4652
report(context, node);
4753
}
4854
}

lib/utils.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
11
'use strict';
22

3+
const BIND_ACTION_CREATORS_FN_NAME = 'bindActionCreators';
4+
35
const isObject = node => node && (
46
node.type === 'ObjectExpression' || node.type === 'Identifier'
57
);
68

9+
const isReturnNodeBindActionCreatorsCall = (node) => {
10+
if (node.type === 'CallExpression') {
11+
return node.callee.type === 'Identifier' && node.callee.name === BIND_ACTION_CREATORS_FN_NAME;
12+
}
13+
14+
return false;
15+
};
16+
717
const getReturnNode = (node) => {
818
const body = node && node.body;
919
if (!body) {
1020
return node;
11-
} else if (isObject(body)) {
21+
} else if (isObject(body) || body.type === 'CallExpression') {
1222
return body;
1323
} else if (body.type === 'BlockStatement') {
1424
return getReturnNode(body);
@@ -28,4 +38,5 @@ const getReturnNode = (node) => {
2838
module.exports = {
2939
getReturnNode,
3040
isObject,
41+
isReturnNodeBindActionCreatorsCall,
3142
};

tests/lib/rules/mapDispatchToProps-returns-object.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,95 @@ ruleTester.run('mapDispatchToProps-returns-object', rule, {
9595
],
9696
}],
9797
});
98+
99+
ruleTester.run('mapDispatchToProps-returns-object-allowReturnBindFn', rule, {
100+
valid: [
101+
{
102+
options: [{ allowReturnBindFn: true }],
103+
code: `function mapDispatchToProps(dispatch) {
104+
return bindActionCreators(
105+
{
106+
requestFilteredItems,
107+
showAlert: showAlertAction,
108+
},
109+
dispatch
110+
);
111+
}`,
112+
},
113+
{
114+
options: [{ allowReturnBindFn: true }],
115+
code: `const mapDispatchToProps = (dispatch) => {
116+
return bindActionCreators(
117+
{
118+
requestFilteredItems,
119+
showAlert: showAlertAction,
120+
},
121+
dispatch
122+
);
123+
}`,
124+
},
125+
{
126+
options: [{ allowReturnBindFn: true }],
127+
code: `const mapDispatchToProps = (dispatch) =>
128+
bindActionCreators(
129+
{
130+
requestFilteredItems,
131+
showAlert: showAlertAction,
132+
},
133+
dispatch
134+
);
135+
`,
136+
},
137+
{
138+
options: [{ allowReturnBindFn: true }],
139+
code: `export default connect(
140+
state => ({
141+
productsList: state.Products.productsList,
142+
}),
143+
function (dispatch) {
144+
return bindActionCreators(
145+
{
146+
requestFilteredItems,
147+
showAlert: showAlertAction,
148+
},
149+
dispatch
150+
)
151+
}
152+
)(Products);`,
153+
},
154+
{
155+
options: [{ allowReturnBindFn: true }],
156+
code: `export default connect(
157+
state => ({
158+
productsList: state.Products.productsList,
159+
}),
160+
(dispatch) => {
161+
return bindActionCreators(
162+
{
163+
requestFilteredItems,
164+
showAlert: showAlertAction,
165+
},
166+
dispatch
167+
)
168+
}
169+
)(Products);`,
170+
},
171+
{
172+
options: [{ allowReturnBindFn: true }],
173+
code: `export default connect(
174+
state => ({
175+
productsList: state.Products.productsList,
176+
}),
177+
(dispatch) =>
178+
bindActionCreators(
179+
{
180+
requestFilteredItems,
181+
showAlert: showAlertAction,
182+
},
183+
dispatch
184+
)
185+
)(Products);`,
186+
},
187+
],
188+
invalid: [],
189+
});

0 commit comments

Comments
 (0)