Skip to content

Commit

Permalink
update no-unused-expression
Browse files Browse the repository at this point in the history
  • Loading branch information
mysticatea committed Jun 17, 2020
1 parent 6c6bd95 commit 6c00e33
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 23 deletions.
80 changes: 57 additions & 23 deletions lib/rules/no-unused-expressions.js
Expand Up @@ -8,6 +8,22 @@
// Rule Definition
//------------------------------------------------------------------------------

/**
* Returns `true`.
* @returns {boolean} `true`.
*/
function alwaysTrue() {
return true;
}

/**
* Returns `false`.
* @returns {boolean} `false`.
*/
function alwaysFalse() {
return false;
}

module.exports = {
meta: {
type: "suggestion",
Expand Down Expand Up @@ -101,40 +117,58 @@ module.exports = {
}

/**
* Determines whether or not a given node is a valid expression. Recurses on short circuit eval and ternary nodes if enabled by flags.
* @param {ASTNode} node any node
* @returns {boolean} whether the given node is a valid expression
* The member functions return `true` if the type has no side-effects.
* Unknown nodes are handled as `false`, then this rule ignores those.
*/
function isValidExpression(node) {
if (allowTernary) {

// Recursive check for ternary and logical expressions
if (node.type === "ConditionalExpression") {
return isValidExpression(node.consequent) && isValidExpression(node.alternate);
const Checker = {
__proto__: null,

isDisallowed(node) {
return (Checker[node.type] || alwaysFalse)(node);
},

ArrayExpression: alwaysTrue,
ArrowFunctionExpression: alwaysTrue,
BinaryExpression: alwaysTrue,
ChainExpression(node) {
return Checker.isDisallowed(node.expression);
},
ClassExpression: alwaysTrue,
ConditionalExpression(node) {
if (allowTernary) {
return Checker.isDisallowed(node.consequent) || Checker.isDisallowed(node.alternate);
}
}

if (allowShortCircuit) {
if (node.type === "LogicalExpression") {
return isValidExpression(node.right);
return true;
},
FunctionExpression: alwaysTrue,
Identifier: alwaysTrue,
Literal: alwaysTrue,
LogicalExpression(node) {
if (allowShortCircuit) {
return Checker.isDisallowed(node.right);
}
}

if (allowTaggedTemplates && node.type === "TaggedTemplateExpression") {
return true;
},
MemberExpression: alwaysTrue,
MetaProperty: alwaysTrue,
ObjectExpression: alwaysTrue,
SequenceExpression: alwaysTrue,
TaggedTemplateExpression() {
return !allowTaggedTemplates;
},
TemplateLiteral: alwaysTrue,
ThisExpression: alwaysTrue,
UnaryExpression(node) {
return node.operator !== "void" && node.operator !== "delete";
}

return /^(?:Assignment|Call|New|Update|Yield|Await|Import)Expression$/u.test(node.type) ||
(node.type === "UnaryExpression" && ["delete", "void"].indexOf(node.operator) >= 0);
}
};

return {
ExpressionStatement(node) {
if (!isValidExpression(node.expression) && !isDirective(node, context.getAncestors())) {
if (Checker.isDisallowed(node.expression) && !isDirective(node, context.getAncestors())) {
context.report({ node, messageId: "unusedExpression" });
}
}
};

}
};
25 changes: 25 additions & 0 deletions tests/lib/rules/no-unused-expressions.js
Expand Up @@ -74,6 +74,14 @@ ruleTester.run("no-unused-expressions", rule, {
{
code: "import(\"foo\")",
parserOptions: { ecmaVersion: 11 }
},
{
code: "func?.(\"foo\")",
parserOptions: { ecmaVersion: 11 }
},
{
code: "obj?.foo(\"bar\")",
parserOptions: { ecmaVersion: 11 }
}
],
invalid: [
Expand Down Expand Up @@ -127,6 +135,23 @@ ruleTester.run("no-unused-expressions", rule, {
options: [{ allowTaggedTemplates: false }],
parserOptions: { ecmaVersion: 6 },
errors: [{ messageId: "unusedExpression" }]
},

// Optional chaining
{
code: "obj?.foo",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unusedExpression", type: "ExpressionStatement" }]
},
{
code: "obj?.foo.bar",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unusedExpression", type: "ExpressionStatement" }]
},
{
code: "obj?.foo().bar",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unusedExpression", type: "ExpressionStatement" }]
}
]
});

0 comments on commit 6c00e33

Please sign in to comment.