From c22f40675e5024092f53e76a3cc1d4278808764a Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Sat, 25 Mar 2017 14:05:26 -0700 Subject: [PATCH 1/2] Lint for strict-boolean-expressions --- package.json | 4 +- src/configuration.ts | 24 ++++----- src/enableDisableRules.ts | 4 +- src/formatterLoader.ts | 4 +- src/formatters/checkstyleFormatter.ts | 6 +-- src/formatters/proseFormatter.ts | 7 +-- src/formatters/stylishFormatter.ts | 2 +- src/formatters/vsoFormatter.ts | 2 +- src/language/utils.ts | 4 +- src/language/walker/ruleWalker.ts | 2 +- src/linter.ts | 10 ++-- src/ruleLoader.ts | 14 +++--- src/rules/adjacentOverloadSignaturesRule.ts | 20 ++++---- src/rules/arrayTypeRule.ts | 12 +++-- src/rules/arrowReturnShorthandRule.ts | 4 +- src/rules/awaitPromiseRule.ts | 3 +- src/rules/banRule.ts | 2 +- src/rules/banTypesRule.ts | 4 +- src/rules/callableTypesRule.ts | 8 +-- src/rules/commentFormatRule.ts | 12 ++--- src/rules/completedDocsRule.ts | 15 +++--- src/rules/cyclomaticComplexityRule.ts | 4 +- src/rules/fileHeaderRule.ts | 32 ++++++------ src/rules/importSpacingRule.ts | 2 +- src/rules/indentRule.ts | 4 +- src/rules/interfaceNameRule.ts | 2 +- src/rules/matchDefaultExportNameRule.ts | 10 ++-- src/rules/memberAccessRule.ts | 6 ++- src/rules/memberOrderingRule.ts | 14 ++++-- src/rules/newlineBeforeReturnRule.ts | 2 +- src/rules/noBooleanLiteralCompareRule.ts | 2 +- src/rules/noConsecutiveBlankLinesRule.ts | 7 ++- src/rules/noDuplicateSuperRule.ts | 16 +++--- src/rules/noEmptyInterfaceRule.ts | 2 +- src/rules/noFloatingPromisesRule.ts | 4 +- src/rules/noForInArrayRule.ts | 6 +-- src/rules/noImportSideEffectRule.ts | 6 +-- src/rules/noMergeableNamespaceRule.ts | 4 +- src/rules/noReferenceImportRule.ts | 8 +-- src/rules/noUnboundMethodRule.ts | 4 +- src/rules/noUnnecessaryCallbackWrapperRule.ts | 6 ++- src/rules/noUnnecessaryInitializerRule.ts | 4 +- src/rules/noUnsafeFinallyRule.ts | 6 +-- src/rules/noUnusedVariableRule.ts | 50 +++++++++---------- src/rules/noUseBeforeDeclareRule.ts | 5 +- src/rules/noVarKeywordRule.ts | 2 +- src/rules/objectLiteralKeyQuotesRule.ts | 7 ++- src/rules/objectLiteralShorthandRule.ts | 4 +- src/rules/oneLineRule.ts | 2 +- src/rules/onlyArrowFunctionsRule.ts | 8 +-- src/rules/orderedImportsRule.ts | 22 +++++--- src/rules/preferConstRule.ts | 6 +-- src/rules/preferFunctionOverMethodRule.ts | 4 +- src/rules/preferMethodSignatureRule.ts | 2 +- src/rules/preferTemplateRule.ts | 2 +- src/rules/returnUndefinedRule.ts | 10 ++-- src/rules/semicolonRule.ts | 4 +- src/rules/strictTypePredicatesRule.ts | 9 ++-- src/rules/trailingCommaRule.ts | 6 +-- src/rules/tripleEqualsRule.ts | 2 +- src/rules/typedefRule.ts | 4 +- src/rules/typedefWhitespaceRule.ts | 2 +- src/rules/typeofCompareRule.ts | 2 +- src/rules/unifiedSignaturesRule.ts | 29 +++++------ src/rules/variableNameRule.ts | 4 +- src/runner.ts | 31 ++++++------ src/test.ts | 14 +++--- src/test/parse.ts | 3 +- src/tslint-cli.ts | 3 ++ src/utils.ts | 8 +-- test/configurationTests.ts | 2 +- test/ruleLoaderTests.ts | 4 +- tslint.json | 1 + 73 files changed, 303 insertions(+), 263 deletions(-) diff --git a/package.json b/package.json index 8de22e766a7..66e1fc2fb57 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,8 @@ "compile:scripts": "tsc -p scripts", "compile:test": "tsc -p test", "lint": "npm-run-all -p lint:global lint:from-bin", - "lint:global": "tslint --project test/tsconfig.json --format stylish # test includes 'src' too", - "lint:from-bin": "node bin/tslint --project test/tsconfig.json --format stylish", + "lint:global": "tslint --project test/tsconfig.json --type-check --format stylish # test includes 'src' too", + "lint:from-bin": "node bin/tslint --project test/tsconfig.json --type-check --format stylish", "test": "npm-run-all test:pre -p test:mocha test:rules", "test:pre": "cd ./test/config && npm install", "test:mocha": "mocha --reporter spec --colors \"build/test/**/*Tests.js\" build/test/assert.js", diff --git a/src/configuration.ts b/src/configuration.ts index 7b3e9bc0ac8..1c2ec7661d0 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -168,7 +168,7 @@ function resolveConfigurationPath(filePath: string, relativeTo?: string) { } } - const basedir = relativeTo || process.cwd(); + const basedir = relativeTo !== undefined ? relativeTo : process.cwd(); try { return resolve.sync(filePath, { basedir }); } catch (err) { @@ -244,7 +244,7 @@ function getHomeDir() { // returns the absolute path (contrary to what the name implies) export function getRelativePath(directory?: string | null, relativeTo?: string) { if (directory != null) { - const basePath = relativeTo || process.cwd(); + const basePath = relativeTo !== undefined ? relativeTo : process.cwd(); return path.resolve(basePath, directory); } return undefined; @@ -291,7 +291,7 @@ function parseRuleOptions(ruleConfigValue: any): Partial { // old style: boolean ruleArguments = []; ruleSeverity = ruleConfigValue === true ? "error" : "off"; - } else if (ruleConfigValue.severity) { + } else if (ruleConfigValue.severity !== undefined) { switch (ruleConfigValue.severity.toLowerCase()) { case "warn": case "warning": @@ -309,7 +309,7 @@ function parseRuleOptions(ruleConfigValue: any): Partial { ruleSeverity = "off"; } - if (ruleConfigValue && ruleConfigValue.options) { + if (ruleConfigValue != null && ruleConfigValue.options != null) { ruleArguments = arrayify(ruleConfigValue.options); } @@ -329,17 +329,17 @@ export function parseConfigFile(configFile: any, configFileDir?: string): IConfi const rules = new Map>(); const jsRules = new Map>(); - if (configFile.rules) { + if (configFile.rules != null) { for (const ruleName in configFile.rules) { - if (configFile.rules.hasOwnProperty(ruleName)) { + if (Object.prototype.hasOwnProperty.call(configFile.rules, ruleName) as boolean) { rules.set(ruleName, parseRuleOptions(configFile.rules[ruleName])); } } } - if (configFile.jsRules) { + if (configFile.jsRules != null) { for (const ruleName in configFile.jsRules) { - if (configFile.jsRules.hasOwnProperty(ruleName)) { + if (Object.prototype.hasOwnProperty.call(configFile.jsRules, ruleName) as boolean) { jsRules.set(ruleName, parseRuleOptions(configFile.jsRules[ruleName])); } } @@ -348,7 +348,7 @@ export function parseConfigFile(configFile: any, configFileDir?: string): IConfi return { extends: arrayify(configFile.extends), jsRules, - linterOptions: configFile.linterOptions || {}, + linterOptions: configFile.linterOptions != null ? configFile.linterOptions : {}, rulesDirectory: getRulesDirectories(configFile.rulesDirectory, configFileDir), rules, }; @@ -359,12 +359,12 @@ export function parseConfigFile(configFile: any, configFileDir?: string): IConfi */ export function convertRuleOptions(ruleConfiguration: Map>): IOptions[] { const output: IOptions[] = []; - ruleConfiguration.forEach((partialOptions, ruleName) => { + ruleConfiguration.forEach(({ ruleArguments, ruleSeverity }, ruleName) => { const options: IOptions = { disabledIntervals: [], - ruleArguments: partialOptions.ruleArguments || [], + ruleArguments: ruleArguments != null ? ruleArguments : [], ruleName, - ruleSeverity: partialOptions.ruleSeverity || "error", + ruleSeverity: ruleSeverity != null ? ruleSeverity : "error", }; output.push(options); }); diff --git a/src/enableDisableRules.ts b/src/enableDisableRules.ts index 64d4cdccfde..c81798c0c90 100644 --- a/src/enableDisableRules.ts +++ b/src/enableDisableRules.ts @@ -74,7 +74,7 @@ export class EnableDisableRulesWalker { position: start, }); - if (end) { + if (end !== undefined) { // we only get here when rule state changes therefore we can safely use opposite state ruleStateMap.push({ isEnabled: !isEnabled, @@ -96,7 +96,7 @@ export class EnableDisableRulesWalker { // filter empty items coming from whitespaces at start, at end or empty list let rulesList = commentText.substr(match[0].length) .split(/\s+/) - .filter((rule) => !!rule); + .filter((rule) => rule !== ""); if (rulesList.length === 0 && match[3] === ":") { // nothing to do here: an explicit separator was specified but no rules to switch return; diff --git a/src/formatterLoader.ts b/src/formatterLoader.ts index 5da7a24d56e..6bd832fef51 100644 --- a/src/formatterLoader.ts +++ b/src/formatterLoader.ts @@ -37,9 +37,9 @@ export function findFormatter(name: string | FormatterFunction, formattersDirect } // then check for rules within the first level of rulesDirectory - if (formattersDirectory) { + if (formattersDirectory !== undefined) { Formatter = loadFormatter(formattersDirectory, camelizedName); - if (Formatter) { + if (Formatter !== undefined) { return Formatter; } } diff --git a/src/formatters/checkstyleFormatter.ts b/src/formatters/checkstyleFormatter.ts index 5d8912ebc55..bf526ba23d7 100644 --- a/src/formatters/checkstyleFormatter.ts +++ b/src/formatters/checkstyleFormatter.ts @@ -42,7 +42,7 @@ export class Formatter extends AbstractFormatter { public format(failures: RuleFailure[]): string { let output = ''; - if (failures.length) { + if (failures.length !== 0) { const failuresSorted = failures.sort((a, b) => { return a.getFileName().localeCompare(b.getFileName()); }); @@ -50,7 +50,7 @@ export class Formatter extends AbstractFormatter { for (const failure of failuresSorted) { const severity = failure.getRuleSeverity(); if (failure.getFileName() !== previousFilename) { - if (previousFilename) { + if (previousFilename !== null) { output += ""; } previousFilename = failure.getFileName(); @@ -63,7 +63,7 @@ export class Formatter extends AbstractFormatter { // checkstyle parser wants "source" to have structure like dotdot output += "source=\"failure.tslint." + this.escapeXml(failure.getRuleName()) + "\" />"; } - if (previousFilename) { + if (previousFilename !== null) { output += ""; } } diff --git a/src/formatters/proseFormatter.ts b/src/formatters/proseFormatter.ts index bc750aca49a..90568df1eda 100644 --- a/src/formatters/proseFormatter.ts +++ b/src/formatters/proseFormatter.ts @@ -30,15 +30,16 @@ export class Formatter extends AbstractFormatter { /* tslint:enable:object-literal-sort-keys */ public format(failures: RuleFailure[], fixes?: RuleFailure[]): string { - if (failures.length === 0 && (!fixes || fixes.length === 0)) { + if (failures.length === 0 && (fixes === undefined || fixes.length === 0)) { return "\n"; } const fixLines: string[] = []; - if (fixes) { + if (fixes !== undefined) { const perFileFixes = new Map(); for (const fix of fixes) { - perFileFixes.set(fix.getFileName(), (perFileFixes.get(fix.getFileName()) || 0) + 1); + const prevFixes = perFileFixes.get(fix.getFileName()); + perFileFixes.set(fix.getFileName(), (prevFixes !== undefined ? prevFixes : 0) + 1); } perFileFixes.forEach((fixCount, fixedFile) => { diff --git a/src/formatters/stylishFormatter.ts b/src/formatters/stylishFormatter.ts index 36a240dd0f5..e4300db5090 100644 --- a/src/formatters/stylishFormatter.ts +++ b/src/formatters/stylishFormatter.ts @@ -50,7 +50,7 @@ export class Formatter extends AbstractFormatter { } private mapToMessages(failures: RuleFailure[]): string[] { - if (!failures) { + if (failures.length === 0) { return []; } const outputLines: string[] = []; diff --git a/src/formatters/vsoFormatter.ts b/src/formatters/vsoFormatter.ts index 90949496be4..e8eaab9888d 100644 --- a/src/formatters/vsoFormatter.ts +++ b/src/formatters/vsoFormatter.ts @@ -43,7 +43,7 @@ export class Formatter extends AbstractFormatter { const lineAndCharacter = failure.getStartPosition().getLineAndCharacter(); const line = lineAndCharacter.line + 1; const character = lineAndCharacter.character + 1; - const code = (failure.getRuleName ? failure.getRuleName() : ""); + const code = failure.getRuleName(); const properties = `sourcepath=${fileName};linenumber=${line};columnnumber=${character};code=${code};`; return `##vso[task.logissue type=warning;${properties}]${failureString}`; diff --git a/src/language/utils.ts b/src/language/utils.ts index e5392ebbeb6..96205930c89 100644 --- a/src/language/utils.ts +++ b/src/language/utils.ts @@ -36,7 +36,7 @@ export function doesIntersect(failure: RuleFailure, disabledIntervals: IDisabled /** * @returns true if any modifier kinds passed along exist in the given modifiers array */ -export function hasModifier(modifiers: ts.ModifiersArray | undefined, ...modifierKinds: ts.SyntaxKind[]) { +export function hasModifier(modifiers: ts.ModifiersArray | undefined, ...modifierKinds: ts.SyntaxKind[]): boolean { if (modifiers === undefined || modifierKinds.length === 0) { return false; } @@ -99,7 +99,7 @@ export function ancestorWhere(node: ts.Node, predicate: (n: t return cur as T; } cur = cur.parent; - } while (cur); + } while (cur !== undefined); return undefined; } diff --git a/src/language/walker/ruleWalker.ts b/src/language/walker/ruleWalker.ts index c686020faf9..4c1fab728f5 100644 --- a/src/language/walker/ruleWalker.ts +++ b/src/language/walker/ruleWalker.ts @@ -57,7 +57,7 @@ export class RuleWalker extends SyntaxWalker implements IWalker { } public hasOption(option: string): boolean { - if (this.options) { + if (this.options !== undefined) { return this.options.indexOf(option) !== -1; } else { return false; diff --git a/src/linter.ts b/src/linter.ts index 15ba445112e..2cad779a53d 100644 --- a/src/linter.ts +++ b/src/linter.ts @@ -104,7 +104,7 @@ class Linter { if (this.options.fix) { for (const rule of enabledRules) { const ruleFailures = this.applyRule(rule, sourceFile); - const fixes = ruleFailures.map((f) => f.getFix()).filter((f): f is Fix => !!f) as Fix[]; + const fixes = ruleFailures.map((f) => f.getFix()).filter((f): f is Fix => f !== undefined) as Fix[]; source = fs.readFileSync(fileName, { encoding: "utf-8" }); if (fixes.length > 0) { this.fixes = this.fixes.concat(ruleFailures); @@ -148,9 +148,9 @@ class Linter { let formatter: IFormatter; const formattersDirectory = getRelativePath(this.options.formattersDirectory); - const formatterName = this.options.formatter || "prose"; + const formatterName = this.options.formatter !== undefined ? this.options.formatter : "prose"; const Formatter = findFormatter(formatterName, formattersDirectory); - if (Formatter) { + if (Formatter !== undefined) { formatter = new Formatter(); } else { throw new Error(`formatter '${formatterName}' not found`); @@ -172,7 +172,7 @@ class Linter { private applyRule(rule: IRule, sourceFile: ts.SourceFile) { let ruleFailures: RuleFailure[] = []; try { - if (this.program && isTypedRule(rule)) { + if (this.program !== undefined && isTypedRule(rule)) { ruleFailures = rule.applyWithProgram(sourceFile, this.program); } else { ruleFailures = rule.apply(sourceFile); @@ -208,7 +208,7 @@ class Linter { } private getSourceFile(fileName: string, source: string) { - if (this.program) { + if (this.program !== undefined) { const sourceFile = this.program.getSourceFile(fileName); if (sourceFile === undefined) { const INVALID_SOURCE_ERROR = dedent` diff --git a/src/ruleLoader.ts b/src/ruleLoader.ts index 1fbc9ec0942..9ac6896e25b 100644 --- a/src/ruleLoader.ts +++ b/src/ruleLoader.ts @@ -36,7 +36,7 @@ export interface IEnableDisablePosition { export function loadRules(ruleOptionsList: IOptions[], enableDisableRuleMap: Map, rulesDirectories?: string | string[], - isJs?: boolean): IRule[] { + isJs = false): IRule[] { const rules: IRule[] = []; const notFoundRules: string[] = []; const notAllowedInJsRules: string[] = []; @@ -44,19 +44,19 @@ export function loadRules(ruleOptionsList: IOptions[], for (const ruleOptions of ruleOptionsList) { const ruleName = ruleOptions.ruleName; const enableDisableRules = enableDisableRuleMap.get(ruleName); - if (ruleOptions.ruleSeverity !== "off" || enableDisableRuleMap) { + if (ruleOptions.ruleSeverity !== "off" || enableDisableRuleMap !== undefined) { const Rule: (typeof AbstractRule) | null = findRule(ruleName, rulesDirectories); if (Rule == null) { notFoundRules.push(ruleName); } else { - if (isJs && Rule.metadata && Rule.metadata.typescriptOnly) { + if (isJs && Rule.metadata !== undefined && Rule.metadata.typescriptOnly) { notAllowedInJsRules.push(ruleName); } else { - const ruleSpecificList = enableDisableRules || []; + const ruleSpecificList = enableDisableRules !== undefined ? enableDisableRules : []; ruleOptions.disabledIntervals = buildDisabledIntervalsFromSwitches(ruleSpecificList); rules.push(new (Rule as any)(ruleOptions)); - if (Rule.metadata && Rule.metadata.deprecationMessage) { + if (Rule.metadata !== undefined && Rule.metadata.deprecationMessage !== undefined) { showWarningOnce(`${Rule.metadata.ruleName} is deprecated. ${Rule.metadata.deprecationMessage}`); } } @@ -127,7 +127,7 @@ function loadRule(directory: string, ruleName: string) { const fullPath = path.join(directory, ruleName); if (fs.existsSync(fullPath + ".js")) { const ruleModule = require(fullPath); - if (ruleModule && ruleModule.Rule) { + if (ruleModule !== undefined && ruleModule.Rule !== undefined) { return ruleModule.Rule; } } @@ -175,7 +175,7 @@ function buildDisabledIntervalsFromSwitches(ruleSpecificList: IEnableDisablePosi // rule enabled state is always alternating therefore we can use position of next switch as end of disabled interval // set endPosition as Infinity in case when last switch for rule in a file is disabled - const endPosition = ruleSpecificList[i + 1] ? ruleSpecificList[i + 1].position : Infinity; + const endPosition = ruleSpecificList[i + 1] !== undefined ? ruleSpecificList[i + 1].position : Infinity; disabledIntervalList.push({ endPosition, diff --git a/src/rules/adjacentOverloadSignaturesRule.ts b/src/rules/adjacentOverloadSignaturesRule.ts index 34036d8464f..cfbf6031de9 100644 --- a/src/rules/adjacentOverloadSignaturesRule.ts +++ b/src/rules/adjacentOverloadSignaturesRule.ts @@ -52,7 +52,7 @@ class AdjacentOverloadSignaturesWalker extends Lint.RuleWalker { public visitModuleDeclaration(node: ts.ModuleDeclaration) { const { body } = node; - if (body && body.kind === ts.SyntaxKind.ModuleBlock) { + if (body !== undefined && body.kind === ts.SyntaxKind.ModuleBlock) { this.visitStatements((body as ts.ModuleBlock).statements); } super.visitModuleDeclaration(node); @@ -77,7 +77,7 @@ class AdjacentOverloadSignaturesWalker extends Lint.RuleWalker { this.checkOverloadsAdjacent(statements, (statement) => { if (statement.kind === ts.SyntaxKind.FunctionDeclaration) { const name = (statement as ts.FunctionDeclaration).name; - return name && { name: name.text, key: name.text }; + return name === undefined ? undefined : { name: name.text, key: name.text }; } else { return undefined; } @@ -94,7 +94,7 @@ class AdjacentOverloadSignaturesWalker extends Lint.RuleWalker { const seen = new Set(); for (const node of overloads) { const overload = getOverload(node); - if (overload) { + if (overload !== undefined) { const { name, key } = overload; if (seen.has(key) && lastKey !== key) { this.addFailureAtNode(node, Rule.FAILURE_STRING_FACTORY(name)); @@ -117,7 +117,7 @@ interface Overload { export function getOverloadKey(node: ts.SignatureDeclaration): string | undefined { const o = getOverload(node); - return o && o.key; + return o === undefined ? undefined : o.key; } function getOverloadIfSignature(node: ts.TypeElement | ts.ClassElement): Overload | undefined { @@ -139,7 +139,7 @@ function getOverload(node: ts.SignatureDeclaration): Overload | undefined { } const propertyInfo = getPropertyInfo(node.name); - if (!propertyInfo) { + if (propertyInfo === undefined) { return undefined; } @@ -149,14 +149,16 @@ function getOverload(node: ts.SignatureDeclaration): Overload | undefined { return { name, key }; } -function getPropertyInfo(name: ts.PropertyName): { name: string, computed?: boolean } | undefined { +function getPropertyInfo(name: ts.PropertyName): { name: string, computed: boolean } | undefined { switch (name.kind) { case ts.SyntaxKind.Identifier: - return { name: (name as ts.Identifier).text }; + return { name: (name as ts.Identifier).text, computed: false }; case ts.SyntaxKind.ComputedPropertyName: const { expression } = (name as ts.ComputedPropertyName); - return utils.isLiteralExpression(expression) ? { name: expression.text } : { name: expression.getText(), computed: true }; + return utils.isLiteralExpression(expression) + ? { name: expression.text, computed: false } + : { name: expression.getText(), computed: true }; default: - return utils.isLiteralExpression(name) ? { name: (name as ts.StringLiteral).text } : undefined; + return utils.isLiteralExpression(name) ? { name: (name as ts.StringLiteral).text, computed: false } : undefined; } } diff --git a/src/rules/arrayTypeRule.ts b/src/rules/arrayTypeRule.ts index 40841ba6d05..fbc06cf4d43 100644 --- a/src/rules/arrayTypeRule.ts +++ b/src/rules/arrayTypeRule.ts @@ -63,7 +63,7 @@ class ArrayTypeWalker extends Lint.RuleWalker { const failureString = this.hasOption(OPTION_GENERIC) ? Rule.FAILURE_STRING_GENERIC : Rule.FAILURE_STRING_GENERIC_SIMPLE; const parens = typeName.kind === ts.SyntaxKind.ParenthesizedType ? 1 : 0; // Add a space if the type is preceded by 'as' and the node has no leading whitespace - const space = !parens && node.parent!.kind === ts.SyntaxKind.AsExpression && + const space = parens === 0 && node.parent!.kind === ts.SyntaxKind.AsExpression && node.getStart() === node.getFullStart() ? " " : ""; const fix = this.createFix( this.createReplacement(typeName.getStart(), parens, space + "Array<"), @@ -81,11 +81,13 @@ class ArrayTypeWalker extends Lint.RuleWalker { if (typeName === "Array" && (this.hasOption(OPTION_ARRAY) || this.hasOption(OPTION_ARRAY_SIMPLE))) { const failureString = this.hasOption(OPTION_ARRAY) ? Rule.FAILURE_STRING_ARRAY : Rule.FAILURE_STRING_ARRAY_SIMPLE; const typeArgs = node.typeArguments; - if (!typeArgs || typeArgs.length === 0) { + if (typeArgs === undefined || typeArgs.length === 0) { // Create an 'any' array const fix = this.createFix(this.createReplacement(node.getStart(), node.getWidth(), "any[]")); this.addFailureAtNode(node, failureString, fix); - } else if (typeArgs && typeArgs.length === 1 && (!this.hasOption(OPTION_ARRAY_SIMPLE) || this.isSimpleType(typeArgs[0]))) { + } else if (typeArgs !== undefined && + typeArgs.length === 1 && + (!this.hasOption(OPTION_ARRAY_SIMPLE) || this.isSimpleType(typeArgs[0]))) { const type = typeArgs[0]; const typeStart = type.getStart(); const typeEnd = type.getEnd(); @@ -121,7 +123,9 @@ class ArrayTypeWalker extends Lint.RuleWalker { // TypeReferences must be non-generic or be another Array with a simple type const node = nodeType as ts.TypeReferenceNode; const typeArgs = node.typeArguments; - if (!typeArgs || typeArgs.length === 0 || node.typeName.getText() === "Array" && this.isSimpleType(typeArgs[0])) { + if (typeArgs === undefined || + typeArgs.length === 0 || + node.typeName.getText() === "Array" && this.isSimpleType(typeArgs[0])) { return true; } else { return false; diff --git a/src/rules/arrowReturnShorthandRule.ts b/src/rules/arrowReturnShorthandRule.ts index 4a765d5fe25..c598261a96e 100644 --- a/src/rules/arrowReturnShorthandRule.ts +++ b/src/rules/arrowReturnShorthandRule.ts @@ -52,7 +52,7 @@ export class Rule extends Lint.Rules.AbstractRule { class Walker extends Lint.RuleWalker { public visitArrowFunction(node: ts.ArrowFunction) { - if (node.body && node.body.kind === ts.SyntaxKind.Block) { + if (node.body !== undefined && node.body.kind === ts.SyntaxKind.Block) { const expr = getSimpleReturnExpression(node.body as ts.Block); if (expr !== undefined && (this.hasOption(OPTION_MULTILINE) || !this.isMultiline(node.body))) { this.addFailureAtNode(node.body, Rule.FAILURE_STRING, this.createArrowFunctionFix(node, node.body as ts.Block, expr)); @@ -77,7 +77,7 @@ class Walker extends Lint.RuleWalker { const semicolon = Lint.childOfKind(statement, ts.SyntaxKind.SemicolonToken); const anyComments = hasComments(arrow) || hasComments(openBrace) || hasComments(statement) || hasComments(returnKeyword) || - hasComments(expr) || (semicolon && hasComments(semicolon)) || hasComments(closeBrace); + hasComments(expr) || (semicolon !== undefined && hasComments(semicolon)) || hasComments(closeBrace); return anyComments ? undefined : this.createFix( // Object literal must be wrapped in `()` ...(expr.kind === ts.SyntaxKind.ObjectLiteralExpression ? [ diff --git a/src/rules/awaitPromiseRule.ts b/src/rules/awaitPromiseRule.ts index 7197af22942..0a81352d9bc 100644 --- a/src/rules/awaitPromiseRule.ts +++ b/src/rules/awaitPromiseRule.ts @@ -65,8 +65,7 @@ function couldBePromise(type: ts.Type): boolean { function isPromiseType(type: ts.Type): boolean { const { target } = type as ts.TypeReference; - const symbol = target && target.symbol; - return !!symbol && symbol.name === "Promise"; + return target !== undefined && target.symbol !== undefined && target.symbol.name === "Promise"; } function isUnionType(type: ts.Type): type is ts.UnionType { diff --git a/src/rules/banRule.ts b/src/rules/banRule.ts index 80c2a36fc37..d1e5f5ee4ab 100644 --- a/src/rules/banRule.ts +++ b/src/rules/banRule.ts @@ -44,7 +44,7 @@ export class Rule extends Lint.Rules.AbstractRule { /* tslint:enable:object-literal-sort-keys */ public static FAILURE_STRING_FACTORY = (expression: string, messageAddition?: string) => { - return `Calls to '${expression}' are not allowed.${messageAddition ? " " + messageAddition : ""}`; + return `Calls to '${expression}' are not allowed.${messageAddition !== undefined ? " " + messageAddition : ""}`; } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { diff --git a/src/rules/banTypesRule.ts b/src/rules/banTypesRule.ts index bab1c710edf..498e8d9d5ff 100644 --- a/src/rules/banTypesRule.ts +++ b/src/rules/banTypesRule.ts @@ -46,7 +46,7 @@ export class Rule extends Lint.Rules.AbstractRule { public static FAILURE_STRING_FACTORY(typeName: string, messageAddition?: string) { return `Don't use '${typeName}' as a type.` + - (messageAddition ? " " + messageAddition : ""); + (messageAddition !== undefined ? " " + messageAddition : ""); } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { @@ -67,7 +67,7 @@ class BanTypeWalker extends Lint.RuleWalker { const ban = this.bans.find(([bannedType]) => typeName.match(`^${bannedType}$`) != null) as string[]; - if (ban) { + if (ban !== undefined) { this.addFailure(this.createFailure( node.getStart(), node.getWidth(), Rule.FAILURE_STRING_FACTORY(typeName, ban[1]))); diff --git a/src/rules/callableTypesRule.ts b/src/rules/callableTypesRule.ts index 3c2b9eb0cfe..d7575e810f7 100644 --- a/src/rules/callableTypesRule.ts +++ b/src/rules/callableTypesRule.ts @@ -61,7 +61,7 @@ class Walker extends Lint.RuleWalker { private check(node: ts.InterfaceDeclaration | ts.TypeLiteralNode) { if (node.members.length === 1 && node.members[0].kind === ts.SyntaxKind.CallSignature) { const call = node.members[0] as ts.CallSignatureDeclaration; - if (!call.type) { + if (call.type === undefined) { // Bad parse return; } @@ -78,7 +78,7 @@ class Walker extends Lint.RuleWalker { /** True if there is no supertype or if the supertype is `Function`. */ function noSupertype(heritageClauses: ts.NodeArray | undefined): boolean { - if (!heritageClauses) { + if (heritageClauses === undefined) { return true; } @@ -93,11 +93,11 @@ function noSupertype(heritageClauses: ts.NodeArray | undefine } function renderSuggestion(call: ts.CallSignatureDeclaration): string { - const typeParameters = call.typeParameters && call.typeParameters.map((p) => p.getText()).join(", "); + const typeParameters = call.typeParameters === undefined ? undefined : call.typeParameters.map((p) => p.getText()).join(", "); const parameters = call.parameters.map((p) => p.getText()).join(", "); const returnType = call.type === undefined ? "void" : call.type.getText(); let res = `(${parameters}) => ${returnType}`; - if (typeParameters) { + if (typeParameters !== undefined) { res = `<${typeParameters}>${res}`; } return res; diff --git a/src/rules/commentFormatRule.ts b/src/rules/commentFormatRule.ts index 12604bd1d3d..268e9ab6aa0 100644 --- a/src/rules/commentFormatRule.ts +++ b/src/rules/commentFormatRule.ts @@ -45,11 +45,11 @@ export class Rule extends Lint.Rules.AbstractRule { * note that comments starting with \`///\` are also allowed, for things such as \`///\` * \`"check-lowercase"\` requires that the first non-whitespace character of a comment must be lowercase, if applicable. * \`"check-uppercase"\` requires that the first non-whitespace character of a comment must be uppercase, if applicable. - + Exceptions to \`"check-lowercase"\` or \`"check-uppercase"\` can be managed with object that may be passed as last argument. - + One of two options can be provided in this object: - + * \`"ignore-words"\` - array of strings - words that will be ignored at the beginning of the comment. * \`"ignore-pattern"\` - string - RegExp pattern that will be ignored at the beginning of the comment. `, @@ -155,18 +155,18 @@ class CommentWalker extends Lint.RuleWalker { const exceptionsObject = optionsList[optionsList.length - 1]; // early return if last element is string instead of exceptions object - if (typeof exceptionsObject === "string" || !exceptionsObject) { + if (typeof exceptionsObject === "string" || exceptionsObject === undefined) { return null; } - if (exceptionsObject["ignore-pattern"]) { + if (exceptionsObject["ignore-pattern"] !== undefined) { const ignorePattern = exceptionsObject["ignore-pattern"] as string; this.failureIgnorePart = Rule.IGNORE_PATTERN_FAILURE_FACTORY(ignorePattern); // regex is "start of string"//"any amount of whitespace" followed by user provided ignore pattern return new RegExp(`^//\\s*(${ignorePattern})`); } - if (exceptionsObject["ignore-words"]) { + if (exceptionsObject["ignore-words"] !== undefined) { const ignoreWords = exceptionsObject["ignore-words"] as string[]; this.failureIgnorePart = Rule.IGNORE_WORDS_FAILURE_FACTORY(ignoreWords); // Converts all exceptions values to strings, trim whitespace, escapes RegExp special characters and combines into alternation diff --git a/src/rules/completedDocsRule.ts b/src/rules/completedDocsRule.ts index e2265032107..023a7742d60 100644 --- a/src/rules/completedDocsRule.ts +++ b/src/rules/completedDocsRule.ts @@ -265,7 +265,7 @@ abstract class Requirement { public abstract shouldNodeBeDocumented(node: ts.Declaration): boolean; protected createSet(values?: T[]): Set { - if (!values || values.length === 0) { + if (values === undefined || values.length === 0) { values = [ALL as T]; } @@ -388,12 +388,12 @@ class CompletedDocsWalker extends Lint.ProgramAwareRuleWalker { } const requirement = this.requirements.get(nodeType); - if (!requirement || !requirement.shouldNodeBeDocumented(node)) { + if (requirement === undefined || !requirement.shouldNodeBeDocumented(node)) { return; } const symbol = this.getTypeChecker().getSymbolAtLocation(node.name); - if (!symbol) { + if (symbol === undefined) { return; } @@ -418,7 +418,7 @@ class CompletedDocsWalker extends Lint.ProgramAwareRuleWalker { private describeDocumentationFailure(node: ts.Declaration, nodeType: string): string { let description = Rule.FAILURE_STRING_EXIST; - if (node.modifiers) { + if (node.modifiers !== undefined) { description += node.modifiers.map((modifier) => this.describeModifier(modifier.kind)) + " "; } @@ -427,7 +427,10 @@ class CompletedDocsWalker extends Lint.ProgramAwareRuleWalker { private describeModifier(kind: ts.SyntaxKind) { const description = ts.SyntaxKind[kind].toLowerCase().split("keyword")[0]; - - return CompletedDocsWalker.modifierAliases[description] || description; + const alias = CompletedDocsWalker.modifierAliases[description]; + if (alias !== undefined) { + return alias; + } + return description; } } diff --git a/src/rules/cyclomaticComplexityRule.ts b/src/rules/cyclomaticComplexityRule.ts index 046ef56a2af..88e21b2a931 100644 --- a/src/rules/cyclomaticComplexityRule.ts +++ b/src/rules/cyclomaticComplexityRule.ts @@ -201,7 +201,7 @@ class CyclomaticComplexityWalker extends Lint.RuleWalker { let failureString: string; // Attempt to find a name for the function. - if (node.name && node.name.kind === ts.SyntaxKind.Identifier) { + if (node.name !== undefined && node.name.kind === ts.SyntaxKind.Identifier) { failureString = Rule.NAMED_FAILURE_STRING(this.threshold, complexity, (node.name as ts.Identifier).text); } else { failureString = Rule.ANONYMOUS_FAILURE_STRING(this.threshold, complexity); @@ -212,7 +212,7 @@ class CyclomaticComplexityWalker extends Lint.RuleWalker { } private incrementComplexity() { - if (this.functions.length) { + if (this.functions.length !== 0) { this.functions[this.functions.length - 1]++; } } diff --git a/src/rules/fileHeaderRule.ts b/src/rules/fileHeaderRule.ts index a1d3ac89fef..9dd0f06b6fa 100644 --- a/src/rules/fileHeaderRule.ts +++ b/src/rules/fileHeaderRule.ts @@ -54,24 +54,22 @@ class FileHeaderWalker extends Lint.RuleWalker { } public visitSourceFile(node: ts.SourceFile) { - if (this.headerRegexp) { - let text = node.getFullText(); - let offset = 0; - // ignore shebang if it exists - if (text.indexOf("#!") === 0) { - offset = text.indexOf("\n") + 1; - text = text.substring(offset); - } - // check for a comment - const match = text.match(this.commentRegexp); - if (!match) { + let text = node.getFullText(); + let offset = 0; + // ignore shebang if it exists + if (text.indexOf("#!") === 0) { + offset = text.indexOf("\n") + 1; + text = text.substring(offset); + } + // check for a comment + const match = text.match(this.commentRegexp); + if (match === null) { + this.addFailureAt(offset, 0, Rule.FAILURE_STRING); + } else { + // either the third or fourth capture group contains the comment contents + const comment = match[2] !== undefined ? match[2] : match[3]; + if (comment !== undefined && comment.search(this.headerRegexp) < 0) { this.addFailureAt(offset, 0, Rule.FAILURE_STRING); - } else { - // either the third or fourth capture group contains the comment contents - const comment = match[2] ? match[2] : match[3]; - if (comment !== undefined && comment.search(this.headerRegexp) < 0) { - this.addFailureAt(offset, 0, Rule.FAILURE_STRING); - } } } } diff --git a/src/rules/importSpacingRule.ts b/src/rules/importSpacingRule.ts index 2565eb2de7e..32c8569e962 100644 --- a/src/rules/importSpacingRule.ts +++ b/src/rules/importSpacingRule.ts @@ -51,7 +51,7 @@ export class Rule extends Lint.Rules.AbstractRule { class ImportStatementWalker extends Lint.RuleWalker { public visitImportDeclaration(node: ts.ImportDeclaration) { - if (!node.importClause) { + if (node.importClause === undefined) { this.checkModuleWithSideEffect(node); } else { const nodeStart = node.getStart(); diff --git a/src/rules/indentRule.ts b/src/rules/indentRule.ts index 682444384c1..03e0386f862 100644 --- a/src/rules/indentRule.ts +++ b/src/rules/indentRule.ts @@ -103,7 +103,7 @@ class IndentWalker extends Lint.RuleWalker { } const commentRanges = ts.getTrailingCommentRanges(node.text, lineStart); - if (commentRanges) { + if (commentRanges !== undefined) { endOfComment = commentRanges[commentRanges.length - 1].end; } else { let scanType = currentScannedType; @@ -135,7 +135,7 @@ class IndentWalker extends Lint.RuleWalker { continue; } - if (fullLeadingWhitespace.match(this.regExp)) { + if (this.regExp.test(fullLeadingWhitespace)) { this.addFailureAt(lineStart, fullLeadingWhitespace.length, this.failureString); } } diff --git a/src/rules/interfaceNameRule.ts b/src/rules/interfaceNameRule.ts index 8d43abd2de1..73f279cfa36 100644 --- a/src/rules/interfaceNameRule.ts +++ b/src/rules/interfaceNameRule.ts @@ -55,7 +55,7 @@ class NameWalker extends Lint.RuleWalker { public visitInterfaceDeclaration(node: ts.InterfaceDeclaration) { const interfaceName = node.name.text; - const always = this.hasOption(OPTION_ALWAYS) || (this.getOptions() && this.getOptions().length === 0); + const always = this.hasOption(OPTION_ALWAYS) || (this.getOptions() !== undefined && this.getOptions().length === 0); if (always) { if (!this.startsWithI(interfaceName)) { diff --git a/src/rules/matchDefaultExportNameRule.ts b/src/rules/matchDefaultExportNameRule.ts index 16839488348..4dbc9789275 100644 --- a/src/rules/matchDefaultExportNameRule.ts +++ b/src/rules/matchDefaultExportNameRule.ts @@ -52,7 +52,7 @@ class Walker extends Lint.ProgramAwareRuleWalker { } const { importClause } = statement as ts.ImportDeclaration; - if (importClause && importClause.name) { + if (importClause !== undefined && importClause.name !== undefined) { this.checkDefaultImport(importClause.name); } } @@ -61,8 +61,12 @@ class Walker extends Lint.ProgramAwareRuleWalker { private checkDefaultImport(defaultImport: ts.Identifier) { const { declarations } = this.getTypeChecker().getAliasedSymbol( this.getTypeChecker().getSymbolAtLocation(defaultImport)); - const name = declarations && declarations[0] && declarations[0].name; - if (name && name.kind === ts.SyntaxKind.Identifier && defaultImport.text !== name.text) { + if (declarations === undefined || declarations[0] === undefined) { + return; + } + + const name = declarations[0].name; + if (name !== undefined && name.kind === ts.SyntaxKind.Identifier && defaultImport.text !== name.text) { this.addFailureAtNode(defaultImport, Rule.FAILURE_STRING(defaultImport.text, name.text)); } } diff --git a/src/rules/memberAccessRule.ts b/src/rules/memberAccessRule.ts index 321ddd6f2dc..695e1e364b6 100644 --- a/src/rules/memberAccessRule.ts +++ b/src/rules/memberAccessRule.ts @@ -112,8 +112,10 @@ function walk(ctx: Lint.WalkContext, noPublic: boolean, checkAccessor: boo ctx.addFailureAtNode(publicKeyword, Rule.FAILURE_STRING_NO_PUBLIC); } if (!noPublic && !isPublic) { - const nameNode = isConstructorDeclaration(node) ? getChildOfKind(node, ts.SyntaxKind.ConstructorKeyword)! : node.name || node; - const memberName = node.name && isIdentifier(node.name) ? node.name.text : undefined; + const nameNode = isConstructorDeclaration(node) + ? getChildOfKind(node, ts.SyntaxKind.ConstructorKeyword)! + : node.name !== undefined ? node.name : node; + const memberName = node.name !== undefined && isIdentifier(node.name) ? node.name.text : undefined; ctx.addFailureAtNode(nameNode, Rule.FAILURE_STRING_FACTORY(memberType(node), memberName)); } } diff --git a/src/rules/memberOrderingRule.ts b/src/rules/memberOrderingRule.ts index b09998fb2f2..b03f8bd3d5b 100644 --- a/src/rules/memberOrderingRule.ts +++ b/src/rules/memberOrderingRule.ts @@ -244,7 +244,7 @@ export class MemberOrderingWalker extends Lint.RuleWalker { `Instead, this should come ${locationHint}.`; this.addFailureAtNode(member, errorLine1); } else { - if (this.opts.alphabetize && member.name) { + if (this.opts.alphabetize && member.name !== undefined) { if (rank !== prevRank) { // No alphabetical ordering between different ranks prevName = undefined; @@ -268,7 +268,7 @@ export class MemberOrderingWalker extends Lint.RuleWalker { /** Finds the lowest name higher than 'targetName'. */ private findLowerName(members: Member[], targetRank: Rank, targetName: string): string { for (const member of members) { - if (!member.name || this.memberRank(member) !== targetRank) { + if (member.name === undefined || this.memberRank(member) !== targetRank) { continue; } const name = nameString(member.name); @@ -397,7 +397,7 @@ function getOptionsJson(allOptions: any[]): { order: MemberCategoryJson[], alpha return { order: convertFromOldStyleOptions(allOptions), alphabetize: false }; // presume allOptions to be string[] } - return { order: categoryFromOption(firstOption[OPTION_ORDER]), alphabetize: !!firstOption[OPTION_ALPHABETIZE] }; + return { order: categoryFromOption(firstOption[OPTION_ORDER]), alphabetize: firstOption[OPTION_ALPHABETIZE] === true }; } function categoryFromOption(orderOption: {}): MemberCategoryJson[] { if (Array.isArray(orderOption)) { @@ -405,7 +405,7 @@ function categoryFromOption(orderOption: {}): MemberCategoryJson[] { } const preset = PRESETS.get(orderOption as string); - if (!preset) { + if (preset === undefined) { throw new Error(`Bad order: ${JSON.stringify(orderOption)}`); } return preset; @@ -459,7 +459,11 @@ function splitOldStyleOptions(categories: NameAndKinds[], filter: (name: string) } function isFunctionLiteral(node: ts.Node | undefined) { - switch (node && node.kind) { + if (node === undefined) { + return false; + } + + switch (node.kind) { case ts.SyntaxKind.ArrowFunction: case ts.SyntaxKind.FunctionExpression: return true; diff --git a/src/rules/newlineBeforeReturnRule.ts b/src/rules/newlineBeforeReturnRule.ts index 0df299f8814..07475310798 100644 --- a/src/rules/newlineBeforeReturnRule.ts +++ b/src/rules/newlineBeforeReturnRule.ts @@ -62,7 +62,7 @@ class NewlineBeforeReturnWalker extends Lint.AbstractWalker { let start = node.getStart(this.sourceFile); let line = ts.getLineAndCharacterOfPosition(this.sourceFile, start).line; const comments = ts.getLeadingCommentRanges(this.sourceFile.text, node.pos); - if (comments) { + if (comments !== undefined) { // check for blank lines between comments for (let i = comments.length - 1; i >= 0; --i) { const endLine = ts.getLineAndCharacterOfPosition(this.sourceFile, comments[i].end).line; diff --git a/src/rules/noBooleanLiteralCompareRule.ts b/src/rules/noBooleanLiteralCompareRule.ts index 73df31152ab..797036b975c 100644 --- a/src/rules/noBooleanLiteralCompareRule.ts +++ b/src/rules/noBooleanLiteralCompareRule.ts @@ -91,7 +91,7 @@ function needsParenthesesForNegate(node: ts.Expression) { function deconstructComparison(node: ts.BinaryExpression): { negate: boolean, expression: ts.Expression } | undefined { const { left, operatorToken, right } = node; const eq = Lint.getEqualsKind(operatorToken); - if (!eq) { + if (eq === undefined) { return undefined; } diff --git a/src/rules/noConsecutiveBlankLinesRule.ts b/src/rules/noConsecutiveBlankLinesRule.ts index 2d1321065d8..4a31ca92bab 100644 --- a/src/rules/noConsecutiveBlankLinesRule.ts +++ b/src/rules/noConsecutiveBlankLinesRule.ts @@ -53,12 +53,15 @@ export class Rule extends Lint.Rules.AbstractRule { */ public isEnabled(): boolean { return super.isEnabled() && - (!this.ruleArguments[0] || + (this.ruleArguments[0] === undefined || typeof this.ruleArguments[0] === "number" && this.ruleArguments[0] > 0); } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { - const limit: number = this.ruleArguments[0] || Rule.DEFAULT_ALLOWED_BLANKS; + let limit: number = this.ruleArguments[0]; + if (limit === undefined) { + limit = Rule.DEFAULT_ALLOWED_BLANKS; + } return this.applyWithFunction(sourceFile, walk, limit); } } diff --git a/src/rules/noDuplicateSuperRule.ts b/src/rules/noDuplicateSuperRule.ts index a349d47bc0c..14c6a90eb83 100644 --- a/src/rules/noDuplicateSuperRule.ts +++ b/src/rules/noDuplicateSuperRule.ts @@ -44,7 +44,7 @@ export class Rule extends Lint.Rules.AbstractRule { class Walker extends Lint.RuleWalker { /** Whether we've seen 'super()' yet in the current constructor. */ public visitConstructorDeclaration(node: ts.ConstructorDeclaration) { - if (!node.body) { + if (node.body === undefined) { return; } @@ -84,7 +84,9 @@ class Walker extends Lint.RuleWalker { case ts.SyntaxKind.IfStatement: { const { thenStatement, elseStatement } = node as ts.IfStatement; - return worse(this.getSuperForNode(thenStatement), elseStatement ? this.getSuperForNode(elseStatement) : Kind.NoSuper); + return worse( + this.getSuperForNode(thenStatement), + elseStatement !== undefined ? this.getSuperForNode(elseStatement) : Kind.NoSuper); } case ts.SyntaxKind.SwitchStatement: @@ -114,7 +116,7 @@ class Walker extends Lint.RuleWalker { return Kind.NoSuper; default: - if (fallthroughSingle) { + if (fallthroughSingle !== undefined) { this.addDuplicateFailure(fallthroughSingle, clauseSuper.node); } if (!clauseSuper.break) { @@ -125,7 +127,7 @@ class Walker extends Lint.RuleWalker { } } - return foundSingle ? { node: foundSingle, break: false } : Kind.NoSuper; + return foundSingle !== undefined ? { node: foundSingle, break: false } : Kind.NoSuper; } /** @@ -141,7 +143,7 @@ class Walker extends Lint.RuleWalker { return; case Kind.Break: - if (seenSingle) { + if (seenSingle !== undefined) { return { ...seenSingle, break: true }; } return childSuper; @@ -150,14 +152,14 @@ class Walker extends Lint.RuleWalker { return childSuper; default: - if (seenSingle && !seenSingle.break) { + if (seenSingle !== undefined && !seenSingle.break) { this.addDuplicateFailure(seenSingle.node, childSuper.node); } seenSingle = childSuper; return; } }); - return res || seenSingle || Kind.NoSuper; + return res !== undefined ? res : seenSingle !== undefined ? seenSingle : Kind.NoSuper; } private addDuplicateFailure(a: ts.Node, b: ts.Node) { diff --git a/src/rules/noEmptyInterfaceRule.ts b/src/rules/noEmptyInterfaceRule.ts index fe29e91b491..2a13f2cf38c 100644 --- a/src/rules/noEmptyInterfaceRule.ts +++ b/src/rules/noEmptyInterfaceRule.ts @@ -47,7 +47,7 @@ class Walker extends Lint.RuleWalker { node.heritageClauses[0].types === undefined || // allow interfaces that extend 2 or more interfaces node.heritageClauses[0].types!.length < 2)) { - this.addFailureAtNode(node.name, node.heritageClauses ? Rule.FAILURE_STRING_FOR_EXTENDS : Rule.FAILURE_STRING); + this.addFailureAtNode(node.name, node.heritageClauses !== undefined ? Rule.FAILURE_STRING_FOR_EXTENDS : Rule.FAILURE_STRING); } } } diff --git a/src/rules/noFloatingPromisesRule.ts b/src/rules/noFloatingPromisesRule.ts index 15b7cf8ccd1..a8ba4bee353 100644 --- a/src/rules/noFloatingPromisesRule.ts +++ b/src/rules/noFloatingPromisesRule.ts @@ -79,7 +79,7 @@ class NoFloatingPromisesWalker extends Lint.ProgramAwareRuleWalker { } private checkNode(node: ts.CallExpression | ts.ExpressionStatement) { - if (node.parent && this.kindCanContainPromise(node.parent.kind)) { + if (node.parent !== undefined && this.kindCanContainPromise(node.parent.kind)) { return; } @@ -92,7 +92,7 @@ class NoFloatingPromisesWalker extends Lint.ProgramAwareRuleWalker { } private symbolIsPromise(symbol?: ts.Symbol) { - if (!symbol) { + if (symbol === undefined) { return false; } diff --git a/src/rules/noForInArrayRule.ts b/src/rules/noForInArrayRule.ts index 3893655600c..1e1cda8555c 100644 --- a/src/rules/noForInArrayRule.ts +++ b/src/rules/noForInArrayRule.ts @@ -60,10 +60,8 @@ class NoForInArrayWalker extends Lint.ProgramAwareRuleWalker { const tc = this.getTypeChecker(); const type = tc.getTypeAtLocation(iteratee); - /* tslint:disable:no-bitwise */ - const isArrayType = type.symbol && type.symbol.name === "Array"; - const isStringType = (type.flags & ts.TypeFlags.StringLike) !== 0; - /* tslint:enable:no-bitwise */ + const isArrayType = type.symbol !== undefined && type.symbol.name === "Array"; + const isStringType = Lint.isTypeFlagSet(type, ts.TypeFlags.StringLike); if (isArrayType || isStringType) { this.addFailureAtNode(node, Rule.FAILURE_STRING); diff --git a/src/rules/noImportSideEffectRule.ts b/src/rules/noImportSideEffectRule.ts index 1153361ab5a..e8b7a69baa1 100644 --- a/src/rules/noImportSideEffectRule.ts +++ b/src/rules/noImportSideEffectRule.ts @@ -52,7 +52,7 @@ export class Rule extends Lint.Rules.AbstractRule { public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { const patternConfig = this.ruleArguments[this.ruleArguments.length - 1]; - const ignorePattern = patternConfig && new RegExp(patternConfig[OPTION_IGNORE_MODULE]); + const ignorePattern = patternConfig === undefined ? undefined : new RegExp(patternConfig[OPTION_IGNORE_MODULE]); return this.applyWithFunction(sourceFile, walk, ignorePattern); } } @@ -65,11 +65,11 @@ function walk(ctx: Lint.WalkContext): void { } const { importClause, moduleSpecifier } = statement; - if (importClause || !utils.isStringLiteral(moduleSpecifier)) { + if (importClause !== undefined || !utils.isStringLiteral(moduleSpecifier)) { continue; } - if (!ignorePattern || !ignorePattern.test(moduleSpecifier.text)) { + if (ignorePattern === undefined || !ignorePattern.test(moduleSpecifier.text)) { ctx.addFailureAtNode(statement, Rule.FAILURE_STRING); } } diff --git a/src/rules/noMergeableNamespaceRule.ts b/src/rules/noMergeableNamespaceRule.ts index 09bdbb362a9..ce03cd9ee66 100644 --- a/src/rules/noMergeableNamespaceRule.ts +++ b/src/rules/noMergeableNamespaceRule.ts @@ -59,7 +59,7 @@ class Walker extends Lint.RuleWalker { if (name.kind === ts.SyntaxKind.Identifier) { const { text } = name; const prev = seen.get(text); - if (prev) { + if (prev !== undefined) { this.addFailureAtNode(name, Rule.failureStringFactory(text, this.getLineOfNode(prev))); } seen.set(text, statement as ts.NamespaceDeclaration); @@ -72,7 +72,7 @@ class Walker extends Lint.RuleWalker { private checkModuleDeclaration(decl: ts.ModuleDeclaration): void { const { body } = decl; - if (!body) { + if (body === undefined) { return; } diff --git a/src/rules/noReferenceImportRule.ts b/src/rules/noReferenceImportRule.ts index 6e62f75ad75..e1c07a8efbe 100644 --- a/src/rules/noReferenceImportRule.ts +++ b/src/rules/noReferenceImportRule.ts @@ -66,7 +66,7 @@ function allImports(sourceFile: ts.SourceFile): Set { if (utils.isImportEqualsDeclaration(node)) { const ref = node.moduleReference; if (ref.kind === ts.SyntaxKind.ExternalModuleReference) { - if (ref.expression) { + if (ref.expression !== undefined) { addImport(ref.expression); } } @@ -79,7 +79,7 @@ function allImports(sourceFile: ts.SourceFile): Set { } const body = moduleDeclarationBody(node); - if (body) { + if (body !== undefined) { for (const statement of body.statements) { recur(statement); } @@ -96,8 +96,8 @@ function allImports(sourceFile: ts.SourceFile): Set { function moduleDeclarationBody(node: ts.ModuleDeclaration): ts.ModuleBlock | undefined { let body = node.body; - while (body && body.kind === ts.SyntaxKind.ModuleDeclaration) { + while (body !== undefined && body.kind === ts.SyntaxKind.ModuleDeclaration) { body = body.body; } - return body && body.kind === ts.SyntaxKind.ModuleBlock ? body : undefined; + return body !== undefined && body.kind === ts.SyntaxKind.ModuleBlock ? body : undefined; } diff --git a/src/rules/noUnboundMethodRule.ts b/src/rules/noUnboundMethodRule.ts index b5b64f02599..4854e086bcd 100644 --- a/src/rules/noUnboundMethodRule.ts +++ b/src/rules/noUnboundMethodRule.ts @@ -43,8 +43,8 @@ class Walker extends Lint.ProgramAwareRuleWalker { public visitPropertyAccessExpression(node: ts.PropertyAccessExpression) { if (!isSafeUse(node)) { const symbol = this.getTypeChecker().getSymbolAtLocation(node); - const declaration = symbol && symbol.valueDeclaration; - if (declaration && isMethod(declaration)) { + const declaration = symbol === undefined ? undefined : symbol.valueDeclaration; + if (declaration !== undefined && isMethod(declaration)) { this.addFailureAtNode(node, Rule.FAILURE_STRING); } } diff --git a/src/rules/noUnnecessaryCallbackWrapperRule.ts b/src/rules/noUnnecessaryCallbackWrapperRule.ts index f47447b4813..7d5b086b49f 100644 --- a/src/rules/noUnnecessaryCallbackWrapperRule.ts +++ b/src/rules/noUnnecessaryCallbackWrapperRule.ts @@ -48,7 +48,7 @@ function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, cb); function cb(node: ts.Node): void { const fn = detectRedundantCallback(node); - if (fn) { + if (fn !== undefined) { const fix = ctx.createFix( Lint.Replacement.deleteFromTo(node.getStart(), fn.getStart()), Lint.Replacement.deleteFromTo(fn.getEnd(), node.getEnd())); @@ -78,9 +78,11 @@ function detectRedundantCallback(node: ts.Node): ts.Expression | undefined { return undefined; } + // Bug in `strict-boolean-expressions` fixed in TSLint 5.0, remove this disable then. + // tslint:disable strict-boolean-expressions const argumentsSameAsParameters = parameters.length === args.length && parameters.every(({dotDotDotToken, name}, i) => { let arg = args[i]; - if (dotDotDotToken) { + if (dotDotDotToken !== undefined) { // Use SpreadElementExpression for ts2.0 compatibility if (!(isSpreadElement(arg) || arg.kind === (ts.SyntaxKind as any).SpreadElementExpression)) { return false; diff --git a/src/rules/noUnnecessaryInitializerRule.ts b/src/rules/noUnnecessaryInitializerRule.ts index c3fda70d632..d8bda8f195e 100644 --- a/src/rules/noUnnecessaryInitializerRule.ts +++ b/src/rules/noUnnecessaryInitializerRule.ts @@ -101,10 +101,10 @@ class Walker extends Lint.RuleWalker { function parametersAllOptionalAfter(parameters: ts.ParameterDeclaration[], idx: number): boolean { for (let i = idx + 1; i < parameters.length; i++) { - if (parameters[i].questionToken) { + if (parameters[i].questionToken !== undefined) { return true; } - if (!parameters[i].initializer) { + if (parameters[i].initializer === undefined) { return false; } } diff --git a/src/rules/noUnsafeFinallyRule.ts b/src/rules/noUnsafeFinallyRule.ts index 6c84729b15b..b79deba6403 100644 --- a/src/rules/noUnsafeFinallyRule.ts +++ b/src/rules/noUnsafeFinallyRule.ts @@ -157,7 +157,7 @@ class NoReturnInFinallyScopeAwareWalker extends Lint.ScopeAwareRuleWalker= 0 : scope.isContinueBoundary; + return node.label !== undefined ? scope.labels.indexOf(node.label.text) >= 0 : scope.isContinueBoundary; } function isBreakBoundary(scope: IFinallyScope, node: ts.BreakStatement): boolean { - return node.label ? scope.labels.indexOf(node.label.text) >= 0 : scope.isBreakBoundary; + return node.label !== undefined ? scope.labels.indexOf(node.label.text) >= 0 : scope.isBreakBoundary; } diff --git a/src/rules/noUnusedVariableRule.ts b/src/rules/noUnusedVariableRule.ts index d897af528cf..4b58dc90a7c 100644 --- a/src/rules/noUnusedVariableRule.ts +++ b/src/rules/noUnusedVariableRule.ts @@ -64,7 +64,7 @@ export class Rule extends Lint.Rules.TypedRule { public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] { const x = program.getCompilerOptions(); - if (x.noUnusedLocals && x.noUnusedParameters) { + if (x.noUnusedLocals === true && x.noUnusedParameters === true) { console.warn("WARNING: 'no-unused-variable' lint rule does not need to be set if " + "the 'no-unused-locals' and 'no-unused-parameters' compiler options are enabled."); } @@ -123,7 +123,7 @@ function walk(ctx: Lint.WalkContext, program: ts.Program, { checkParameter } } - if (ignorePattern) { + if (ignorePattern !== undefined) { const varName = /'(.*)'/.exec(failure)![1]; if (ignorePattern.test(varName)) { continue; @@ -133,7 +133,7 @@ function walk(ctx: Lint.WalkContext, program: ts.Program, { checkParameter ctx.addFailureAt(diag.start, diag.length, failure); } - if (importSpecifierFailures.size) { + if (importSpecifierFailures.size !== 0) { addImportSpecifierFailures(ctx, importSpecifierFailures, sourceFile); } } @@ -150,43 +150,43 @@ function addImportSpecifierFailures(ctx: Lint.WalkContext, failures: Map failures.has(e.name)); - if (namedBindings && allNamedBindingsAreFailures) { + const allNamedBindingsAreFailures = namedBindings === undefined || namedBindings.elements.every((e) => failures.has(e.name)); + if (namedBindings !== undefined && allNamedBindingsAreFailures) { for (const e of namedBindings.elements) { failures.delete(e.name); } } - if ((!defaultName || failures.has(defaultName)) && allNamedBindingsAreFailures) { - if (defaultName) { failures.delete(defaultName); } + if ((defaultName === undefined || failures.has(defaultName)) && allNamedBindingsAreFailures) { + if (defaultName !== undefined) { failures.delete(defaultName); } removeAll(importNode, "All imports are unused."); return; } - if (defaultName) { + if (defaultName !== undefined) { const failure = tryDelete(defaultName); if (failure !== undefined) { const start = defaultName.getStart(); - const end = namedBindings ? namedBindings.getStart() : importNode.moduleSpecifier.getStart(); + const end = namedBindings !== undefined ? namedBindings.getStart() : importNode.moduleSpecifier.getStart(); const fix = ctx.createFix(Lint.Replacement.deleteFromTo(start, end)); ctx.addFailureAtNode(defaultName, failure, fix); } } - if (namedBindings) { + if (namedBindings !== undefined) { if (allNamedBindingsAreFailures) { - const start = defaultName ? defaultName.getEnd() : namedBindings.getStart(); + const start = defaultName !== undefined ? defaultName.getEnd() : namedBindings.getStart(); const fix = ctx.createFix(Lint.Replacement.deleteFromTo(start, namedBindings.getEnd())); const failure = "All named bindings are unused."; ctx.addFailureAtNode(namedBindings, failure, fix); @@ -201,8 +201,8 @@ function addImportSpecifierFailures(ctx: Lint.WalkContext, failures: Map, failures: Map, failures: Map(); function getUnusedCheckedProgram(program: ts.Program, checkParameters: boolean): ts.Program { // Assuming checkParameters will always have the same value, so only lookup by program. let checkedProgram = programToUnusedCheckedProgram.get(program); - if (checkedProgram) { + if (checkedProgram !== undefined) { return checkedProgram; } diff --git a/src/rules/noUseBeforeDeclareRule.ts b/src/rules/noUseBeforeDeclareRule.ts index 8d0d438ef12..903357343fa 100644 --- a/src/rules/noUseBeforeDeclareRule.ts +++ b/src/rules/noUseBeforeDeclareRule.ts @@ -65,12 +65,11 @@ function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker): void { }); function checkIdentifier(node: ts.Identifier, symbol: ts.Symbol | undefined): void { - const declarations = symbol && symbol.declarations; - if (!declarations) { + if (symbol === undefined || symbol.declarations === undefined) { return; } - const declaredBefore = declarations.some((decl) => { + const declaredBefore = symbol.declarations.some((decl) => { switch (decl.kind) { case ts.SyntaxKind.FunctionDeclaration: // Functions may be declared later. diff --git a/src/rules/noVarKeywordRule.ts b/src/rules/noVarKeywordRule.ts index f58fc27dae7..933e998b5aa 100644 --- a/src/rules/noVarKeywordRule.ts +++ b/src/rules/noVarKeywordRule.ts @@ -68,7 +68,7 @@ class NoVarKeywordWalker extends Lint.RuleWalker { } private handleInitializerNode(node: ts.VariableDeclarationList | ts.Expression | undefined) { - if (node && node.kind === ts.SyntaxKind.VariableDeclarationList && + if (node !== undefined && node.kind === ts.SyntaxKind.VariableDeclarationList && !(Lint.isNodeFlagSet(node, ts.NodeFlags.Let) || Lint.isNodeFlagSet(node, ts.NodeFlags.Const))) { this.reportFailure(node); } diff --git a/src/rules/objectLiteralKeyQuotesRule.ts b/src/rules/objectLiteralKeyQuotesRule.ts index d2609713481..deaddf3860d 100644 --- a/src/rules/objectLiteralKeyQuotesRule.ts +++ b/src/rules/objectLiteralKeyQuotesRule.ts @@ -84,7 +84,10 @@ class ObjectLiteralKeyQuotesWalker extends Lint.RuleWalker { constructor(sourceFile: ts.SourceFile, options: Lint.IOptions) { super(sourceFile, options); - this.mode = this.getOptions()[0] || "always"; + this.mode = this.getOptions()[0]; + if (this.mode === undefined) { + this.mode = "always"; + } } public visitObjectLiteralExpression(node: ts.ObjectLiteralExpression) { @@ -128,7 +131,7 @@ class ObjectLiteralKeyQuotesWalker extends Lint.RuleWalker { } } - private noneMayHaveQuotes(properties: ts.ObjectLiteralElementLike[], noneNeedQuotes?: boolean) { + private noneMayHaveQuotes(properties: ts.ObjectLiteralElementLike[], noneNeedQuotes = false) { for (const { name } of properties) { if (name !== undefined && name.kind === ts.SyntaxKind.StringLiteral && (noneNeedQuotes || !propertyNeedsQuotes(name.text))) { const fix = this.createFix(this.deleteText(name.getStart(), 1), this.deleteText(name.getEnd() - 1, 1)); diff --git a/src/rules/objectLiteralShorthandRule.ts b/src/rules/objectLiteralShorthandRule.ts index 1f4f1d95048..b4264decc36 100644 --- a/src/rules/objectLiteralShorthandRule.ts +++ b/src/rules/objectLiteralShorthandRule.ts @@ -60,10 +60,10 @@ class ObjectLiteralShorthandWalker extends Lint.RuleWalker { if (value.kind === ts.SyntaxKind.FunctionExpression) { const fnNode = value as ts.FunctionExpression; - if (fnNode.name) { + if (fnNode.name !== undefined) { return; // named function expressions are OK. } - const star = fnNode.asteriskToken ? fnNode.asteriskToken.getText() : ""; + const star = fnNode.asteriskToken !== undefined ? fnNode.asteriskToken.getText() : ""; this.addFailureAtNode(node, Rule.LONGHAND_METHOD + `('{${name.getText()}${star}() {...}}').`); } diff --git a/src/rules/oneLineRule.ts b/src/rules/oneLineRule.ts index 89304f96cc0..13a2d5b7910 100644 --- a/src/rules/oneLineRule.ts +++ b/src/rules/oneLineRule.ts @@ -299,7 +299,7 @@ class OneLineWalker extends Lint.RuleWalker { failure = Rule.WHITESPACE_FAILURE_STRING; } - if (failure) { + if (failure !== undefined) { this.addFailureAtNode(openBraceToken, failure); } } diff --git a/src/rules/onlyArrowFunctionsRule.ts b/src/rules/onlyArrowFunctionsRule.ts index 86934595f4b..59ed5053661 100644 --- a/src/rules/onlyArrowFunctionsRule.ts +++ b/src/rules/onlyArrowFunctionsRule.ts @@ -88,13 +88,13 @@ class OnlyArrowFunctionsWalker extends Lint.RuleWalker { } /** Generator functions and functions using `this` are allowed. */ -function functionIsExempt(node: ts.FunctionLikeDeclaration) { - return node.asteriskToken || hasThisParameter(node) || node.body && usesThisInBody(node.body); +function functionIsExempt(node: ts.FunctionLikeDeclaration): boolean { + return node.asteriskToken !== undefined || hasThisParameter(node) || node.body !== undefined && usesThisInBody(node.body); } -function hasThisParameter(node: ts.FunctionLikeDeclaration) { +function hasThisParameter(node: ts.FunctionLikeDeclaration): boolean { const first = node.parameters[0]; - return first && first.name.kind === ts.SyntaxKind.Identifier && + return first !== undefined && first.name.kind === ts.SyntaxKind.Identifier && (first.name as ts.Identifier).originalKeywordKind === ts.SyntaxKind.ThisKeyword; } diff --git a/src/rules/orderedImportsRule.ts b/src/rules/orderedImportsRule.ts index 3a69ea1bf53..ec2250f1884 100644 --- a/src/rules/orderedImportsRule.ts +++ b/src/rules/orderedImportsRule.ts @@ -130,7 +130,7 @@ function compare(a: string, b: string) { function removeQuotes(value: string) { // strip out quotes - if (value && value.length > 1 && (value[0] === "'" || value[0] === "\"")) { + if (value.length > 1 && (value[0] === "'" || value[0] === "\"")) { value = value.substr(1, value.length - 2); } return value; @@ -161,11 +161,19 @@ class OrderedImportsWalker extends Lint.RuleWalker { constructor(sourceFile: ts.SourceFile, options: Lint.IOptions) { super(sourceFile, options); - const optionSet = this.getOptions()[0] || {}; - this.importSourcesOrderTransform = - TRANSFORMS[optionSet["import-sources-order"] || "case-insensitive"]; - this.namedImportsOrderTransform = - TRANSFORMS[optionSet["named-imports-order"] || "case-insensitive"]; + const optionSet = this.getOptions()[0]; + if (optionSet !== undefined) { + this.importSourcesOrderTransform = + TRANSFORMS[optionSet["import-sources-order"]]; + this.namedImportsOrderTransform = + TRANSFORMS[optionSet["named-imports-order"]]; + } + if (this.importSourcesOrderTransform === undefined) { + this.importSourcesOrderTransform = TRANSFORMS["case-insensitive"]; + } + if (this.namedImportsOrderTransform === undefined) { + this.namedImportsOrderTransform = TRANSFORMS["case-insensitive"]; + } } // e.g. "import Foo from "./foo";" @@ -176,7 +184,7 @@ class OrderedImportsWalker extends Lint.RuleWalker { const previousSource = this.currentImportsBlock.getLastImportSource(); this.currentImportsBlock.addImportDeclaration(this.getSourceFile(), node, source); - if (previousSource && compare(source, previousSource) === -1) { + if (previousSource !== null && compare(source, previousSource) === -1) { this.lastFix = this.createFix(); this.addFailureAtNode(node, Rule.IMPORT_SOURCES_UNORDERED, this.lastFix); } diff --git a/src/rules/preferConstRule.ts b/src/rules/preferConstRule.ts index 735e0f59d82..79f6f81b8f5 100644 --- a/src/rules/preferConstRule.ts +++ b/src/rules/preferConstRule.ts @@ -37,7 +37,7 @@ export class Rule extends Lint.Rules.AbstractRule { hasFix: true, optionsDescription: Lint.Utils.dedent` An optional object containing the property "destructuring" with two possible values: - + * "${OPTION_DESTRUCTURING_ANY}" (default) - If any variable in destructuring can be const, this rule warns for those variables. * "${OPTION_DESTRUCTURING_ALL}" - Only warns if all variables in destructuring can be const.`, options: { @@ -78,7 +78,7 @@ class Scope { public reassigned = new Set(); constructor(functionScope?: Scope) { // if no functionScope is provided we are in the process of creating a new function scope, which for consistency links to itself - this.functionScope = functionScope || this; + this.functionScope = functionScope === undefined ? this : functionScope; } public addVariable(identifier: ts.Identifier, declarationInfo: DeclarationInfo, destructuringInfo?: DestructuringInfo) { @@ -174,7 +174,7 @@ class PreferConstWalker extends Lint.AbstractWalker { this.handleExpression(node.left); } - if (boundary) { + if (boundary !== utils.ScopeBoundary.None) { ts.forEachChild(node, cb); this.onScopeEnd(savedScope); this.scope = savedScope; diff --git a/src/rules/preferFunctionOverMethodRule.ts b/src/rules/preferFunctionOverMethodRule.ts index ac518c1e89f..9ceb03ef0b1 100644 --- a/src/rules/preferFunctionOverMethodRule.ts +++ b/src/rules/preferFunctionOverMethodRule.ts @@ -66,12 +66,12 @@ class PreferFunctionOverMethodWalker extends Lint.AbstractWalker { const cb = (node: ts.Node): void => { if (isMethodDeclaration(node) && !this.isExempt(node)) { // currentScope is always undefined here, so we don't need to save it and just set it to undefined afterwards - const scope = this.currentScope = { + this.currentScope = { isThisUsed: false, name: getPropertyName(node.name), }; ts.forEachChild(node, cb); - if (!scope.isThisUsed) { + if (!this.currentScope.isThisUsed) { this.addFailureAtNode(node.name, Rule.FAILURE_STRING); } this.currentScope = undefined; diff --git a/src/rules/preferMethodSignatureRule.ts b/src/rules/preferMethodSignatureRule.ts index 9ab1c93410c..52e91698f67 100644 --- a/src/rules/preferMethodSignatureRule.ts +++ b/src/rules/preferMethodSignatureRule.ts @@ -51,7 +51,7 @@ class Walker extends Lint.RuleWalker { } private createMethodSignatureFix(node: ts.PropertyDeclaration, type: ts.FunctionTypeNode): Lint.Fix | undefined { - return type.type && this.createFix( + return type.type === undefined ? undefined : this.createFix( this.deleteFromTo(Lint.childOfKind(node, ts.SyntaxKind.ColonToken)!.getStart(), type.getStart()), this.deleteFromTo(Lint.childOfKind(type, ts.SyntaxKind.EqualsGreaterThanToken)!.getStart(), type.type.getStart()), this.appendText(Lint.childOfKind(type, ts.SyntaxKind.CloseParenToken)!.end, ":")); diff --git a/src/rules/preferTemplateRule.ts b/src/rules/preferTemplateRule.ts index 72077ba4229..f5a769d9b2f 100644 --- a/src/rules/preferTemplateRule.ts +++ b/src/rules/preferTemplateRule.ts @@ -55,7 +55,7 @@ export class Rule extends Lint.Rules.AbstractRule { function walk(ctx: Lint.WalkContext, allowSingleConcat: boolean): void { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { const failure = getError(node, allowSingleConcat); - if (failure) { + if (failure !== undefined) { ctx.addFailureAtNode(node, failure); } else { return ts.forEachChild(node, cb); diff --git a/src/rules/returnUndefinedRule.ts b/src/rules/returnUndefinedRule.ts index 42cbae8557e..1f274857bfa 100644 --- a/src/rules/returnUndefinedRule.ts +++ b/src/rules/returnUndefinedRule.ts @@ -62,7 +62,7 @@ function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker) { } const functionReturningFrom = Lint.ancestorWhere(node, isFunctionLike) as FunctionLike | undefined; - if (!functionReturningFrom) { + if (functionReturningFrom === undefined) { // Return outside of function is invalid return; } @@ -76,7 +76,7 @@ function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker) { } function returnKindFromReturn(node: ts.ReturnStatement): ReturnKind | undefined { - if (!node.expression) { + if (node.expression === undefined) { return ReturnKind.Void; } else if (u.isIdentifier(node.expression) && node.expression.text === "undefined") { return ReturnKind.Value; @@ -110,7 +110,7 @@ function getReturnKind(node: FunctionLike, checker: ts.TypeChecker): ReturnKind } // Go with an explicit type declaration if possible. - if (node.type) { + if (node.type !== undefined) { return node.type.kind === ts.SyntaxKind.VoidKeyword ? ReturnKind.Void : ReturnKind.Value; } @@ -118,8 +118,8 @@ function getReturnKind(node: FunctionLike, checker: ts.TypeChecker): ReturnKind ? checker.getContextualType(node) : undefined; - const ty = contextualType || checker.getTypeAtLocation(node); - if (!ty) { + const ty = contextualType !== undefined ? contextualType : checker.getTypeAtLocation(node); + if (ty === undefined) { // Type error somewhere. Bail. return undefined; } diff --git a/src/rules/semicolonRule.ts b/src/rules/semicolonRule.ts index 3b2f6496358..7ab5b985e67 100644 --- a/src/rules/semicolonRule.ts +++ b/src/rules/semicolonRule.ts @@ -154,7 +154,7 @@ class SemicolonWalker extends Lint.AbstractWalker { } private isFollowedByLineBreak(pos: number) { - const scanner = this.scanner || + const scanner = this.scanner !== undefined ? this.scanner : (this.scanner = ts.createScanner(this.sourceFile.languageVersion, true, this.sourceFile.languageVariant, this.sourceFile.text)); scanner.setTextPos(pos); return scanner.scan() === ts.SyntaxKind.EndOfFileToken || scanner.hasPrecedingLineBreak(); @@ -208,7 +208,7 @@ class SemicolonWalker extends Lint.AbstractWalker { )); } - private reportUnnecessary(pos: number, noFix?: boolean) { + private reportUnnecessary(pos: number, noFix = false) { this.addFailureAt(pos, 1, Rule.FAILURE_STRING_UNNECESSARY, noFix ? undefined : this.createFix( Lint.Replacement.deleteText(pos, 1), )); diff --git a/src/rules/strictTypePredicatesRule.ts b/src/rules/strictTypePredicatesRule.ts index 421ee4b0ef4..e295b5773ad 100644 --- a/src/rules/strictTypePredicatesRule.ts +++ b/src/rules/strictTypePredicatesRule.ts @@ -57,7 +57,7 @@ export class Rule extends Lint.Rules.TypedRule { class Walker extends Lint.ProgramAwareRuleWalker { public visitBinaryExpression(node: ts.BinaryExpression) { const equals = Lint.getEqualsKind(node.operatorToken); - if (equals) { + if (equals !== undefined) { this.checkEquals(node, equals); } super.visitBinaryExpression(node); @@ -65,7 +65,7 @@ class Walker extends Lint.ProgramAwareRuleWalker { private checkEquals(node: ts.BinaryExpression, { isStrict, isPositive }: Lint.EqualsKind) { const exprPred = getTypePredicate(node, isStrict); - if (!exprPred) { + if (exprPred === undefined) { return; } @@ -114,7 +114,8 @@ class Walker extends Lint.ProgramAwareRuleWalker { /** Detects a type predicate given `left === right`. */ function getTypePredicate(node: ts.BinaryExpression, isStrictEquals: boolean): TypePredicate | undefined { const { left, right } = node; - return getTypePredicateOneWay(left, right, isStrictEquals) || getTypePredicateOneWay(right, left, isStrictEquals); + const lr = getTypePredicateOneWay(left, right, isStrictEquals); + return lr !== undefined ? lr : getTypePredicateOneWay(right, left, isStrictEquals); } /** Only gets the type predicate if the expression is on the left. */ @@ -206,7 +207,7 @@ function isFunction(t: ts.Type): boolean { return true; } const symbol = t.getSymbol(); - return (symbol && symbol.getName()) === "Function"; + return symbol === undefined ? false : symbol.getName() === "Function"; } /** Returns a boolean value if that should always be the result of a type predicate. */ diff --git a/src/rules/trailingCommaRule.ts b/src/rules/trailingCommaRule.ts index 950216a8302..74827aa7be8 100644 --- a/src/rules/trailingCommaRule.ts +++ b/src/rules/trailingCommaRule.ts @@ -148,7 +148,7 @@ class TrailingCommaWalker extends Lint.AbstractWalker { } const token = getChildOfKind(node, closeTokenKind, this.sourceFile); if (token !== undefined) { - return this.checkComma(list.hasTrailingComma, list, token.end); + return this.checkComma(list.hasTrailingComma === true, list, token.end); } } @@ -156,11 +156,11 @@ class TrailingCommaWalker extends Lint.AbstractWalker { if (list.length === 0) { return; } - return this.checkComma(list.hasTrailingComma, list, closeElementPos); + return this.checkComma(list.hasTrailingComma === true, list, closeElementPos); } /* Expects `list.length !== 0` */ - private checkComma(hasTrailingComma: boolean | undefined, list: ts.NodeArray, closeTokenPos: number) { + private checkComma(hasTrailingComma: boolean, list: ts.NodeArray, closeTokenPos: number) { const lastElementLine = ts.getLineAndCharacterOfPosition(this.sourceFile, list[list.length - 1].end).line; const closeTokenLine = ts.getLineAndCharacterOfPosition(this.sourceFile, closeTokenPos).line; const option = lastElementLine === closeTokenLine ? this.options.singleline : this.options.multiline; diff --git a/src/rules/tripleEqualsRule.ts b/src/rules/tripleEqualsRule.ts index 9b69f645058..dca8859ee48 100644 --- a/src/rules/tripleEqualsRule.ts +++ b/src/rules/tripleEqualsRule.ts @@ -62,7 +62,7 @@ class ComparisonWalker extends Lint.RuleWalker { public visitBinaryExpression(node: ts.BinaryExpression) { const eq = Lint.getEqualsKind(node.operatorToken); - if (eq && !eq.isStrict && !this.isExpressionAllowed(node)) { + if (eq !== undefined && !eq.isStrict && !this.isExpressionAllowed(node)) { this.addFailureAtNode(node.operatorToken, eq.isPositive ? Rule.EQ_FAILURE_STRING : Rule.NEQ_FAILURE_STRING); } super.visitBinaryExpression(node); diff --git a/src/rules/typedefRule.ts b/src/rules/typedefRule.ts index 1eaff25b39d..143d708393e 100644 --- a/src/rules/typedefRule.ts +++ b/src/rules/typedefRule.ts @@ -236,7 +236,7 @@ class TypedefWalker extends Lint.RuleWalker { } } -function getName(name?: ts.Node, prefix?: string, suffix?: string): string { +function getName(name?: ts.Node, prefix = "", suffix = ""): string { let ns = ""; if (name != null) { @@ -257,7 +257,7 @@ function getName(name?: ts.Node, prefix?: string, suffix?: string): string { break; } } - return ns ? `${prefix || ""}${ns}${suffix || ""}` : ""; + return ns === "" ? "" : `${prefix}${ns}${suffix}`; } function isTypedPropertyDeclaration(node: ts.Node): boolean { diff --git a/src/rules/typedefWhitespaceRule.ts b/src/rules/typedefWhitespaceRule.ts index 526ef36f484..7120029f967 100644 --- a/src/rules/typedefWhitespaceRule.ts +++ b/src/rules/typedefWhitespaceRule.ts @@ -91,7 +91,7 @@ export class Rule extends Lint.Rules.AbstractRule { class TypedefWhitespaceWalker extends Lint.RuleWalker { private static getColonPosition(node: ts.Node) { const colon = Lint.childOfKind(node, ts.SyntaxKind.ColonToken); - return colon && colon.getStart(); + return colon === undefined ? undefined : colon.getStart(); } public visitFunctionDeclaration(node: ts.FunctionDeclaration) { diff --git a/src/rules/typeofCompareRule.ts b/src/rules/typeofCompareRule.ts index 846b74e272c..1cd651b7d18 100644 --- a/src/rules/typeofCompareRule.ts +++ b/src/rules/typeofCompareRule.ts @@ -45,7 +45,7 @@ export class Rule extends Lint.Rules.AbstractRule { class Walker extends Lint.RuleWalker { public visitBinaryExpression(node: ts.BinaryExpression) { const { operatorToken, left, right } = node; - if (Lint.getEqualsKind(operatorToken) && (isFaultyTypeof(left, right) || isFaultyTypeof(right, left))) { + if (Lint.getEqualsKind(operatorToken) !== undefined && (isFaultyTypeof(left, right) || isFaultyTypeof(right, left))) { this.addFailureAtNode(node, Rule.FAILURE_STRING); } super.visitBinaryExpression(node); diff --git a/src/rules/unifiedSignaturesRule.ts b/src/rules/unifiedSignaturesRule.ts index 2f14483e84a..10adafb3d5b 100644 --- a/src/rules/unifiedSignaturesRule.ts +++ b/src/rules/unifiedSignaturesRule.ts @@ -64,7 +64,7 @@ class Walker extends Lint.RuleWalker { public visitModuleDeclaration(node: ts.ModuleDeclaration) { const { body } = node; - if (body && body.kind === ts.SyntaxKind.ModuleBlock) { + if (body !== undefined && body.kind === ts.SyntaxKind.ModuleBlock) { this.checkStatements((body as ts.ModuleBlock).statements); } super.visitModuleDeclaration(node); @@ -89,10 +89,10 @@ class Walker extends Lint.RuleWalker { this.checkOverloads(statements, (statement) => { if (statement.kind === ts.SyntaxKind.FunctionDeclaration) { const fn = statement as ts.FunctionDeclaration; - if (fn.body) { + if (fn.body !== undefined) { return undefined; } - return fn.name && { signature: fn, key: fn.name.text }; + return fn.name === undefined ? undefined : { signature: fn, key: fn.name.text }; } else { return undefined; } @@ -102,7 +102,7 @@ class Walker extends Lint.RuleWalker { private checkMembers(members: Array, typeParameters?: ts.TypeParameterDeclaration[]) { this.checkOverloads(members, getOverloadName, typeParameters); function getOverloadName(member: ts.TypeElement | ts.ClassElement) { - if (!utils.isSignatureDeclaration(member) || (member as ts.MethodDeclaration).body) { + if (!utils.isSignatureDeclaration(member) || (member as ts.MethodDeclaration).body !== undefined) { return undefined; } const key = getOverloadKey(member); @@ -130,17 +130,17 @@ class Walker extends Lint.RuleWalker { if (a.parameters.length === b.parameters.length) { const params = signaturesDifferBySingleParameter(a.parameters, b.parameters); - if (params) { + if (params !== undefined) { const [p0, p1] = params; const lineOfOtherOverload = only2 ? undefined : this.getLine(p0); this.addFailureAtNode(p1, Rule.FAILURE_STRING_SINGLE_PARAMETER_DIFFERENCE(lineOfOtherOverload, typeText(p0), typeText(p1))); } } else { const diff = signaturesDifferByOptionalOrRestParameter(a.parameters, b.parameters); - if (diff) { + if (diff !== undefined) { const [extraParameter, signatureWithExtraParameter] = diff; const lineOfOtherOverload = only2 ? undefined : this.getLine(signatureWithExtraParameter === a.parameters ? b : a); - this.addFailureAtNode(extraParameter, extraParameter.dotDotDotToken + this.addFailureAtNode(extraParameter, extraParameter.dotDotDotToken !== undefined ? Rule.FAILURE_STRING_OMITTING_REST_PARAMETER(lineOfOtherOverload) : Rule.FAILURE_STRING_OMITTING_SINGLE_PARAMETER(lineOfOtherOverload)); } @@ -208,7 +208,7 @@ function signaturesDifferByOptionalOrRestParameter(types1: ts.ParameterDeclarati } } - if (minLength > 0 && shorter[minLength - 1].dotDotDotToken) { + if (minLength > 0 && shorter[minLength - 1].dotDotDotToken !== undefined) { return undefined; } @@ -229,7 +229,7 @@ type IsTypeParameter = (typeName: string) => boolean; /** Given type parameters, returns a function to test whether a type is one of those parameters. */ function getIsTypeParameter(typeParameters?: ts.TypeParameterDeclaration[]): IsTypeParameter { - if (!typeParameters) { + if (typeParameters === undefined) { return () => false; } @@ -263,13 +263,13 @@ function collectOverloads(nodes: T[], getOverload: GetOverload): ts.Signat const map = new Map(); for (const sig of nodes) { const overload = getOverload(sig); - if (!overload) { + if (overload === undefined) { continue; } const { signature, key } = overload; const overloads = map.get(key); - if (overloads) { + if (overloads !== undefined) { overloads.push(signature); } else { map.set(key, [signature]); @@ -284,12 +284,13 @@ function parametersAreEqual(a: ts.ParameterDeclaration, b: ts.ParameterDeclarati /** True for optional/rest parameters. */ function parameterMayBeMissing(p: ts.ParameterDeclaration): boolean { - return !!p.dotDotDotToken || !!p.questionToken; + return p.dotDotDotToken !== undefined || p.questionToken !== undefined; } /** False if one is optional and the other isn't, or one is a rest parameter and the other isn't. */ function parametersHaveEqualSigils(a: ts.ParameterDeclaration, b: ts.ParameterDeclaration): boolean { - return !!a.dotDotDotToken === !!b.dotDotDotToken && !!a.questionToken === !!b.questionToken; + return (a.dotDotDotToken !== undefined) === (b.dotDotDotToken !== undefined) && + (a.questionToken !== undefined) === (b.questionToken !== undefined); } function typeParametersAreEqual(a: ts.TypeParameterDeclaration, b: ts.TypeParameterDeclaration): boolean { @@ -298,7 +299,7 @@ function typeParametersAreEqual(a: ts.TypeParameterDeclaration, b: ts.TypeParame function typesAreEqual(a: ts.TypeNode | undefined, b: ts.TypeNode | undefined): boolean { // TODO: Could traverse AST so that formatting differences don't affect this. - return a === b || !!a && !!b && a.getText() === b.getText(); + return a === b || a !== undefined && b !== undefined && a.getText() === b.getText(); } /** Returns the first index where `a` and `b` differ. */ diff --git a/src/rules/variableNameRule.ts b/src/rules/variableNameRule.ts index 4733e2be884..8e98decbcfa 100644 --- a/src/rules/variableNameRule.ts +++ b/src/rules/variableNameRule.ts @@ -109,7 +109,7 @@ function walk(ctx: Lint.WalkContext): void { handleVariableNameKeyword(name); // A destructuring pattern that does not rebind an expression is always an alias, e.g. `var {Foo} = ...;`. // Only check if the name is rebound (`var {Foo: bar} = ...;`). - if (node.parent!.kind !== ts.SyntaxKind.ObjectBindingPattern || propertyName) { + if (node.parent!.kind !== ts.SyntaxKind.ObjectBindingPattern || propertyName !== undefined) { handleVariableNameFormat(name, initializer); } } @@ -147,7 +147,7 @@ function walk(ctx: Lint.WalkContext): void { } const { text } = name; - if (initializer && isAlias(text, initializer)) { + if (initializer !== undefined && isAlias(text, initializer)) { return; } diff --git a/src/runner.ts b/src/runner.ts index 484e24231dd..c9e87ca4a09 100644 --- a/src/runner.ts +++ b/src/runner.ts @@ -110,12 +110,12 @@ export class Runner { constructor(private options: IRunnerOptions, private outputStream: NodeJS.WritableStream) { } public run(onComplete: (status: number) => void) { - if (this.options.version) { + if (this.options.version === true) { this.outputStream.write(Linter.VERSION + "\n"); return onComplete(0); } - if (this.options.init) { + if (this.options.init === true) { if (fs.existsSync(CONFIG_FILENAME)) { console.error(`Cannot generate ${CONFIG_FILENAME}: file already exists`); return onComplete(1); @@ -126,14 +126,15 @@ export class Runner { return onComplete(0); } - if (this.options.test) { - const results = runTests((this.options.files || []).map(Runner.trimSingleQuotes), this.options.rulesDirectory); + if (this.options.test !== undefined) { + const files = this.options.files !== undefined ? this.options.files : []; + const results = runTests(files.map(Runner.trimSingleQuotes), this.options.rulesDirectory); const didAllTestsPass = consoleTestResultsHandler(results); return onComplete(didAllTestsPass ? 0 : 1); } // when provided, it should point to an existing location - if (this.options.config && !fs.existsSync(this.options.config)) { + if (this.options.config !== undefined && !fs.existsSync(this.options.config)) { console.error("Invalid option for configuration: " + this.options.config); return onComplete(1); } @@ -142,7 +143,7 @@ export class Runner { let files = this.options.files === undefined ? [] : this.options.files; let program: ts.Program | undefined; - if (this.options.project != null) { + if (this.options.project !== undefined) { if (!fs.existsSync(this.options.project)) { console.error("Invalid option for project: " + this.options.project); return onComplete(1); @@ -151,14 +152,14 @@ export class Runner { if (files.length === 0) { files = Linter.getFileNames(program); } - if (this.options.typeCheck) { + if (this.options.typeCheck === true) { // if type checking, run the type checker const diagnostics = ts.getPreEmitDiagnostics(program); if (diagnostics.length > 0) { const messages = diagnostics.map((diag) => { // emit any error messages let message = ts.DiagnosticCategory[diag.category]; - if (diag.file) { + if (diag.file !== undefined) { const {line, character} = diag.file.getLineAndCharacterOfPosition(diag.start); message += ` at ${diag.file.fileName}:${line + 1}:${character + 1}:`; } @@ -166,19 +167,19 @@ export class Runner { return message; }); console.error(messages.join("\n")); - return onComplete(this.options.force ? 0 : 1); + return onComplete(this.options.force === true ? 0 : 1); } } else { // if not type checking, we don't need to pass in a program object program = undefined; } - } else if (this.options.typeCheck) { + } else if (this.options.typeCheck === true) { console.error("--project must be specified in order to enable type checking."); return onComplete(1); } let ignorePatterns: string[] = []; - if (this.options.exclude) { + if (this.options.exclude !== undefined) { const excludeArguments: string[] = Array.isArray(this.options.exclude) ? this.options.exclude : [this.options.exclude]; ignorePatterns = excludeArguments.map(Runner.trimSingleQuotes); @@ -205,10 +206,10 @@ export class Runner { private processFiles(onComplete: (status: number) => void, files: string[], program?: ts.Program) { const possibleConfigAbsolutePath = this.options.config != null ? path.resolve(this.options.config) : null; const linter = new Linter({ - fix: !!this.options.fix, + fix: this.options.fix === true, formatter: this.options.format, - formattersDirectory: this.options.formattersDirectory || "", - rulesDirectory: this.options.rulesDirectory || "", + formattersDirectory: this.options.formattersDirectory !== undefined ? this.options.formattersDirectory : "", + rulesDirectory: this.options.rulesDirectory !== undefined ? this.options.rulesDirectory : "", }, program); let lastFolder: string | undefined; @@ -246,7 +247,7 @@ export class Runner { const lintResult = linter.getResult(); this.outputStream.write(lintResult.output, () => { - if (this.options.force || lintResult.errorCount === 0) { + if (this.options.force === true || lintResult.errorCount === 0) { onComplete(0); } else { onComplete(2); diff --git a/src/test.ts b/src/test.ts index 22bb95af0c2..abfef8667e0 100644 --- a/src/test.ts +++ b/src/test.ts @@ -71,7 +71,7 @@ export function runTest(testDirectory: string, rulesDirectory?: string | string[ let compilerOptions: ts.CompilerOptions = { allowJs: true }; if (fs.existsSync(tsConfig)) { const {config, error} = ts.readConfigFile(tsConfig, ts.sys.readFile); - if (error) { + if (error !== undefined) { throw new Error(JSON.stringify(error)); } @@ -90,7 +90,7 @@ export function runTest(testDirectory: string, rulesDirectory?: string | string[ const fileCompileName = fileBasename.replace(/\.lint$/, ""); let fileText = fs.readFileSync(fileToLint, "utf8"); const tsVersionRequirement = parse.getTypescriptVersionRequirement(fileText); - if (tsVersionRequirement) { + if (tsVersionRequirement !== undefined) { const tsVersion = new semver.SemVer(ts.version); // remove prerelease suffix when matching to allow testing with nightly builds if (!semver.satisfies(`${tsVersion.major}.${tsVersion.minor}.${tsVersion.patch}`, tsVersionRequirement)) { @@ -112,7 +112,7 @@ export function runTest(testDirectory: string, rulesDirectory?: string | string[ const errorsFromMarkup = parse.parseErrorsFromMarkup(fileText); let program: ts.Program | undefined; - if (tslintConfig !== undefined && tslintConfig.linterOptions && tslintConfig.linterOptions.typeCheck) { + if (tslintConfig !== undefined && tslintConfig.linterOptions !== undefined && tslintConfig.linterOptions.typeCheck === true) { const compilerHost: ts.CompilerHost = { fileExists: () => true, getCanonicalFileName: (filename: string) => filename, @@ -224,8 +224,8 @@ export function consoleTestResultHandler(testResult: TestResult): boolean { } else { const markupDiffResults = diff.diffLines(results.markupFromMarkup, results.markupFromLinter); const fixesDiffResults = diff.diffLines(results.fixesFromLinter, results.fixesFromMarkup); - const didMarkupTestPass = !markupDiffResults.some((diff) => !!diff.added || !!diff.removed); - const didFixesTestPass = !fixesDiffResults.some((diff) => !!diff.added || !!diff.removed); + const didMarkupTestPass = !markupDiffResults.some((diff) => diff.added === true || diff.removed === true); + const didFixesTestPass = !fixesDiffResults.some((diff) => diff.added === true || diff.removed === true); if (didMarkupTestPass && didFixesTestPass) { console.log(colors.green(" Passed")); @@ -253,9 +253,9 @@ function displayDiffResults(diffResults: diff.IDiffResult[], extension: string) for (const diffResult of diffResults) { let color = colors.grey; - if (diffResult.added) { + if (diffResult.added === true) { color = colors.green.underline; - } else if (diffResult.removed) { + } else if (diffResult.removed === true) { color = colors.red.underline; } process.stdout.write(color(diffResult.value)); diff --git a/src/test/parse.ts b/src/test/parse.ts index 233d428396e..7c701a2576c 100644 --- a/src/test/parse.ts +++ b/src/test/parse.ts @@ -68,10 +68,11 @@ export function parseErrorsFromMarkup(text: string): LintError[] { const lintErrors: LintError[] = []; function addError(errorLine: EndErrorLine, errorStartPos: { line: number, col: number }, lineNo: number) { + const message = messageSubstitutions.get(errorLine.message); lintErrors.push({ startPos: errorStartPos, endPos: { line: lineNo, col: errorLine.endCol }, - message: messageSubstitutions.get(errorLine.message) || errorLine.message, + message: message !== undefined ? message : errorLine.message, }); } // for each line of code... diff --git a/src/tslint-cli.ts b/src/tslint-cli.ts index 8f3566e4e1e..d786c2bdb39 100644 --- a/src/tslint-cli.ts +++ b/src/tslint-cli.ts @@ -24,12 +24,14 @@ const processed = optimist .usage("Usage: $0 [options] file ...") .check((argv: any) => { // at least one of file, help, version, project or unqualified argument must be present + // tslint:disable-next-line strict-boolean-expressions if (!(argv.h || argv.i || argv.test || argv.v || argv.project || argv._.length > 0)) { // throw a string, otherwise a call stack is printed for this message // tslint:disable-next-line:no-string-throw throw "Missing files"; } + // tslint:disable-next-line strict-boolean-expressions if (argv.f) { // throw a string, otherwise a call stack is printed for this message // tslint:disable-next-line:no-string-throw @@ -117,6 +119,7 @@ if (argv.o != null) { outputStream = process.stdout; } +// tslint:disable-next-line strict-boolean-expressions if (argv.help) { outputStream.write(processed.help()); const outputString = ` diff --git a/src/utils.ts b/src/utils.ts index 16603a219e6..e98246939c7 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -57,7 +57,7 @@ export function dedent(strings: TemplateStringsArray, ...values: string[]) { // match all leading spaces/tabs at the start of each line const match = fullString.match(/^[ \t]*(?=\S)/gm); - if (!match) { + if (match === null) { // e.g. if the string is empty or all whitespace. return fullString; } @@ -82,10 +82,10 @@ export function stripComments(content: string): string { const regexp: RegExp = /("(?:[^\\\"]*(?:\\.)?)*")|('(?:[^\\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g; const result = content.replace(regexp, (match, _m1, _m2, m3, m4) => { // Only one of m1, m2, m3, m4 matches - if (m3) { + if (m3 !== undefined) { // A block comment. Replace with nothing return ""; - } else if (m4) { + } else if (m4 !== undefined) { // A line comment. If it ends in \r?\n then keep it. const length = m4.length; if (length > 2 && m4[length - 1] === "\n") { @@ -112,5 +112,5 @@ export function escapeRegExp(re: string): string { export type Equal = (a: T, b: T) => boolean; export function arraysAreEqual(a: T[] | undefined, b: T[] | undefined, eq: Equal): boolean { - return a === b || !!a && !!b && a.length === b.length && a.every((x, idx) => eq(x, b[idx])); + return a === b || a !== undefined && b !== undefined && a.length === b.length && a.every((x, idx) => eq(x, b[idx])); } diff --git a/test/configurationTests.ts b/test/configurationTests.ts index 6217d7dd871..80058b53aaf 100644 --- a/test/configurationTests.ts +++ b/test/configurationTests.ts @@ -337,7 +337,7 @@ function demap(map: Map) { // this is needed since `assertConfigEquals` doesn't go into Map object function assertConfigEquals(actual: any, expected: any) { assert.deepEqual(actual, expected); - if (actual && (actual.jsRules || actual.rules)) { + if (actual !== undefined && (actual.jsRules !== undefined || actual.rules !== undefined)) { assert.deepEqual(demap(actual.jsRules), demap(expected.jsRules)); assert.deepEqual(demap(actual.rules), demap(expected.rules)); } diff --git a/test/ruleLoaderTests.ts b/test/ruleLoaderTests.ts index 9366ae95e11..0a4c17af689 100644 --- a/test/ruleLoaderTests.ts +++ b/test/ruleLoaderTests.ts @@ -112,10 +112,10 @@ describe("Rule Loader", () => { const diffResults = diff.diffLines(rules, tests); let testFailed = false; for (const result of diffResults) { - if (result.added) { + if (result.added === true) { console.warn("Test has no matching rule: " + result.value); testFailed = true; - } else if (result.removed) { + } else if (result.removed === true) { console.warn("Missing test: " + result.value); testFailed = true; } diff --git a/tslint.json b/tslint.json index bc74695e6c7..f7d2f9e722b 100644 --- a/tslint.json +++ b/tslint.json @@ -24,6 +24,7 @@ "no-switch-case-fall-through": true, "prefer-const": true, "switch-default": false, + "strict-boolean-expressions": true, "variable-name": [true, "ban-keywords", "check-format", From c333e46f4395273f125cf2be9c063b7884962db2 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Mon, 8 May 2017 18:10:08 -0700 Subject: [PATCH 2/2] Respond to PR comments --- src/rules/completedDocsRule.ts | 5 +---- src/rules/noConsecutiveBlankLinesRule.ts | 2 +- src/rules/orderedImportsRule.ts | 6 ++++-- src/rules/strictTypePredicatesRule.ts | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/rules/completedDocsRule.ts b/src/rules/completedDocsRule.ts index 995d74f80ae..0c3a4d18ba6 100644 --- a/src/rules/completedDocsRule.ts +++ b/src/rules/completedDocsRule.ts @@ -434,9 +434,6 @@ class CompletedDocsWalker extends Lint.ProgramAwareRuleWalker { private describeModifier(kind: ts.SyntaxKind) { const description = ts.SyntaxKind[kind].toLowerCase().split("keyword")[0]; const alias = CompletedDocsWalker.modifierAliases[description]; - if (alias !== undefined) { - return alias; - } - return description; + return alias !== undefined ? alias : description; } } diff --git a/src/rules/noConsecutiveBlankLinesRule.ts b/src/rules/noConsecutiveBlankLinesRule.ts index 22b0fa86c21..8d581f2e7dd 100644 --- a/src/rules/noConsecutiveBlankLinesRule.ts +++ b/src/rules/noConsecutiveBlankLinesRule.ts @@ -57,7 +57,7 @@ export class Rule extends Lint.Rules.AbstractRule { } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { - const limit = this.ruleArguments[0] as number | undefined ; + const limit = this.ruleArguments[0] as number | undefined; return this.applyWithFunction(sourceFile, walk, limit !== undefined ? limit : Rule.DEFAULT_ALLOWED_BLANKS); } } diff --git a/src/rules/orderedImportsRule.ts b/src/rules/orderedImportsRule.ts index f48c1755092..5b144a8afb0 100644 --- a/src/rules/orderedImportsRule.ts +++ b/src/rules/orderedImportsRule.ts @@ -163,8 +163,10 @@ class OrderedImportsWalker extends Lint.RuleWalker { interface Options { "import-sources-order"?: string; "named-imports-order"?: string; } const optionSet = (this.getOptions() as [Options])[0]; - const { "import-sources-order": sources = "case-insensitive", "named-imports-order": named = "case-insensitive" } = - optionSet === undefined ? {} : optionSet; + const { + "import-sources-order": sources = "case-insensitive", + "named-imports-order": named = "case-insensitive", + } = optionSet === undefined ? {} : optionSet; this.importSourcesOrderTransform = TRANSFORMS[sources]; this.namedImportsOrderTransform = TRANSFORMS[named]; } diff --git a/src/rules/strictTypePredicatesRule.ts b/src/rules/strictTypePredicatesRule.ts index 90fc3472cb6..c6dc98279f3 100644 --- a/src/rules/strictTypePredicatesRule.ts +++ b/src/rules/strictTypePredicatesRule.ts @@ -208,7 +208,7 @@ function isFunction(t: ts.Type): boolean { return true; } const symbol = t.getSymbol(); - return symbol === undefined ? false : symbol.getName() === "Function"; + return symbol !== undefined && symbol.getName() === "Function"; } /** Returns a boolean value if that should always be the result of a type predicate. */