Skip to content

Commit

Permalink
[[FEAT]] Implement noreturnawait
Browse files Browse the repository at this point in the history
  • Loading branch information
jugglinmike authored and rwaldron committed Jan 29, 2019
1 parent bc4ae9f commit 70ab03d
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 4 deletions.
16 changes: 14 additions & 2 deletions src/jshint.js
Original file line number Diff line number Diff line change
Expand Up @@ -2135,7 +2135,12 @@ var JSHINT = (function() {
state.funct["(scope)"].validateParams(true);
}

expression(10, context);
var expr = expression(10, context);

if (state.option.noreturnawait && context & prodParams.async &&
expr.identifier && expr.value === "await") {
warning("W146", expr);
}

if (state.option.strict && state.funct["(context)"]["(global)"]) {
if (!state.isStrict()) {
Expand Down Expand Up @@ -3641,6 +3646,7 @@ var JSHINT = (function() {
}

context &= ~prodParams.noin;
context &= ~prodParams.tryClause;

if (isAsync) {
context |= prodParams.async;
Expand Down Expand Up @@ -4682,7 +4688,7 @@ var JSHINT = (function() {
state.funct["(scope)"].unstack();
}

block(context, true);
block(context | prodParams.tryClause, true);

while (state.tokens.next.id === "catch") {
increaseComplexityCount();
Expand Down Expand Up @@ -5169,6 +5175,12 @@ var JSHINT = (function() {
!this.first.paren && !state.option.boss) {
warningAt("W093", this.first.line, this.first.character);
}

if (state.option.noreturnawait && context & prodParams.async &&
!(context & prodParams.tryClause) &&
this.first.identifier && this.first.value === "await") {
warning("W146", this.first);
}
}
} else {
if (state.tokens.next.type === "(punctuator)" &&
Expand Down
3 changes: 2 additions & 1 deletion src/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,8 @@ var warnings = {
W143: "Assignment to properties of a mapped arguments object may cause " +
"unexpected changes to formal parameters.",
W144: "'{a}' is a non-standard language feature. Enable it using the '{b}' unstable option.",
W145: "Superfluous 'case' clause."
W145: "Superfluous 'case' clause.",
W146: "Unnecessary `await` expression."
};

var info = {
Expand Down
13 changes: 13 additions & 0 deletions src/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,19 @@ exports.bool = {
*/
nonew : true,


/**
* Async functions resolve on their return value. In most cases, this makes
* returning the result of an AwaitExpression (which is itself a Promise
* instance) unnecessary. For clarity, it's often preferable to return the
* result of the asynchronous operation directly. The notable exception is
* within the `try` clause of a TryStatement--for more, see "await vs
* return vs return await":
*
* https://jakearchibald.com/2017/await-vs-return-vs-return-await/
*/
noreturnawait: true,

/**
* This option prohibits the use of explicitly undeclared variables. This
* option is very useful for spotting leaking and mistyped variables.
Expand Down
8 changes: 7 additions & 1 deletion src/prod-params.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,11 @@ module.exports = {

preAsync: 8,

async: 16
async: 16,

/**
* Enabled when any exception thrown by the expression will be caught by a
* TryStatement.
*/
tryClause: 32
};
58 changes: 58 additions & 0 deletions tests/unit/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -4369,3 +4369,61 @@ exports.leanswitch = function (test) {

test.done();
};

exports.noreturnawait = function(test) {
var code = [
"void function() {",
" return await;",
"};",
"void function() {",
" return await(null);",
"};",
"void async function() {",
" return null;",
"};",
"void async function() {",
" return 'await';",
"};",
"void async function() {",
" try {",
" return await null;",
" } catch (err) {}",
"};",
"void async function() {",
" try {",
" void async function() {",
" return await null;",
" };",
" } catch (err) {}",
"};",
"void async function() {",
" return await null;",
"};"
];

TestRun(test, "function expression (disabled)")
.test(code, { esversion: 8 });

TestRun(test, "function expression (enabled)")
.addError(21, 14, "Unnecessary `await` expression.")
.addError(26, 10, "Unnecessary `await` expression.")
.test(code, { esversion: 8, noreturnawait: true });

code = [
"void (() => await);",
"void (() => await(null));",
"void (async () => null);",
"void (async () => 'await');",
"void (async () => await null);",
"void (async () => { await null; });"
];

TestRun(test, "arrow function (disabled)")
.test(code, { esversion: 8 });

TestRun(test, "arrow function (enabled)")
.addError(5, 19, "Unnecessary `await` expression.")
.test(code, { esversion: 8, noreturnawait: true });

test.done();
};

0 comments on commit 70ab03d

Please sign in to comment.