Skip to content

Commit 9fa8d20

Browse files
addaleaxtargos
authored andcommitted
tools: add linting rule for async IIFEs
The result of an async IIFE should always be handled in our tests, typically by adding `.then(common.mustCall())` to verify that the async function actually finishes executing at some point. PR-URL: #34363 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Richard Lau <riclau@uk.ibm.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
1 parent 89ee6ab commit 9fa8d20

3 files changed

Lines changed: 90 additions & 0 deletions

File tree

‎test/.eslintrc.yaml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ rules:
5353
node-core/prefer-common-mustsucceed: error
5454
node-core/crypto-check: error
5555
node-core/eslint-check: error
56+
node-core/async-iife-no-unused-result: error
5657
node-core/inspector-check: error
5758
## common module is mandatory in tests
5859
node-core/required-modules:
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict';
2+
constcommon=require('../common');
3+
if(!common.hasCrypto)
4+
common.skip('missing crypto');
5+
common.skipIfEslintMissing();
6+
7+
constRuleTester=require('../../tools/node_modules/eslint').RuleTester;
8+
construle=require('../../tools/eslint-rules/async-iife-no-unused-result');
9+
10+
constmessage='The result of an immediately-invoked async function needs '+
11+
'to be used (e.g. with `.then(common.mustCall())`)';
12+
13+
consttester=newRuleTester({parserOptions: {ecmaVersion: 8}});
14+
tester.run('async-iife-no-unused-result',rule,{
15+
valid: [
16+
'(() => {})()',
17+
'(async () => {})',
18+
'(async () => {})().then()',
19+
'(async () => {})().catch()',
20+
'(function () {})()',
21+
'(async function () {})',
22+
'(async function () {})().then()',
23+
'(async function () {})().catch()',
24+
],
25+
invalid: [
26+
{
27+
code: '(async () => {})()',
28+
errors: [{ message }],
29+
output: '(async () => {})()',
30+
},
31+
{
32+
code: '(async function() {})()',
33+
errors: [{ message }],
34+
output: '(async function() {})()',
35+
},
36+
{
37+
code: "const common = require('../common');(async () => {})()",
38+
errors: [{ message }],
39+
output: "const common = require('../common');(async () => {})()"+
40+
'.then(common.mustCall())',
41+
},
42+
{
43+
code: "const common = require('../common');(async function() {})()",
44+
errors: [{ message }],
45+
output: "const common = require('../common');(async function() {})()"+
46+
'.then(common.mustCall())',
47+
},
48+
]
49+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use strict';
2+
const{ isCommonModule }=require('./rules-utils.js');
3+
4+
functionisAsyncIIFE(node){
5+
const{callee: { type, async }}=node;
6+
consttypes=['FunctionExpression','ArrowFunctionExpression'];
7+
returntypes.includes(type)&&async;
8+
}
9+
10+
constmessage=
11+
'The result of an immediately-invoked async function needs to be used '+
12+
'(e.g. with `.then(common.mustCall())`)';
13+
14+
module.exports={
15+
meta: {
16+
fixable: 'code'
17+
},
18+
create: function(context){
19+
lethasCommonModule=false;
20+
return{
21+
CallExpression: function(node){
22+
if(isCommonModule(node)&&node.parent.type==='VariableDeclarator'){
23+
hasCommonModule=true;
24+
}
25+
26+
if(!isAsyncIIFE(node))return;
27+
if(node.parent&&node.parent.type==='ExpressionStatement'){
28+
context.report({
29+
node,
30+
message,
31+
fix: (fixer)=>{
32+
if(hasCommonModule)
33+
returnfixer.insertTextAfter(node,'.then(common.mustCall())');
34+
}
35+
});
36+
}
37+
}
38+
};
39+
}
40+
};

0 commit comments

Comments
 (0)