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

Commit 2dd17e2

Browse files
andy-hansonnchen63
authored andcommitted
Lint for strict-boolean-expressions (#2408)
1 parent 0da23e4 commit 2dd17e2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+236
-220
lines changed

src/configuration.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,9 @@ export function findConfigurationPath(suppliedConfigFilePath: string | null, inp
145145
* This is case-insensitive, so it can find 'TsLiNt.JsOn' when searching for 'tslint.json'.
146146
*/
147147
function findup(filename: string, directory: string): string | undefined {
148-
while (true) {
148+
while (true) { // tslint:disable-line strict-boolean-expressions
149149
const res = findFile(directory);
150-
if (res) {
150+
if (res !== undefined) {
151151
return res;
152152
}
153153

@@ -236,7 +236,7 @@ function resolveConfigurationPath(filePath: string, relativeTo?: string) {
236236
}
237237
}
238238

239-
const basedir = relativeTo || process.cwd();
239+
const basedir = relativeTo !== undefined ? relativeTo : process.cwd();
240240
try {
241241
return resolve.sync(filePath, { basedir });
242242
} catch (err) {
@@ -261,7 +261,7 @@ export function extendConfigurationFile(targetConfig: IConfigurationFile,
261261
return combinedProperty as T;
262262

263263
function add(property: T | undefined): void {
264-
if (property) {
264+
if (property !== undefined) {
265265
for (const name in property) {
266266
if (hasOwnProperty(property, name)) {
267267
combinedProperty[name] = property[name];
@@ -321,7 +321,7 @@ function getHomeDir(): string | undefined {
321321
// returns the absolute path (contrary to what the name implies)
322322
export function getRelativePath(directory?: string | null, relativeTo?: string) {
323323
if (directory != null) {
324-
const basePath = relativeTo || process.cwd();
324+
const basePath = relativeTo !== undefined ? relativeTo : process.cwd();
325325
return path.resolve(basePath, directory);
326326
}
327327
return undefined;
@@ -371,7 +371,7 @@ function parseRuleOptions(ruleConfigValue: RawRuleConfig, rawDefaultRuleSeverity
371371
let ruleArguments: any[] | undefined;
372372
let defaultRuleSeverity: RuleSeverity = "error";
373373

374-
if (rawDefaultRuleSeverity) {
374+
if (rawDefaultRuleSeverity !== undefined) {
375375
switch (rawDefaultRuleSeverity.toLowerCase()) {
376376
case "warn":
377377
case "warning":
@@ -402,7 +402,7 @@ function parseRuleOptions(ruleConfigValue: RawRuleConfig, rawDefaultRuleSeverity
402402
ruleArguments = [];
403403
ruleSeverity = ruleConfigValue === true ? defaultRuleSeverity : "off";
404404
} else if (typeof ruleConfigValue === "object") {
405-
if (ruleConfigValue.severity) {
405+
if (ruleConfigValue.severity !== undefined) {
406406
switch (ruleConfigValue.severity.toLowerCase()) {
407407
case "default":
408408
ruleSeverity = defaultRuleSeverity;
@@ -460,14 +460,14 @@ export function parseConfigFile(configFile: RawConfigFile, configFileDir?: strin
460460
return {
461461
extends: arrayify(configFile.extends),
462462
jsRules: parseRules(configFile.jsRules),
463-
linterOptions: configFile.linterOptions || {},
463+
linterOptions: configFile.linterOptions !== undefined ? configFile.linterOptions : {},
464464
rules: parseRules(configFile.rules),
465465
rulesDirectory: getRulesDirectories(configFile.rulesDirectory, configFileDir),
466466
};
467467

468468
function parseRules(config: RawRulesConfig | undefined): Map<string, Partial<IOptions>> {
469469
const map = new Map<string, Partial<IOptions>>();
470-
if (config) {
470+
if (config !== undefined) {
471471
for (const ruleName in config) {
472472
if (hasOwnProperty(config, ruleName)) {
473473
map.set(ruleName, parseRuleOptions(config[ruleName], configFile.defaultSeverity));
@@ -483,12 +483,12 @@ export function parseConfigFile(configFile: RawConfigFile, configFileDir?: strin
483483
*/
484484
export function convertRuleOptions(ruleConfiguration: Map<string, Partial<IOptions>>): IOptions[] {
485485
const output: IOptions[] = [];
486-
ruleConfiguration.forEach((partialOptions, ruleName) => {
486+
ruleConfiguration.forEach(({ ruleArguments, ruleSeverity }, ruleName) => {
487487
const options: IOptions = {
488488
disabledIntervals: [], // deprecated, so just provide an empty array.
489-
ruleArguments: partialOptions.ruleArguments || [],
489+
ruleArguments: ruleArguments != null ? ruleArguments : [],
490490
ruleName,
491-
ruleSeverity: partialOptions.ruleSeverity || "error",
491+
ruleSeverity: ruleSeverity != null ? ruleSeverity : "error",
492492
};
493493
output.push(options);
494494
});

src/enableDisableRules.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import * as ts from "typescript";
2222
import { RuleFailure } from "./language/rule/rule";
2323

2424
export function removeDisabledFailures(sourceFile: ts.SourceFile, failures: RuleFailure[]): RuleFailure[] {
25-
if (!failures.length) {
25+
if (failures.length === 0) {
2626
// Usually there won't be failures anyway, so no need to look for "tslint:disable".
2727
return failures;
2828
}
@@ -31,7 +31,7 @@ export function removeDisabledFailures(sourceFile: ts.SourceFile, failures: Rule
3131
const map = getDisableMap(sourceFile, failingRules);
3232
return failures.filter((failure) => {
3333
const disabledIntervals = map.get(failure.getRuleName());
34-
return !disabledIntervals || !disabledIntervals.some(({ pos, end }) => {
34+
return disabledIntervals === undefined || !disabledIntervals.some(({ pos, end }) => {
3535
const failPos = failure.getStartPosition().getPosition();
3636
const failEnd = failure.getEndPosition().getPosition();
3737
return failEnd >= pos && (end === -1 || failPos <= end);
@@ -51,10 +51,10 @@ function getDisableMap(sourceFile: ts.SourceFile, failingRules: Set<string>): Re
5151
? fullText.substring(comment.pos + 2, comment.end)
5252
: fullText.substring(comment.pos + 2, comment.end - 2);
5353
const parsed = parseComment(commentText);
54-
if (parsed) {
54+
if (parsed !== undefined) {
5555
const { rulesList, isEnabled, modifier } = parsed;
5656
const switchRange = getSwitchRange(modifier, comment, sourceFile);
57-
if (switchRange) {
57+
if (switchRange !== undefined) {
5858
const rulesToSwitch = rulesList === "all" ? Array.from(failingRules) : rulesList.filter((r) => failingRules.has(r));
5959
for (const ruleToSwitch of rulesToSwitch) {
6060
switchRuleState(ruleToSwitch, isEnabled, switchRange.pos, switchRange.end);
@@ -69,7 +69,7 @@ function getDisableMap(sourceFile: ts.SourceFile, failingRules: Set<string>): Re
6969
const disableRanges = map.get(ruleName);
7070

7171
if (isEnable) {
72-
if (disableRanges) {
72+
if (disableRanges !== undefined) {
7373
const lastDisable = disableRanges[disableRanges.length - 1];
7474
if (lastDisable.end === -1) {
7575
lastDisable.end = start;
@@ -80,7 +80,7 @@ function getDisableMap(sourceFile: ts.SourceFile, failingRules: Set<string>): Re
8080
}
8181
}
8282
} else { // disable
83-
if (!disableRanges) {
83+
if (disableRanges === undefined) {
8484
map.set(ruleName, [{ pos: start, end }]);
8585
} else if (disableRanges[disableRanges.length - 1].end !== -1) {
8686
disableRanges.push({ pos: start, end });
@@ -138,9 +138,7 @@ function parseComment(commentText: string): { rulesList: string[] | "all", isEna
138138
// remove everything matched by the previous regex to get only the specified rules
139139
// split at whitespaces
140140
// filter empty items coming from whitespaces at start, at end or empty list
141-
let rulesList: string[] | "all" = commentText.substr(match[0].length)
142-
.split(/\s+/)
143-
.filter((rule) => !!rule);
141+
let rulesList: string[] | "all" = splitOnSpaces(commentText.substr(match[0].length));
144142
if (rulesList.length === 0 && match[3] === ":") {
145143
// nothing to do here: an explicit separator was specified but no rules to switch
146144
return undefined;
@@ -154,3 +152,7 @@ function parseComment(commentText: string): { rulesList: string[] | "all", isEna
154152

155153
return { rulesList, isEnabled: match[1] === "enable", modifier: match[2] as Modifier };
156154
}
155+
156+
function splitOnSpaces(str: string): string[] {
157+
return str.split(/\s+/).filter((s) => s !== "");
158+
}

src/formatterLoader.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ export function findFormatter(name: string | FormatterConstructor, formattersDir
3737
}
3838

3939
// then check for rules within the first level of rulesDirectory
40-
if (formattersDirectory) {
40+
if (formattersDirectory !== undefined) {
4141
Formatter = loadFormatter(formattersDirectory, camelizedName);
42-
if (Formatter) {
42+
if (Formatter !== undefined) {
4343
return Formatter;
4444
}
4545
}

src/formatters/checkstyleFormatter.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,15 @@ export class Formatter extends AbstractFormatter {
4242
public format(failures: RuleFailure[]): string {
4343
let output = '<?xml version="1.0" encoding="utf-8"?><checkstyle version="4.3">';
4444

45-
if (failures.length) {
45+
if (failures.length !== 0) {
4646
const failuresSorted = failures.sort((a, b) => {
4747
return a.getFileName().localeCompare(b.getFileName());
4848
});
4949
let previousFilename: string | null = null;
5050
for (const failure of failuresSorted) {
5151
const severity = failure.getRuleSeverity();
5252
if (failure.getFileName() !== previousFilename) {
53-
if (previousFilename) {
53+
if (previousFilename !== null) {
5454
output += "</file>";
5555
}
5656
previousFilename = failure.getFileName();
@@ -63,7 +63,7 @@ export class Formatter extends AbstractFormatter {
6363
// checkstyle parser wants "source" to have structure like <anything>dot<category>dot<type>
6464
output += "source=\"failure.tslint." + this.escapeXml(failure.getRuleName()) + "\" />";
6565
}
66-
if (previousFilename) {
66+
if (previousFilename !== null) {
6767
output += "</file>";
6868
}
6969
}

src/formatters/proseFormatter.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,16 @@ export class Formatter extends AbstractFormatter {
3030
/* tslint:enable:object-literal-sort-keys */
3131

3232
public format(failures: RuleFailure[], fixes?: RuleFailure[]): string {
33-
if (failures.length === 0 && (!fixes || fixes.length === 0)) {
33+
if (failures.length === 0 && (fixes === undefined || fixes.length === 0)) {
3434
return "\n";
3535
}
3636

3737
const fixLines: string[] = [];
38-
if (fixes) {
38+
if (fixes !== undefined) {
3939
const perFileFixes = new Map<string, number>();
4040
for (const fix of fixes) {
41-
perFileFixes.set(fix.getFileName(), (perFileFixes.get(fix.getFileName()) || 0) + 1);
41+
const prevFixes = perFileFixes.get(fix.getFileName());
42+
perFileFixes.set(fix.getFileName(), (prevFixes !== undefined ? prevFixes : 0) + 1);
4243
}
4344

4445
perFileFixes.forEach((fixCount, fixedFile) => {

src/formatters/stylishFormatter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export class Formatter extends AbstractFormatter {
5050
}
5151

5252
private mapToMessages(failures: RuleFailure[]): string[] {
53-
if (!failures) {
53+
if (failures.length === 0) {
5454
return [];
5555
}
5656
const outputLines: string[] = [];

src/formatters/vsoFormatter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export class Formatter extends AbstractFormatter {
4343
const lineAndCharacter = failure.getStartPosition().getLineAndCharacter();
4444
const line = lineAndCharacter.line + 1;
4545
const character = lineAndCharacter.character + 1;
46-
const code = (failure.getRuleName ? failure.getRuleName() : "");
46+
const code = failure.getRuleName();
4747
const properties = `sourcepath=${fileName};linenumber=${line};columnnumber=${character};code=${code};`;
4848

4949
return `##vso[task.logissue type=warning;${properties}]${failureString}`;

src/language/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export function doesIntersect(failure: RuleFailure, disabledIntervals: IDisabled
3838
/**
3939
* @returns true if any modifier kinds passed along exist in the given modifiers array
4040
*/
41-
export function hasModifier(modifiers: ts.ModifiersArray | undefined, ...modifierKinds: ts.SyntaxKind[]) {
41+
export function hasModifier(modifiers: ts.ModifiersArray | undefined, ...modifierKinds: ts.SyntaxKind[]): boolean {
4242
if (modifiers === undefined || modifierKinds.length === 0) {
4343
return false;
4444
}
@@ -101,7 +101,7 @@ export function ancestorWhere<T extends ts.Node>(node: ts.Node, predicate: (n: t
101101
return cur as T;
102102
}
103103
cur = cur.parent;
104-
} while (cur);
104+
} while (cur !== undefined);
105105
return undefined;
106106
}
107107

src/language/walker/ruleWalker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export class RuleWalker extends SyntaxWalker implements IWalker {
5757
}
5858

5959
public hasOption(option: string): boolean {
60-
if (this.options) {
60+
if (this.options !== undefined) {
6161
return this.options.indexOf(option) !== -1;
6262
} else {
6363
return false;

src/linter.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ class Linter {
9595
const enabledRules = this.getEnabledRules(configuration, isJs);
9696

9797
let fileFailures = this.getAllFailures(sourceFile, enabledRules);
98-
if (!fileFailures.length) {
98+
if (fileFailures.length === 0) {
9999
// Usual case: no errors.
100100
return;
101101
}
@@ -124,9 +124,9 @@ class Linter {
124124
let formatter: IFormatter;
125125
const formattersDirectory = getRelativePath(this.options.formattersDirectory);
126126

127-
const formatterName = this.options.formatter || "prose";
127+
const formatterName = this.options.formatter !== undefined ? this.options.formatter : "prose";
128128
const Formatter = findFormatter(formatterName, formattersDirectory);
129-
if (Formatter) {
129+
if (Formatter !== undefined) {
130130
formatter = new Formatter();
131131
} else {
132132
throw new Error(`formatter '${formatterName}' not found`);
@@ -193,7 +193,7 @@ class Linter {
193193

194194
private applyRule(rule: IRule, sourceFile: ts.SourceFile): RuleFailure[] {
195195
try {
196-
if (this.program && isTypedRule(rule)) {
196+
if (this.program !== undefined && isTypedRule(rule)) {
197197
return rule.applyWithProgram(sourceFile, this.program);
198198
} else {
199199
return rule.apply(sourceFile);
@@ -216,7 +216,7 @@ class Linter {
216216
}
217217

218218
private getSourceFile(fileName: string, source: string) {
219-
if (this.program) {
219+
if (this.program !== undefined) {
220220
const sourceFile = this.program.getSourceFile(fileName);
221221
if (sourceFile === undefined) {
222222
const INVALID_SOURCE_ERROR = dedent`

src/ruleLoader.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const cachedRules = new Map<string, RuleConstructor | "not-found">();
2929

3030
export function loadRules(ruleOptionsList: IOptions[],
3131
rulesDirectories?: string | string[],
32-
isJs?: boolean): IRule[] {
32+
isJs = false): IRule[] {
3333
const rules: IRule[] = [];
3434
const notFoundRules: string[] = [];
3535
const notAllowedInJsRules: string[] = [];
@@ -44,15 +44,15 @@ export function loadRules(ruleOptionsList: IOptions[],
4444
const Rule = findRule(ruleName, rulesDirectories);
4545
if (Rule === undefined) {
4646
notFoundRules.push(ruleName);
47-
} else if (isJs && Rule.metadata && Rule.metadata.typescriptOnly) {
47+
} else if (isJs && Rule.metadata !== undefined && Rule.metadata.typescriptOnly) {
4848
notAllowedInJsRules.push(ruleName);
4949
} else {
5050
const rule = new Rule(ruleOptions);
5151
if (rule.isEnabled()) {
5252
rules.push(rule);
5353
}
5454

55-
if (Rule.metadata && Rule.metadata.deprecationMessage) {
55+
if (Rule.metadata !== undefined && Rule.metadata.deprecationMessage !== undefined) {
5656
showWarningOnce(`${Rule.metadata.ruleName} is deprecated. ${Rule.metadata.deprecationMessage}`);
5757
}
5858
}

src/rules/arrayTypeRule.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ function walk(ctx: Lint.WalkContext<Option>): void {
7979
const failureString = option === "generic" ? Rule.FAILURE_STRING_GENERIC : Rule.FAILURE_STRING_GENERIC_SIMPLE;
8080
const parens = elementType.kind === ts.SyntaxKind.ParenthesizedType ? 1 : 0;
8181
// Add a space if the type is preceded by 'as' and the node has no leading whitespace
82-
const space = !parens && parent!.kind === ts.SyntaxKind.AsExpression && node.getStart() === node.getFullStart();
82+
const space = parens === 0 && parent!.kind === ts.SyntaxKind.AsExpression && node.getStart() === node.getFullStart();
8383
const fix = [
8484
new Lint.Replacement(elementType.getStart(), parens, (space ? " " : "") + "Array<"),
8585
// Delete the square brackets and replace with an angle bracket
@@ -96,7 +96,7 @@ function walk(ctx: Lint.WalkContext<Option>): void {
9696
}
9797

9898
const failureString = option === "array" ? Rule.FAILURE_STRING_ARRAY : Rule.FAILURE_STRING_ARRAY_SIMPLE;
99-
if (!typeArguments || typeArguments.length === 0) {
99+
if (typeArguments === undefined || typeArguments.length === 0) {
100100
// Create an 'any' array
101101
const fix = Lint.Replacement.replaceFromTo(node.getStart(), node.getEnd(), "any[]");
102102
ctx.addFailureAtNode(node, failureString, fix);
@@ -152,7 +152,7 @@ function isSimpleType(nodeType: ts.TypeNode): boolean {
152152
case ts.SyntaxKind.TypeReference:
153153
// TypeReferences must be non-generic or be another Array with a simple type
154154
const { typeName, typeArguments } = nodeType as ts.TypeReferenceNode;
155-
if (!typeArguments) {
155+
if (typeArguments === undefined) {
156156
return true;
157157
}
158158
switch (typeArguments.length) {

src/rules/arrowReturnShorthandRule.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ function createFix(arrowFunction: ts.FunctionLikeDeclaration, body: ts.Block, ex
8181
const semicolon = Lint.childOfKind(statement, ts.SyntaxKind.SemicolonToken);
8282

8383
const anyComments = hasComments(arrow) || hasComments(openBrace) || hasComments(statement) || hasComments(returnKeyword) ||
84-
hasComments(expr) || (semicolon && hasComments(semicolon)) || hasComments(closeBrace);
84+
hasComments(expr) || (semicolon !== undefined && hasComments(semicolon)) || hasComments(closeBrace);
8585
return anyComments ? undefined : [
8686
// Object literal must be wrapped in `()`
8787
...(expr.kind === ts.SyntaxKind.ObjectLiteralExpression ? [

src/rules/awaitPromiseRule.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,7 @@ function couldBePromise(type: ts.Type): boolean {
6565

6666
function isPromiseType(type: ts.Type): boolean {
6767
const { target } = type as ts.TypeReference;
68-
const symbol = target && target.symbol;
69-
return !!symbol && symbol.name === "Promise";
68+
return target !== undefined && target.symbol !== undefined && target.symbol.name === "Promise";
7069
}
7170

7271
function isUnionType(type: ts.Type): type is ts.UnionType {

src/rules/banRule.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export class Rule extends Lint.Rules.AbstractRule {
5050
/* tslint:enable:object-literal-sort-keys */
5151

5252
public static FAILURE_STRING_FACTORY(expression: string, messageAddition?: string) {
53-
return `Calls to '${expression}' are not allowed.${messageAddition ? " " + messageAddition : ""}`;
53+
return `Calls to '${expression}' are not allowed.${messageAddition !== undefined ? " " + messageAddition : ""}`;
5454
}
5555

5656
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {

src/rules/banTypesRule.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export class Rule extends Lint.Rules.AbstractRule {
5252

5353
public static FAILURE_STRING_FACTORY(typeName: string, messageAddition?: string) {
5454
return `Don't use '${typeName}' as a type.` +
55-
(messageAddition ? " " + messageAddition : "");
55+
(messageAddition !== undefined ? " " + messageAddition : "");
5656
}
5757

5858
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {

0 commit comments

Comments
 (0)