-
-
Notifications
You must be signed in to change notification settings - Fork 204
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
[NEW RULE] Adding no-async-actions rule [DO NOT MERGE] #424
base: master
Are you sure you want to change the base?
Changes from all commits
24ebede
84ffc97
a8dda02
020b127
efc6aaf
8027f82
85e5e05
e849ad4
80cc3aa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# Do not use async actions | ||
## Rule `no-async-actions` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead, could we throw a lint error only after an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. example?: #1421 |
||
|
||
Using async actions can lead to memory leaks and application errors if you | ||
don't check for `isDestroying` and `isDestroyed` after each async step | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a bit unclear on why we should not use async actions. Can you explain that more and include in the doc here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Me too not very clear about the requirement, i am exploring , will add more info once ready There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's add at least a brief explanation of the reasoning in this doc. |
||
|
||
Examples of **incorrect** code for this rule: | ||
```js | ||
actions: { | ||
async handleClick() { | ||
// ... | ||
} | ||
} | ||
``` | ||
|
||
```js | ||
actions: { | ||
handleClick() { | ||
return something.then(() => { /* ... */ }); | ||
} | ||
} | ||
``` | ||
|
||
```js | ||
@action | ||
async handleClick() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why forbid this? This is totally valid |
||
// ... | ||
} | ||
``` | ||
|
||
```js | ||
@action | ||
handleClick() { | ||
return something.then(() => { /* ... */ }); | ||
} | ||
``` | ||
|
||
|
||
Examples of **correct** code for this rule: | ||
```js | ||
actions: { | ||
handleClick() { | ||
return nothingOrSomethingThatIsNotAPromise; | ||
} | ||
} | ||
``` | ||
|
||
|
||
## Further Reading | ||
|
||
- Ember Concurrency http://ember-concurrency.com/docs/tutorial (scroll down to Version 4) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
'use strict'; | ||
|
||
const utils = require('../utils/utils'); | ||
|
||
|
||
//------------------------------------------------------------------------------ | ||
// General rule - Don't use async actions | ||
//------------------------------------------------------------------------------ | ||
|
||
|
||
const ERROR_MESSAGE = 'Do not use async actions.'; | ||
|
||
module.exports = { | ||
meta: { | ||
docs: { | ||
description: 'Disallow usage of async actions in components', | ||
category: 'Possible Errors', | ||
url: 'http://ember-concurrency.com/docs/tutorial' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please rebase on the latest master to pickup the prettier changes. |
||
}, | ||
fixable: null, | ||
ERROR_MESSAGE, | ||
}, | ||
|
||
create(context) { | ||
return { | ||
Property(node) { | ||
if (node.key.name === 'actions') { | ||
const props = node.value.properties; | ||
|
||
props.forEach((p) => { | ||
const body = p.value.body.body; | ||
if (p.value.async) { | ||
context.report({ | ||
node: p, | ||
message: ERROR_MESSAGE, | ||
}); | ||
} else if (body.length === 1 && utils.isReturnStatement(body[0])) { | ||
const retSt = body[0]; | ||
if (retSt.argument.type === 'CallExpression' && | ||
retSt.argument.callee.property.name === 'then') { | ||
context.report({ | ||
node: retSt, | ||
message: ERROR_MESSAGE, | ||
}); | ||
} | ||
} | ||
}); | ||
} else if (node.decorators) { | ||
if (node.decorators.find(d => d.expression.name === 'action')) { | ||
if (node.value.async) { | ||
context.report({ | ||
node, | ||
message: ERROR_MESSAGE | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
} | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
'use strict'; | ||
|
||
//------------------------------------------------------------------------------ | ||
// Requirements | ||
//------------------------------------------------------------------------------ | ||
|
||
const rule = require('../../../lib/rules/no-async-actions.js'); | ||
const RuleTester = require('eslint').RuleTester; | ||
|
||
const { ERROR_MESSAGE } = rule; | ||
//------------------------------------------------------------------------------ | ||
// Tests | ||
//------------------------------------------------------------------------------ | ||
|
||
|
||
const ruleTester = new RuleTester({}); | ||
|
||
ruleTester.run('no-async-actions', rule, { | ||
valid: [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need a valid example to ensure this rule does not trigger on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ^ still waiting on this rule to be limited to |
||
{ | ||
code: ` | ||
Component.extend({ | ||
actions: { | ||
handleClick() { | ||
// ... | ||
} | ||
} | ||
});`, | ||
} | ||
|
||
], | ||
|
||
invalid: [ | ||
{ | ||
code: `Component.extend({ | ||
actions: { | ||
async handleClick() { | ||
// ... | ||
} | ||
} | ||
});`, | ||
output: null, | ||
errors: [{ | ||
message: ERROR_MESSAGE, | ||
}] | ||
}, | ||
{ | ||
code: `Component.extend({ | ||
actions: { | ||
handleClick() { | ||
return something.then(() => { | ||
let hello = "world"; | ||
}); | ||
} | ||
} | ||
});`, | ||
output: null, | ||
errors: [{ | ||
message: ERROR_MESSAGE, | ||
}] | ||
}, | ||
{ | ||
code: `Component.extend({ | ||
@action | ||
async handleClick() { | ||
// ... | ||
} | ||
});`, | ||
parser: 'babel-eslint', | ||
output: null, | ||
errors: [{ | ||
message: ERROR_MESSAGE, | ||
}] | ||
}, | ||
{ | ||
code: `Component.extend({ | ||
@action | ||
handleClick() { | ||
return something.then(() => { | ||
let hello = "world"; | ||
}); | ||
} | ||
});`, | ||
parser: 'babel-eslint', | ||
output: null, | ||
errors: [{ | ||
message: ERROR_MESSAGE, | ||
}] | ||
}, | ||
|
||
] | ||
}); |
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.
Instead, could we throw a lint error only after an
await
AND access ofthis
?