Skip to content

Commit 2eaee9f

Browse files
authored
Merge pull request #16 from IPWright83/angular-excludes
Angular excludes
2 parents b196512 + a8fc651 commit 2eaee9f

File tree

7 files changed

+114
-66
lines changed

7 files changed

+114
-66
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "eslint-plugin-async-protect",
3-
"version": "1.1.1",
3+
"version": "2.0.0",
44
"description": "Protects against missing await keywords on async functions",
55
"keywords": [
66
"eslint",

src/async-await.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
*/
55
"use strict";
66

7+
const { ignoreAngularFunctionName } = require("./ignoreAngularFunctionName");
8+
79
module.exports = {
810
type: "suggestion",
911
meta: {
@@ -15,15 +17,14 @@ module.exports = {
1517
},
1618
},
1719

18-
create: function(context) {
20+
create: function (context) {
1921
const MISSING_AWAIT = "The call to '{{name}}' is missing an await";
2022
const EXTRA_AWAIT = "The call to '{{name}}' has an un-needed await";
2123

2224
const endsWithAsync = (name) => name.endsWith("Async");
2325

2426
const getName = (node) => {
25-
26-
switch(node.type) {
27+
switch (node.type) {
2728
case "CallExpression": {
2829
return getName(node.callee);
2930
}
@@ -36,7 +37,7 @@ module.exports = {
3637
}
3738

3839
return null;
39-
}
40+
};
4041

4142
// Has the call been awaited?
4243
const isAwaited = (node) => {
@@ -46,7 +47,7 @@ module.exports = {
4647

4748
const isReturned = (node) => {
4849
// Immediate parent is "return" so we are returning
49-
return node.parent.type === 'ReturnStatement';
50+
return node.parent.type === "ReturnStatement";
5051
};
5152

5253
const CallExpression = (node) => {
@@ -62,6 +63,11 @@ module.exports = {
6263
const calledWithReturn = isReturned(node);
6364
const nameEndsWithAsync = endsWithAsync(idNode.name);
6465

66+
// Skip the rule if this looks like an angular lifecycle event
67+
if (ignoreAngularFunctionName(idNode.name)) {
68+
return;
69+
}
70+
6571
if (nameEndsWithAsync && !calledWithAwait && !calledWithReturn) {
6672
context.report({
6773
node: node,
@@ -82,5 +88,5 @@ module.exports = {
8288
return {
8389
CallExpression,
8490
};
85-
}
91+
},
8692
};

src/async-suffix.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
*/
55
"use strict";
66

7+
const { ignoreAngularFunctionName } = require("./ignoreAngularFunctionName");
8+
79
//------------------------------------------------------------------------------
810
// Rule Definition
911
//------------------------------------------------------------------------------
@@ -19,7 +21,7 @@ module.exports = {
1921
},
2022
},
2123

22-
create: function(context) {
24+
create: function (context) {
2325
const MISSING_ASYNC = "Names should end with 'Async' for async functions. Rename '{{name}}' to '{{name}}Async'";
2426
const EXTRA_ASYNC = "Non async names should not end with 'Async'. Rename '{{name}}Async' to '{{name}}'";
2527

@@ -36,11 +38,15 @@ module.exports = {
3638
if (!identifier || !identifier.name) {
3739
return;
3840
}
39-
41+
4042
const nameEndsWithAsync = endsWithAsync(identifier.name);
4143

42-
if (isAsync && !nameEndsWithAsync) {
44+
// Skip the rule if this looks like an angular lifecycle event
45+
if (ignoreAngularFunctionName(identifier.name)) {
46+
return;
47+
}
4348

49+
if (isAsync && !nameEndsWithAsync) {
4450
context.report({
4551
node: identifier,
4652
message: MISSING_ASYNC,
@@ -64,10 +70,10 @@ module.exports = {
6470
// },
6571
});
6672
}
67-
}
73+
};
6874

6975
const VariableDeclarator = (node) => {
70-
const init = node.init
76+
const init = node.init;
7177
const identifier = node.id;
7278

7379
if (init && identifier) {
@@ -98,7 +104,7 @@ module.exports = {
98104
if (identifier && functionExpression && functionExpression.async !== undefined) {
99105
check(node, identifier, functionExpression.async);
100106
}
101-
}
107+
};
102108

103109
const Property = (node) => {
104110
// Only care for Methods
@@ -117,5 +123,5 @@ module.exports = {
117123
Property,
118124
AssignmentExpression,
119125
};
120-
}
126+
},
121127
};

src/ignoreAngularFunctionName.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// https://angular.io/guide/lifecycle-hooks#lifecycle-event-sequence
2+
const angularExcludes = [
3+
"ngOnChanges",
4+
"ngOnInit",
5+
"ngDoCheck",
6+
"ngAfterContentInit",
7+
"ngAfterContentChecked",
8+
"ngAfterViewInit",
9+
"ngAfterViewChecked",
10+
"ngOnDestroy",
11+
];
12+
13+
/**
14+
* Should the function be excluded, as it's one of the common
15+
* angular named functions?
16+
* @param {String} functionName The name of the function
17+
* @return {Boolean} True if the rules should be ignored for this function
18+
*/
19+
function ignoreAngularFunctionName(functionName) {
20+
return angularExcludes.includes(functionName);
21+
}
22+
23+
module.exports = {
24+
ignoreAngularFunctionName,
25+
};

tests/rules/async-await.js

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -21,92 +21,95 @@ RuleTester.setDefaultConfig({
2121
//------------------------------------------------------------------------------
2222
const ruleTester = new RuleTester();
2323

24-
const getError = (name, asyncMissing) => asyncMissing ?
25-
`The call to '${name}' is missing an await` :
26-
`The call to '${name}' has an un-needed await`;
24+
const getError = (name, asyncMissing) =>
25+
asyncMissing ? `The call to '${name}' is missing an await` : `The call to '${name}' has an un-needed await`;
2726

2827
ruleTester.run("async-await", rule, {
29-
3028
valid: [
3129
{
3230
code: `
3331
(iife = async function() {
3432
await fooAsync();
35-
})();`
33+
})();`,
3634
},
3735
{
3836
code: `
3937
(iife = async function() {
4038
return fooAsync();
41-
})();`
39+
})();`,
4240
},
4341
{
4442
code: `
4543
(iife = async function() {
4644
return await fooAsync();
47-
})();`
45+
})();`,
4846
},
4947
{
5048
code: `
5149
(iife = async function() {
5250
foo();
53-
})();`
51+
})();`,
5452
},
5553
{
5654
code: `
5755
(iife = async function() {
5856
const result = await fooAsync();
59-
})();`
57+
})();`,
6058
},
6159
{
6260
code: `
6361
(iife = async function() {
6462
const result = foo();
65-
})();`
63+
})();`,
6664
},
6765
{
6866
code: `
6967
(iife = async function() {
7068
(await fooAsync()).doSomething();
71-
})();`
69+
})();`,
7270
},
7371
{
7472
code: `
7573
(iife = async function() {
7674
foo().doSomething();
77-
})();`
75+
})();`,
7876
},
7977
{
8078
code: `
8179
(iife = async function() {
8280
const result = (await fooAsync()).x;
83-
})();`
81+
})();`,
8482
},
8583
{
8684
code: `
8785
(iife = async function() {
8886
const result = foo().x;
89-
})();`
87+
})();`,
9088
},
9189
{
92-
code: `
90+
code: `
9391
(iife = async function() {
9492
const result = (await fooAsync()).x.y.z().a.doSomething();
95-
})();`
93+
})();`,
9694
},
9795
{
98-
code: `
96+
code: `
9997
(iife = async function() {
10098
const result = await foo().x.y.z().a.doSomethingAsync();
101-
})();`
102-
99+
})();`,
103100
},
104101
{
105-
code: `
102+
code: `
106103
(iife = async function() {
107104
const result = (await foo().x.y.zAsync()).a.doSomething();
108-
})();`
109-
105+
})();`,
106+
},
107+
{
108+
code: `
109+
(iife = async function() {
110+
await ngOnInit();
111+
})();
112+
`,
110113
},
111114
],
112115

@@ -166,7 +169,7 @@ ruleTester.run("async-await", rule, {
166169
code: `
167170
(iife = async function() {
168171
fooAsync().doSomething();
169-
})();`, // accessing doSomething() too early / not async
172+
})();`, // accessing doSomething() too early / not async
170173
errors: [{ message: getError("fooAsync", true), type: "CallExpression" }],
171174
},
172175
{
@@ -212,20 +215,24 @@ ruleTester.run("async-await", rule, {
212215
(iife = async function() {
213216
const result = fooAsync().x();
214217
})();`,
215-
errors: [{
216-
message: getError("fooAsync", true),
217-
type: "CallExpression",
218-
}],
218+
errors: [
219+
{
220+
message: getError("fooAsync", true),
221+
type: "CallExpression",
222+
},
223+
],
219224
},
220225
{
221226
code: `
222227
(iife = async function() {
223228
const result = foo().xAsync();
224229
})();`,
225-
errors: [{
226-
message: getError("xAsync", true),
227-
type: "CallExpression",
228-
}],
230+
errors: [
231+
{
232+
message: getError("xAsync", true),
233+
type: "CallExpression",
234+
},
235+
],
229236
},
230237
{
231238
code: `
@@ -252,18 +259,17 @@ ruleTester.run("async-await", rule, {
252259
(iife = async function() {
253260
const result = foo().x.y.z().a.doSomethingAsync();
254261
})();`,
255-
errors: [{ message: getError("doSomethingAsync", true), type: "CallExpression" }]
256-
262+
errors: [{ message: getError("doSomethingAsync", true), type: "CallExpression" }],
257263
},
258264
{
259265
code: `
260266
(iife = async function() {
261267
const result = await fooAsync().x.y.z().a.doSomething();
262268
})();`,
263-
errors: [
269+
errors: [
264270
{ message: getError("doSomething", false), type: "CallExpression" },
265271
{ message: getError("fooAsync", true), type: "CallExpression" },
266272
],
267273
},
268-
]
274+
],
269275
});

0 commit comments

Comments
 (0)