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

Commit 5ee57de

Browse files
committed
feat: Add an option to allow retun value of bindActionCreators call
Fixes DianaSuvorova#30
1 parent b1298ac commit 5ee57de

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
@@ -90,3 +90,95 @@ ruleTester.run('mapDispatchToProps-returns-object', rule, {
9090
],
9191
}],
9292
});
93+
94+
ruleTester.run('mapDispatchToProps-returns-object-allowReturnBindFn', rule, {
95+
valid: [
96+
{
97+
options: [{ allowReturnBindFn: true }],
98+
code: `function mapDispatchToProps(dispatch) {
99+
return bindActionCreators(
100+
{
101+
requestFilteredItems,
102+
showAlert: showAlertAction,
103+
},
104+
dispatch
105+
);
106+
}`,
107+
},
108+
{
109+
options: [{ allowReturnBindFn: true }],
110+
code: `const mapDispatchToProps = (dispatch) => {
111+
return bindActionCreators(
112+
{
113+
requestFilteredItems,
114+
showAlert: showAlertAction,
115+
},
116+
dispatch
117+
);
118+
}`,
119+
},
120+
{
121+
options: [{ allowReturnBindFn: true }],
122+
code: `const mapDispatchToProps = (dispatch) =>
123+
bindActionCreators(
124+
{
125+
requestFilteredItems,
126+
showAlert: showAlertAction,
127+
},
128+
dispatch
129+
);
130+
`,
131+
},
132+
{
133+
options: [{ allowReturnBindFn: true }],
134+
code: `export default connect(
135+
state => ({
136+
productsList: state.Products.productsList,
137+
}),
138+
function (dispatch) {
139+
return bindActionCreators(
140+
{
141+
requestFilteredItems,
142+
showAlert: showAlertAction,
143+
},
144+
dispatch
145+
)
146+
}
147+
)(Products);`,
148+
},
149+
{
150+
options: [{ allowReturnBindFn: true }],
151+
code: `export default connect(
152+
state => ({
153+
productsList: state.Products.productsList,
154+
}),
155+
(dispatch) => {
156+
return bindActionCreators(
157+
{
158+
requestFilteredItems,
159+
showAlert: showAlertAction,
160+
},
161+
dispatch
162+
)
163+
}
164+
)(Products);`,
165+
},
166+
{
167+
options: [{ allowReturnBindFn: true }],
168+
code: `export default connect(
169+
state => ({
170+
productsList: state.Products.productsList,
171+
}),
172+
(dispatch) =>
173+
bindActionCreators(
174+
{
175+
requestFilteredItems,
176+
showAlert: showAlertAction,
177+
},
178+
dispatch
179+
)
180+
)(Products);`,
181+
},
182+
],
183+
invalid: [],
184+
});

0 commit comments

Comments
 (0)