Skip to content

Commit

Permalink
fix(eslint-plugin): [req-await] crash on nonasync promise return (#1228)
Browse files Browse the repository at this point in the history
  • Loading branch information
bradzacher committed Nov 19, 2019
1 parent dd9f58c commit 56c00b3
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 112 deletions.
19 changes: 8 additions & 11 deletions packages/eslint-plugin/src/rules/require-await.ts
Expand Up @@ -42,29 +42,26 @@ export default util.createRule<Options, MessageIds>({
}

return {
'FunctionDeclaration[async = true]': rules.FunctionDeclaration,
'FunctionExpression[async = true]': rules.FunctionExpression,
FunctionDeclaration: rules.FunctionDeclaration,
FunctionExpression: rules.FunctionExpression,
ArrowFunctionExpression: rules.ArrowFunctionExpression,
'ArrowFunctionExpression[async = true]'(
node: TSESTree.ArrowFunctionExpression,
): void {
rules.ArrowFunctionExpression(node);

// If body type is not BlockStatment, we need to check the return type here
if (node.body.type !== AST_NODE_TYPES.BlockStatement) {
const expression = parserServices.esTreeNodeToTSNodeMap.get(
node.body,
);
if (expression && isThenableType(expression)) {
// tell the base rule to mark the scope as having an await so it ignores it
rules.AwaitExpression(node as never);
rules.AwaitExpression();
}
}
},
'FunctionDeclaration[async = true]:exit':
rules['FunctionDeclaration:exit'],
'FunctionExpression[async = true]:exit': rules['FunctionExpression:exit'],
'ArrowFunctionExpression[async = true]:exit':
rules['ArrowFunctionExpression:exit'],
'FunctionDeclaration:exit': rules['FunctionDeclaration:exit'],
'FunctionExpression:exit': rules['FunctionExpression:exit'],
'ArrowFunctionExpression:exit': rules['ArrowFunctionExpression:exit'],
AwaitExpression: rules.AwaitExpression,
ForOfStatement: rules.ForOfStatement,

Expand All @@ -74,7 +71,7 @@ export default util.createRule<Options, MessageIds>({
>(node);
if (expression && isThenableType(expression)) {
// tell the base rule to mark the scope as having an await so it ignores it
rules.AwaitExpression(node as never);
rules.AwaitExpression();
}
},
};
Expand Down
181 changes: 81 additions & 100 deletions packages/eslint-plugin/tests/rules/require-await.test.ts
Expand Up @@ -28,106 +28,87 @@ const noAwaitAsyncFunctionExpression: any = {

ruleTester.run('require-await', rule, {
valid: [
{
// Non-async function declaration
code: `function numberOne(): number {
return 1;
}`,
},
{
// Non-async function expression
code: `const numberOne = function(): number {
return 1;
}`,
},
{
// Non-async arrow function expression (concise-body)
code: `const numberOne = (): number => 1;`,
},
{
// Non-async arrow function expression (block-body)
code: `const numberOne = (): number => {
return 1;
};`,
},
{
// Async function declaration with await
code: `async function numberOne(): Promise<number> {
return await 1;
}`,
},
{
// Async function expression with await
code: `const numberOne = async function(): Promise<number> {
return await 1;
}`,
},
{
// Async arrow function expression with await (concise-body)
code: `const numberOne = async (): Promise<number> => await 1;`,
},
{
// Async arrow function expression with await (block-body)
code: `const numberOne = async (): Promise<number> => {
return await 1;
};`,
},
{
// Async function declaration with promise return
code: `async function numberOne(): Promise<number> {
return Promise.resolve(1);
}`,
},
{
// Async function expression with promise return
code: `const numberOne = async function(): Promise<number> {
return Promise.resolve(1);
}`,
},
{
// Async arrow function with promise return (concise-body)
code: `const numberOne = async (): Promise<number> => Promise.resolve(1);`,
},
{
// Async arrow function with promise return (block-body)
code: `const numberOne = async (): Promise<number> => {
return Promise.resolve(1);
};`,
},
{
// Async function declaration with async function return
code: `async function numberOne(): Promise<number> {
return getAsyncNumber(1);
}
async function getAsyncNumber(x: number): Promise<number> {
return Promise.resolve(x);
}`,
},
{
// Async function expression with async function return
code: `const numberOne = async function(): Promise<number> {
return getAsyncNumber(1);
}
const getAsyncNumber = async function(x: number): Promise<number> {
return Promise.resolve(x);
}`,
},
{
// Async arrow function with async function return (concise-body)
code: `const numberOne = async (): Promise<number> => getAsyncNumber(1);
const getAsyncNumber = async function(x: number): Promise<number> {
return Promise.resolve(x);
}`,
},
{
// Async arrow function with async function return (block-body)
code: `const numberOne = async (): Promise<number> => {
return getAsyncNumber(1);
};
const getAsyncNumber = async function(x: number): Promise<number> {
return Promise.resolve(x);
}`,
},
// Non-async function declaration
`function numberOne(): number {
return 1;
}`,
// Non-async function expression
`const numberOne = function(): number {
return 1;
}`,
// Non-async arrow function expression (concise-body)
`const numberOne = (): number => 1;`,
// Non-async arrow function expression (block-body)
`const numberOne = (): number => {
return 1;
};`,
// Non-async function that returns a promise
// https://github.com/typescript-eslint/typescript-eslint/issues/1226
`
function delay() {
return Promise.resolve();
}
`,
`
const delay = () => {
return Promise.resolve();
}
`,
`const delay = () => Promise.resolve();`,
// Async function declaration with await
`async function numberOne(): Promise<number> {
return await 1;
}`,
// Async function expression with await
`const numberOne = async function(): Promise<number> {
return await 1;
}`,
// Async arrow function expression with await (concise-body)
`const numberOne = async (): Promise<number> => await 1;`,
// Async arrow function expression with await (block-body)
`const numberOne = async (): Promise<number> => {
return await 1;
};`,
// Async function declaration with promise return
`async function numberOne(): Promise<number> {
return Promise.resolve(1);
}`,
// Async function expression with promise return
`const numberOne = async function(): Promise<number> {
return Promise.resolve(1);
}`,
// Async arrow function with promise return (concise-body)
`const numberOne = async (): Promise<number> => Promise.resolve(1);`,
// Async arrow function with promise return (block-body)
`const numberOne = async (): Promise<number> => {
return Promise.resolve(1);
};`,
// Async function declaration with async function return
`async function numberOne(): Promise<number> {
return getAsyncNumber(1);
}
async function getAsyncNumber(x: number): Promise<number> {
return Promise.resolve(x);
}`,
// Async function expression with async function return
`const numberOne = async function(): Promise<number> {
return getAsyncNumber(1);
}
const getAsyncNumber = async function(x: number): Promise<number> {
return Promise.resolve(x);
}`,
// Async arrow function with async function return (concise-body)
`const numberOne = async (): Promise<number> => getAsyncNumber(1);
const getAsyncNumber = async function(x: number): Promise<number> {
return Promise.resolve(x);
}`,
// Async arrow function with async function return (block-body)
`const numberOne = async (): Promise<number> => {
return getAsyncNumber(1);
};
const getAsyncNumber = async function(x: number): Promise<number> {
return Promise.resolve(x);
}`,
// https://github.com/typescript-eslint/typescript-eslint/issues/1188
`
async function testFunction(): Promise<void> {
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin/typings/eslint-rules.d.ts
Expand Up @@ -451,7 +451,7 @@ declare module 'eslint/lib/rules/require-await' {
node: TSESTree.ArrowFunctionExpression,
): void;
ReturnStatement(node: TSESTree.ReturnStatement): void;
AwaitExpression(node: TSESTree.AwaitExpression): void;
AwaitExpression(): void;
ForOfStatement(node: TSESTree.ForOfStatement): void;
}
>;
Expand Down

0 comments on commit 56c00b3

Please sign in to comment.