eslint-plugin-unicorn
Version:
Various awesome ESLint rules
102 lines (95 loc) • 2.49 kB
JavaScript
;
const {findVariable, getFunctionHeadLocation} = require('eslint-utils');
const {matches, memberExpressionSelector} = require('./selectors/index.js');
const ERROR_PROMISE = 'promise';
const ERROR_IIFE = 'iife';
const ERROR_IDENTIFIER = 'identifier';
const SUGGESTION_ADD_AWAIT = 'add-await';
const messages = {
[ERROR_PROMISE]: 'Prefer top-level await over using a promise chain.',
[ERROR_IIFE]: 'Prefer top-level await over an async IIFE.',
[ERROR_IDENTIFIER]: 'Prefer top-level await over an async function `{{name}}` call.',
[SUGGESTION_ADD_AWAIT]: 'Insert `await`.'
};
const topLevelCallExpression = 'Program > ExpressionStatement > CallExpression[optional!=true].expression';
const iife = [
topLevelCallExpression,
matches([
'[callee.type="FunctionExpression"]',
'[callee.type="ArrowFunctionExpression"]'
]),
'[callee.async!=false]',
'[callee.generator!=true]'
].join('');
const promise = [
topLevelCallExpression,
memberExpressionSelector({
path: 'callee',
names: ['then', 'catch', 'finally']
})
].join('');
const identifier = [
topLevelCallExpression,
'[callee.type="Identifier"]'
].join('');
/** @param {import('eslint').Rule.RuleContext} context */
function create(context) {
return {
[promise](node) {
return {
node: node.callee.property,
messageId: ERROR_PROMISE
};
},
[iife](node) {
return {
node,
loc: getFunctionHeadLocation(node.callee, context.getSourceCode()),
messageId: ERROR_IIFE
};
},
[identifier](node) {
const variable = findVariable(context.getScope(), node.callee);
if (!variable || variable.defs.length !== 1) {
return;
}
const [definition] = variable.defs;
const value = definition.type === 'Variable' && definition.kind === 'const' ?
definition.node.init :
definition.node;
if (
!(
(
value.type === 'ArrowFunctionExpression' ||
value.type === 'FunctionExpression' ||
value.type === 'FunctionDeclaration'
) && !value.generator && value.async
)
) {
return;
}
return {
node,
messageId: ERROR_IDENTIFIER,
data: {name: node.callee.name},
suggest: [
{
messageId: SUGGESTION_ADD_AWAIT,
fix: fixer => fixer.insertTextBefore(node, 'await ')
}
]
};
}
};
}
module.exports = {
create,
meta: {
type: 'suggestion',
docs: {
description: 'Prefer top-level await over top-level promises and async function calls.'
},
messages,
hasSuggestions: true
}
};