mirror of https://github.com/nodejs/node.git
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: https://github.com/nodejs/node/pull/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>pull/34445/head
parent
2c4ebe0426
commit
77b68f9a29
|
@ -53,6 +53,7 @@ rules:
|
|||
node-core/prefer-common-mustnotcall: error
|
||||
node-core/crypto-check: error
|
||||
node-core/eslint-check: error
|
||||
node-core/async-iife-no-unused-result: error
|
||||
node-core/inspector-check: error
|
||||
## common module is mandatory in tests
|
||||
node-core/required-modules:
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
'use strict';
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
common.skipIfEslintMissing();
|
||||
|
||||
const RuleTester = require('../../tools/node_modules/eslint').RuleTester;
|
||||
const rule = require('../../tools/eslint-rules/async-iife-no-unused-result');
|
||||
|
||||
const message = 'The result of an immediately-invoked async function needs ' +
|
||||
'to be used (e.g. with `.then(common.mustCall())`)';
|
||||
|
||||
const tester = new RuleTester({ parserOptions: { ecmaVersion: 8 } });
|
||||
tester.run('async-iife-no-unused-result', rule, {
|
||||
valid: [
|
||||
'(() => {})()',
|
||||
'(async () => {})',
|
||||
'(async () => {})().then()',
|
||||
'(async () => {})().catch()',
|
||||
'(function () {})()',
|
||||
'(async function () {})',
|
||||
'(async function () {})().then()',
|
||||
'(async function () {})().catch()',
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: '(async () => {})()',
|
||||
errors: [{ message }],
|
||||
output: '(async () => {})()',
|
||||
},
|
||||
{
|
||||
code: '(async function() {})()',
|
||||
errors: [{ message }],
|
||||
output: '(async function() {})()',
|
||||
},
|
||||
{
|
||||
code: "const common = require('../common');(async () => {})()",
|
||||
errors: [{ message }],
|
||||
output: "const common = require('../common');(async () => {})()" +
|
||||
'.then(common.mustCall())',
|
||||
},
|
||||
{
|
||||
code: "const common = require('../common');(async function() {})()",
|
||||
errors: [{ message }],
|
||||
output: "const common = require('../common');(async function() {})()" +
|
||||
'.then(common.mustCall())',
|
||||
},
|
||||
]
|
||||
});
|
|
@ -0,0 +1,37 @@
|
|||
'use strict';
|
||||
const { isCommonModule } = require('./rules-utils.js');
|
||||
|
||||
function isAsyncIIFE(node) {
|
||||
const { callee: { type, async } } = node;
|
||||
const types = ['FunctionExpression', 'ArrowFunctionExpression'];
|
||||
return types.includes(type) && async;
|
||||
}
|
||||
|
||||
const message =
|
||||
'The result of an immediately-invoked async function needs to be used ' +
|
||||
'(e.g. with `.then(common.mustCall())`)';
|
||||
|
||||
module.exports = {
|
||||
create: function(context) {
|
||||
let hasCommonModule = false;
|
||||
return {
|
||||
CallExpression: function(node) {
|
||||
if (isCommonModule(node) && node.parent.type === 'VariableDeclarator') {
|
||||
hasCommonModule = true;
|
||||
}
|
||||
|
||||
if (!isAsyncIIFE(node)) return;
|
||||
if (node.parent && node.parent.type === 'ExpressionStatement') {
|
||||
context.report({
|
||||
node,
|
||||
message,
|
||||
fix: (fixer) => {
|
||||
if (hasCommonModule)
|
||||
return fixer.insertTextAfter(node, '.then(common.mustCall())');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue