routie dev init since i didn't adhere to any proper guidance up until now
This commit is contained in:
+108
@@ -0,0 +1,108 @@
|
||||
import {addParenthesizesToReturnOrThrowExpression, removeSpacesAfter} from './fix/index.js';
|
||||
import {isParenthesized, needsSemicolon, isOnSameLine} from './utils/index.js';
|
||||
|
||||
const MESSAGE_ID = 'no-unnecessary-await';
|
||||
const messages = {
|
||||
[MESSAGE_ID]: 'Do not `await` non-promise value.',
|
||||
};
|
||||
|
||||
function notPromise(node) {
|
||||
switch (node.type) {
|
||||
case 'ArrayExpression':
|
||||
case 'ArrowFunctionExpression':
|
||||
case 'AwaitExpression':
|
||||
case 'BinaryExpression':
|
||||
case 'ClassExpression':
|
||||
case 'FunctionExpression':
|
||||
case 'JSXElement':
|
||||
case 'JSXFragment':
|
||||
case 'Literal':
|
||||
case 'TemplateLiteral':
|
||||
case 'UnaryExpression':
|
||||
case 'UpdateExpression': {
|
||||
return true;
|
||||
}
|
||||
|
||||
case 'SequenceExpression': {
|
||||
return notPromise(node.expressions.at(-1));
|
||||
}
|
||||
|
||||
// No default
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @param {import('eslint').Rule.RuleContext} context */
|
||||
const create = context => {
|
||||
context.on('AwaitExpression', node => {
|
||||
if (
|
||||
// F#-style pipeline operator, `Promise.resolve() |> await`
|
||||
!node.argument
|
||||
|| !notPromise(node.argument)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {sourceCode} = context;
|
||||
const awaitToken = sourceCode.getFirstToken(node);
|
||||
const problem = {
|
||||
node,
|
||||
loc: sourceCode.getLoc(awaitToken),
|
||||
messageId: MESSAGE_ID,
|
||||
};
|
||||
|
||||
const valueNode = node.argument;
|
||||
if (
|
||||
// Removing `await` may change them to a declaration, if there is no `id` will cause SyntaxError
|
||||
valueNode.type === 'FunctionExpression'
|
||||
|| valueNode.type === 'ClassExpression'
|
||||
// `+await +1` -> `++1`
|
||||
|| (
|
||||
node.parent.type === 'UnaryExpression'
|
||||
&& valueNode.type === 'UnaryExpression'
|
||||
&& node.parent.operator === valueNode.operator
|
||||
)
|
||||
) {
|
||||
return problem;
|
||||
}
|
||||
|
||||
return Object.assign(problem, {
|
||||
/** @param {import('eslint').Rule.RuleFixer} fixer */
|
||||
* fix(fixer) {
|
||||
if (
|
||||
!isOnSameLine(awaitToken, valueNode, context)
|
||||
&& !isParenthesized(node, context)
|
||||
) {
|
||||
yield addParenthesizesToReturnOrThrowExpression(fixer, node.parent, context);
|
||||
}
|
||||
|
||||
yield fixer.remove(awaitToken);
|
||||
yield removeSpacesAfter(awaitToken, context, fixer);
|
||||
|
||||
const nextToken = sourceCode.getTokenAfter(awaitToken);
|
||||
const tokenBefore = sourceCode.getTokenBefore(awaitToken);
|
||||
if (needsSemicolon(tokenBefore, context, nextToken.value)) {
|
||||
yield fixer.insertTextBefore(nextToken, ';');
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
const config = {
|
||||
create,
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'Disallow awaiting non-promise values.',
|
||||
recommended: 'unopinionated',
|
||||
},
|
||||
fixable: 'code',
|
||||
|
||||
messages,
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
Reference in New Issue
Block a user