Skip to content
This repository has been archived by the owner on Mar 25, 2021. It is now read-only.

prefer-conditional-expression: don't check else-if by default #2963

Merged
merged 2 commits into from
Aug 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 24 additions & 11 deletions src/rules/preferConditionalExpressionRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ import * as ts from "typescript";

import * as Lint from "../index";

const OPTION_CHECK_ELSE_IF = "check-else-if";

interface Options {
checkElseIf: boolean;
}

export class Rule extends Lint.Rules.AbstractRule {
/* tslint:disable:object-literal-sort-keys */
public static metadata: Lint.IRuleMetadata = {
Expand All @@ -28,9 +34,12 @@ export class Rule extends Lint.Rules.AbstractRule {
Recommends to use a conditional expression instead of assigning to the same thing in each branch of an if statement.`,
rationale: Lint.Utils.dedent`
This reduces duplication and can eliminate an unnecessary variable declaration.`,
optionsDescription: "Not configurable.",
options: null,
optionExamples: [true],
optionsDescription: `If \`${OPTION_CHECK_ELSE_IF}\` is specified, the rule also checks nested if-else-if statements.`,
options: {
type: "string",
enum: [OPTION_CHECK_ELSE_IF],
},
optionExamples: [true, [true, OPTION_CHECK_ELSE_IF]],
type: "functionality",
typescriptOnly: false,
};
Expand All @@ -41,19 +50,23 @@ export class Rule extends Lint.Rules.AbstractRule {
}

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, walk);
return this.applyWithFunction(sourceFile, walk, {
checkElseIf: this.ruleArguments.indexOf(OPTION_CHECK_ELSE_IF) !== -1,
});
}
}

function walk(ctx: Lint.WalkContext<void>): void {
const { sourceFile } = ctx;
function walk(ctx: Lint.WalkContext<Options>): void {
const { sourceFile, options: { checkElseIf } } = ctx;
return ts.forEachChild(sourceFile, function cb(node: ts.Node): void {
if (isIfStatement(node)) {
const assigned = detect(node, sourceFile);
const assigned = detect(node, sourceFile, checkElseIf);
if (assigned !== undefined) {
ctx.addFailureAtNode(
Lint.childOfKind(node, ts.SyntaxKind.IfKeyword)!,
node.getChildAt(0, sourceFile),
Rule.FAILURE_STRING(assigned.getText(sourceFile)));
}
if (assigned !== undefined || !checkElseIf) {
// Be careful not to fail again for the "else if"
ts.forEachChild(node.expression, cb);
ts.forEachChild(node.thenStatement, cb);
Expand All @@ -67,11 +80,11 @@ function walk(ctx: Lint.WalkContext<void>): void {
});
}

function detect({ thenStatement, elseStatement }: ts.IfStatement, sourceFile: ts.SourceFile): ts.Expression | undefined {
if (elseStatement === undefined) {
function detect({ thenStatement, elseStatement }: ts.IfStatement, sourceFile: ts.SourceFile, elseIf: boolean): ts.Expression | undefined {
if (elseStatement === undefined || !elseIf && elseStatement.kind === ts.SyntaxKind.IfStatement) {
return undefined;
}
const elze = isIfStatement(elseStatement) ? detect(elseStatement, sourceFile) : getAssigned(elseStatement, sourceFile);
const elze = isIfStatement(elseStatement) ? detect(elseStatement, sourceFile, elseIf) : getAssigned(elseStatement, sourceFile);
if (elze === undefined) {
return undefined;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
let x;
if (true) {
~~ [X]
~~ [err % ('x')]
x = 1;
} else {
x = 2;
}

if (true)
~~ [X]
~~ [err % ('x')]
x = "TRUE";
else if (false)
x = "FALSE";
Expand Down Expand Up @@ -51,5 +51,4 @@ if (true) {
foo(bar).baz = 1;
}

[X]: Use a conditional expression instead of assigning to 'x' in multiple places.
[err]: Use a conditional expression instead of assigning to '%s' in multiple places.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"prefer-conditional-expression": [true, "check-else-if"]
}
}
53 changes: 53 additions & 0 deletions test/rules/prefer-conditional-expression/default/test.ts.lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
let x;
if (true) {
~~ [err % ('x')]
x = 1;
} else {
x = 2;
}

if (true)
x = "TRUE";
else if (false)
x = "FALSE";
else
x = "FILE_NOT_FOUND";

// Must assign same variable
if (true) {
x = 1;
} else {
y = 2;
}

// All branches must be present
if (true) {
x = 1;
}

// Must not be a multi-statement block.
if (true) {
x = 1;
} else {
x = 2;
y = 3;
}

// Or even multi-line.
if (true)
x = [
1,
2
];
else
x = 3;

// Works for complex left hand side.
if (true) {
~~ [err % ('foo(bar).baz')]
foo(bar).baz = 0;
} else {
foo(bar).baz = 1;
}

[err]: Use a conditional expression instead of assigning to '%s' in multiple places.