Skip to content

Commit 075ef2c

Browse files
feat: add suggestion for no-return-await (#16637)
* refactor: extract error list into a function Suggestions will be different for different errors, so a constant object won't work anymore * feat: suggest removing await in no-return-await * Fix suggestion message Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com> * refactor: remove unused data * fix: only trim after await if there is a space * refactor: allow expecting no suggestion * refactor: move code for fixing into fix function * fix: do not suggest a fix if await and awaited expression are not on th same line * Simplify suggestion message Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com> * Simplify single-character access Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com> * Simplify removing a range Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com> * feat: suggest removing await when expression starts with ( * refactor: use awaitToken to determine await range * fix: use more performant way to identify tokens Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>
1 parent ba74253 commit 075ef2c

2 files changed

Lines changed: 168 additions & 32 deletions

File tree

lib/rules/no-return-await.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const astUtils = require("./utils/ast-utils");
1313
/** @type {import('../shared/types').Rule} */
1414
module.exports = {
1515
meta: {
16+
hasSuggestions: true,
1617
type: "suggestion",
1718

1819
docs: {
@@ -29,6 +30,7 @@ module.exports = {
2930
],
3031

3132
messages: {
33+
removeAwait: "Remove redundant `await`.",
3234
redundantUseOfAwait: "Redundant use of `await` on a return value."
3335
}
3436
},
@@ -44,7 +46,32 @@ module.exports = {
4446
context.report({
4547
node: context.getSourceCode().getFirstToken(node),
4648
loc: node.loc,
47-
messageId: "redundantUseOfAwait"
49+
messageId: "redundantUseOfAwait",
50+
suggest: [
51+
{
52+
messageId: "removeAwait",
53+
fix(fixer) {
54+
const sourceCode = context.getSourceCode();
55+
const [awaitToken, tokenAfterAwait] = sourceCode.getFirstTokens(node, 2);
56+
57+
const areAwaitAndAwaitedExpressionOnTheSameLine = awaitToken.loc.start.line === tokenAfterAwait.loc.start.line;
58+
59+
if (!areAwaitAndAwaitedExpressionOnTheSameLine) {
60+
return null;
61+
}
62+
63+
const [startOfAwait, endOfAwait] = awaitToken.range;
64+
65+
const characterAfterAwait = sourceCode.text[endOfAwait];
66+
const trimLength = characterAfterAwait === " " ? 1 : 0;
67+
68+
const range = [startOfAwait, endOfAwait + trimLength];
69+
70+
return fixer.removeRange(range);
71+
}
72+
}
73+
]
74+
4875
});
4976
}
5077

tests/lib/rules/no-return-await.js

Lines changed: 140 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,24 @@ const { RuleTester } = require("../../../lib/rule-tester");
1616
// Tests
1717
//------------------------------------------------------------------------------
1818

19-
// pending https://github.com/eslint/espree/issues/304, the type should be "Keyword"
20-
const errors = [{ messageId: "redundantUseOfAwait", type: "Identifier" }];
19+
/**
20+
* Creates the list of errors that should be found by this rule
21+
* @param {Object} options Options for creating errors
22+
* @param {string} options.suggestionOutput The suggested output
23+
* @returns {Array} the list of errors
24+
*/
25+
function createErrorList({ suggestionOutput: output } = {}) {
26+
27+
// pending https://github.com/eslint/espree/issues/304, the type should be "Keyword"
28+
return [{
29+
messageId: "redundantUseOfAwait",
30+
type: "Identifier",
31+
suggestions: output ? [{
32+
messageId: "removeAwait", output
33+
}] : []
34+
}];
35+
}
36+
2137

2238
const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2017 } });
2339

@@ -138,99 +154,103 @@ ruleTester.run("no-return-await", rule, {
138154
invalid: [
139155
{
140156
code: "\nasync function foo() {\n\treturn await bar();\n}\n",
141-
errors
157+
errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn bar();\n}\n" })
158+
},
159+
{
160+
code: "\nasync function foo() {\n\treturn await(bar());\n}\n",
161+
errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (bar());\n}\n" })
142162
},
143163
{
144164
code: "\nasync function foo() {\n\treturn (a, await bar());\n}\n",
145-
errors
165+
errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (a, bar());\n}\n" })
146166
},
147167
{
148168
code: "\nasync function foo() {\n\treturn (a, b, await bar());\n}\n",
149-
errors
169+
errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (a, b, bar());\n}\n" })
150170
},
151171
{
152172
code: "\nasync function foo() {\n\treturn (a && await bar());\n}\n",
153-
errors
173+
errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (a && bar());\n}\n" })
154174
},
155175
{
156176
code: "\nasync function foo() {\n\treturn (a && b && await bar());\n}\n",
157-
errors
177+
errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (a && b && bar());\n}\n" })
158178
},
159179
{
160180
code: "\nasync function foo() {\n\treturn (a || await bar());\n}\n",
161-
errors
181+
errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (a || bar());\n}\n" })
162182
},
163183
{
164184
code: "\nasync function foo() {\n\treturn (a, b, (c, d, await bar()));\n}\n",
165-
errors
185+
errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (a, b, (c, d, bar()));\n}\n" })
166186
},
167187
{
168188
code: "\nasync function foo() {\n\treturn (a, b, (c && await bar()));\n}\n",
169-
errors
189+
errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (a, b, (c && bar()));\n}\n" })
170190
},
171191
{
172192
code: "\nasync function foo() {\n\treturn (await baz(), b, await bar());\n}\n",
173-
errors
193+
errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (await baz(), b, bar());\n}\n" })
174194
},
175195
{
176196
code: "\nasync function foo() {\n\treturn (baz() ? await bar() : b);\n}\n",
177-
errors
197+
errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (baz() ? bar() : b);\n}\n" })
178198
},
179199
{
180200
code: "\nasync function foo() {\n\treturn (baz() ? a : await bar());\n}\n",
181-
errors
201+
errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (baz() ? a : bar());\n}\n" })
182202
},
183203
{
184204
code: "\nasync function foo() {\n\treturn (baz() ? (a, await bar()) : b);\n}\n",
185-
errors
205+
errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (baz() ? (a, bar()) : b);\n}\n" })
186206
},
187207
{
188208
code: "\nasync function foo() {\n\treturn (baz() ? a : (b, await bar()));\n}\n",
189-
errors
209+
errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (baz() ? a : (b, bar()));\n}\n" })
190210
},
191211
{
192212
code: "\nasync function foo() {\n\treturn (baz() ? (a && await bar()) : b);\n}\n",
193-
errors
213+
errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (baz() ? (a && bar()) : b);\n}\n" })
194214
},
195215
{
196216
code: "\nasync function foo() {\n\treturn (baz() ? a : (b && await bar()));\n}\n",
197-
errors
217+
errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (baz() ? a : (b && bar()));\n}\n" })
198218
},
199219
{
200220
code: "\nasync () => { return await bar(); }\n",
201-
errors
221+
errors: createErrorList({ suggestionOutput: "\nasync () => { return bar(); }\n" })
202222
},
203223
{
204224
code: "\nasync () => await bar()\n",
205-
errors
225+
errors: createErrorList({ suggestionOutput: "\nasync () => bar()\n" })
206226
},
207227
{
208228
code: "\nasync () => (a, b, await bar())\n",
209-
errors
229+
errors: createErrorList({ suggestionOutput: "\nasync () => (a, b, bar())\n" })
210230
},
211231
{
212232
code: "\nasync () => (a && await bar())\n",
213-
errors
233+
errors: createErrorList({ suggestionOutput: "\nasync () => (a && bar())\n" })
214234
},
215235
{
216236
code: "\nasync () => (baz() ? await bar() : b)\n",
217-
errors
237+
errors: createErrorList({ suggestionOutput: "\nasync () => (baz() ? bar() : b)\n" })
218238
},
219239
{
220240
code: "\nasync () => (baz() ? a : (b, await bar()))\n",
221-
errors
241+
errors: createErrorList({ suggestionOutput: "\nasync () => (baz() ? a : (b, bar()))\n" })
222242
},
223243
{
224244
code: "\nasync () => (baz() ? a : (b && await bar()))\n",
225-
errors
245+
errors: createErrorList({ suggestionOutput: "\nasync () => (baz() ? a : (b && bar()))\n" })
226246
},
227247
{
228248
code: "\nasync function foo() {\nif (a) {\n\t\tif (b) {\n\t\t\treturn await bar();\n\t\t}\n\t}\n}\n",
229-
errors
249+
errors: createErrorList({ suggestionOutput: "\nasync function foo() {\nif (a) {\n\t\tif (b) {\n\t\t\treturn bar();\n\t\t}\n\t}\n}\n" })
230250
},
231251
{
232252
code: "\nasync () => {\nif (a) {\n\t\tif (b) {\n\t\t\treturn await bar();\n\t\t}\n\t}\n}\n",
233-
errors
253+
errors: createErrorList({ suggestionOutput: "\nasync () => {\nif (a) {\n\t\tif (b) {\n\t\t\treturn bar();\n\t\t}\n\t}\n}\n" })
234254
},
235255
{
236256
code: `
@@ -241,7 +261,16 @@ ruleTester.run("no-return-await", rule, {
241261
}
242262
}
243263
`,
244-
errors
264+
errors: createErrorList({
265+
suggestionOutput: `
266+
async function foo() {
267+
try {}
268+
finally {
269+
return bar();
270+
}
271+
}
272+
`
273+
})
245274
},
246275
{
247276
code: `
@@ -252,7 +281,16 @@ ruleTester.run("no-return-await", rule, {
252281
}
253282
}
254283
`,
255-
errors
284+
errors: createErrorList({
285+
suggestionOutput: `
286+
async function foo() {
287+
try {}
288+
catch (e) {
289+
return bar();
290+
}
291+
}
292+
`
293+
})
256294
},
257295
{
258296
code: `
@@ -262,15 +300,29 @@ ruleTester.run("no-return-await", rule, {
262300
}
263301
} catch (e) {}
264302
`,
265-
errors
303+
errors: createErrorList({
304+
suggestionOutput: `
305+
try {
306+
async function foo() {
307+
return bar();
308+
}
309+
} catch (e) {}
310+
`
311+
})
266312
},
267313
{
268314
code: `
269315
try {
270316
async () => await bar();
271317
} catch (e) {}
272318
`,
273-
errors
319+
errors: createErrorList({
320+
suggestionOutput: `
321+
try {
322+
async () => bar();
323+
} catch (e) {}
324+
`
325+
})
274326
},
275327
{
276328
code: `
@@ -284,7 +336,64 @@ ruleTester.run("no-return-await", rule, {
284336
}
285337
}
286338
`,
287-
errors
339+
errors: createErrorList({
340+
suggestionOutput: `
341+
async function foo() {
342+
try {}
343+
catch (e) {
344+
try {}
345+
catch (e) {
346+
return bar();
347+
}
348+
}
349+
}
350+
`
351+
})
352+
},
353+
{
354+
code: `
355+
async function foo() {
356+
return await new Promise(resolve => {
357+
resolve(5);
358+
});
359+
}
360+
`,
361+
errors: createErrorList({
362+
suggestionOutput: `
363+
async function foo() {
364+
return new Promise(resolve => {
365+
resolve(5);
366+
});
367+
}
368+
`
369+
})
370+
},
371+
{
372+
code: `
373+
async () => {
374+
return await (
375+
foo()
376+
)
377+
};
378+
`,
379+
errors: createErrorList({
380+
suggestionOutput: `
381+
async () => {
382+
return (
383+
foo()
384+
)
385+
};
386+
`
387+
})
388+
},
389+
{
390+
code: `
391+
async function foo() {
392+
return await // Test
393+
5;
394+
}
395+
`,
396+
errors: createErrorList()
288397
}
289398
]
290399
});

0 commit comments

Comments
 (0)