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

Commit 0ef6255

Browse files
committed
feat: Add an option to allow retun value of bindActionCreators call
Fixes DianaSuvorova#30
1 parent df981f9 commit 0ef6255

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

0 commit comments

Comments
 (0)