Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix(eslint-plugin): [no-unused-expressions] handle ternary and short-…
…circuit options (#2194)
  • Loading branch information
yeonjuan committed Jun 9, 2020
1 parent 5d68129 commit ee9f100
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 17 deletions.
38 changes: 30 additions & 8 deletions packages/eslint-plugin/src/rules/no-unused-expressions.ts
@@ -1,4 +1,7 @@
import { AST_NODE_TYPES } from '@typescript-eslint/experimental-utils';
import {
AST_NODE_TYPES,
TSESTree,
} from '@typescript-eslint/experimental-utils';
import baseRule from 'eslint/lib/rules/no-unused-expressions';
import * as util from '../util';

Expand All @@ -18,17 +21,36 @@ export default util.createRule<Options, MessageIds>({
schema: baseRule.meta.schema,
messages: baseRule.meta.messages,
},
defaultOptions: [],
create(context) {
defaultOptions: [
{
allowShortCircuit: false,
allowTernary: false,
allowTaggedTemplates: false,
},
],
create(context, options) {
const rules = baseRule.create(context);
const { allowShortCircuit = false, allowTernary = false } = options[0];

function isValidExpression(node: TSESTree.Node): boolean {
if (allowShortCircuit && node.type === AST_NODE_TYPES.LogicalExpression) {
return isValidExpression(node.right);
}
if (allowTernary && node.type === AST_NODE_TYPES.ConditionalExpression) {
return (
isValidExpression(node.alternate) &&
isValidExpression(node.consequent)
);
}
return (
node.type === AST_NODE_TYPES.OptionalCallExpression ||
node.type === AST_NODE_TYPES.ImportExpression
);
}

return {
ExpressionStatement(node): void {
if (
node.directive ||
node.expression.type === AST_NODE_TYPES.OptionalCallExpression ||
node.expression.type === AST_NODE_TYPES.ImportExpression
) {
if (node.directive || isValidExpression(node.expression)) {
return;
}

Expand Down
36 changes: 36 additions & 0 deletions packages/eslint-plugin/tests/rules/no-unused-expressions.test.ts
Expand Up @@ -71,6 +71,18 @@ ruleTester.run('no-unused-expressions', rule, {
`
import('./foo').then(() => {});
`,
{
code: 'foo && foo?.();',
options: [{ allowShortCircuit: true }],
},
{
code: "foo && import('./foo');",
options: [{ allowShortCircuit: true }],
},
{
code: "foo ? import('./foo') : import('./bar');",
options: [{ allowTernary: true }],
},
],
invalid: [
{
Expand Down Expand Up @@ -259,5 +271,29 @@ function foo() {
},
]),
},
{
code: 'foo && foo?.bar;',
options: [{ allowShortCircuit: true }],
errors: error([
{
line: 1,
endLine: 1,
column: 1,
endColumn: 17,
},
]),
},
{
code: 'foo ? foo?.bar : bar.baz;',
options: [{ allowTernary: true }],
errors: error([
{
line: 1,
endLine: 1,
column: 1,
endColumn: 26,
},
]),
},
],
});
16 changes: 7 additions & 9 deletions packages/eslint-plugin/typings/eslint-rules.d.ts
Expand Up @@ -411,15 +411,13 @@ declare module 'eslint/lib/rules/no-unused-expressions' {

const rule: TSESLint.RuleModule<
'expected',
(
| 'all'
| 'local'
| {
allowShortCircuit?: boolean;
allowTernary?: boolean;
allowTaggedTemplates?: boolean;
}
)[],
[
{
allowShortCircuit?: boolean;
allowTernary?: boolean;
allowTaggedTemplates?: boolean;
},
],
{
ExpressionStatement(node: TSESTree.ExpressionStatement): void;
}
Expand Down

0 comments on commit ee9f100

Please sign in to comment.