123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- 'use strict';
- 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',
- properties: ['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 '),
- },
- ],
- };
- },
- };
- }
- /** @type {import('eslint').Rule.RuleModule} */
- module.exports = {
- create,
- meta: {
- type: 'suggestion',
- docs: {
- description: 'Prefer top-level await over top-level promises and async function calls.',
- },
- hasSuggestions: true,
- messages,
- },
- };
|