diff --git a/src/exportNameRule.ts b/src/exportNameRule.ts index bbeefcd29..010caf84d 100644 --- a/src/exportNameRule.ts +++ b/src/exportNameRule.ts @@ -130,13 +130,18 @@ export class ExportNameWalker extends Lint.RuleWalker { } private getExportStatementsWithinModules(moduleDeclaration: ts.ModuleDeclaration): ts.Statement[] | undefined { - if (moduleDeclaration.body!.kind === ts.SyntaxKind.ModuleDeclaration) { + if (moduleDeclaration.body === undefined) { + return undefined; + } + + if (moduleDeclaration.body.kind === ts.SyntaxKind.ModuleDeclaration) { // modules may be nested so recur into the structure return this.getExportStatementsWithinModules(moduleDeclaration.body); - } else if (moduleDeclaration.body!.kind === ts.SyntaxKind.ModuleBlock) { + } else if (moduleDeclaration.body.kind === ts.SyntaxKind.ModuleBlock) { const moduleBlock: ts.ModuleBlock = moduleDeclaration.body; return moduleBlock.statements.filter(isExportedDeclaration); } + return undefined; } @@ -146,7 +151,7 @@ export class ExportNameWalker extends Lint.RuleWalker { const element = exportedElements[0]; if (ts.isModuleDeclaration(element) || ts.isClassDeclaration(element) || ts.isFunctionDeclaration(element)) { if (element.name !== undefined) { - this.validateExport(element.name!.text, exportedElements[0]); + this.validateExport(element.name.text, exportedElements[0]); } } else if (exportedElements[0].kind === ts.SyntaxKind.VariableStatement) { const variableStatement: ts.VariableStatement = exportedElements[0]; diff --git a/src/importNameRule.ts b/src/importNameRule.ts index ed412cf67..20798c533 100644 --- a/src/importNameRule.ts +++ b/src/importNameRule.ts @@ -4,6 +4,7 @@ import * as Lint from 'tslint'; import { Utils } from './utils/Utils'; import { ExtendedMetadata } from './utils/ExtendedMetadata'; import { isObject } from './utils/TypeGuard'; +import { isImportEqualsDeclaration } from 'tsutils'; export class Rule extends Lint.Rules.AbstractRule { public static metadata: ExtendedMetadata = { @@ -142,8 +143,8 @@ class ImportNameRuleWalker extends Lint.RuleWalker { } protected visitImportDeclaration(node: ts.ImportDeclaration): void { - if (node.importClause!.name !== undefined) { - const name: string = node.importClause!.name!.text; + if (node.importClause !== undefined && node.importClause.name !== undefined) { + const name: string = node.importClause.name.text; if (node.moduleSpecifier.kind === ts.SyntaxKind.StringLiteral) { const moduleName: string = (node.moduleSpecifier).text; this.validateImport(node, name, moduleName); @@ -157,17 +158,32 @@ class ImportNameRuleWalker extends Lint.RuleWalker { if (expectedImportedName === '' || expectedImportedName === '.' || expectedImportedName === '..') { return; } + expectedImportedName = this.makeCamelCase(expectedImportedName); - if (this.isImportNameValid(importedName, expectedImportedName, moduleName, node) === false) { - const message: string = `Misnamed import. Import should be named '${expectedImportedName}' but found '${importedName}'`; - const nameNode = - node.kind === ts.SyntaxKind.ImportEqualsDeclaration - ? (node).name - : (node).importClause!.name; - const nameNodeStartPos = nameNode!.getStart(); - const fix = new Lint.Replacement(nameNodeStartPos, nameNode!.end - nameNodeStartPos, expectedImportedName); - this.addFailureAt(node.getStart(), node.getWidth(), message, fix); + if (this.isImportNameValid(importedName, expectedImportedName, moduleName, node)) { + return; + } + + const message: string = `Misnamed import. Import should be named '${expectedImportedName}' but found '${importedName}'`; + + const nameNode = this.getNameNodeFromImportNode(node); + if (nameNode === undefined) { + return; } + + const nameNodeStartPos = nameNode.getStart(); + const fix = new Lint.Replacement(nameNodeStartPos, nameNode.end - nameNodeStartPos, expectedImportedName); + this.addFailureAt(node.getStart(), node.getWidth(), message, fix); + } + + private getNameNodeFromImportNode(node: ts.ImportEqualsDeclaration | ts.ImportDeclaration): ts.Node | undefined { + if (isImportEqualsDeclaration(node)) { + return node.name; + } + + const importClause = node.importClause; + + return importClause === undefined ? undefined : importClause.name; } private makeCamelCase(input: string): string { diff --git a/src/noUnsupportedBrowserCodeRule.ts b/src/noUnsupportedBrowserCodeRule.ts index cd45f6c43..15714ba50 100644 --- a/src/noUnsupportedBrowserCodeRule.ts +++ b/src/noUnsupportedBrowserCodeRule.ts @@ -62,18 +62,25 @@ class NoUnsupportedBrowserCodeRuleWalker extends Lint.RuleWalker { // tslint:disable-next-line:no-conditional-assignment while ((match = regex.exec(tokenText))) { const browser = this.parseBrowserString(match[1]); + if (browser === undefined) { + break; + } + this.findUnsupportedBrowserFailures(browser, range.pos, range.end - range.pos); } }); } - private parseBrowserString(browser: string): BrowserVersion { + private parseBrowserString(browser: string): BrowserVersion | undefined { // This case-insensitive regex contains 3 capture groups: // #1 looks for a browser name (combination of spaces and alpha) // #2 looks for an optional comparison operator (>=, <=, etc) // #3 looks for a version number const regex = /([a-zA-Z ]*)(>=|<=|<|>)?\s*(\d*)/i; - const match = browser.match(regex)!; + const match = browser.match(regex); + if (match === null) { + return undefined; + } return { name: match[1].trim(), @@ -89,7 +96,9 @@ class NoUnsupportedBrowserCodeRuleWalker extends Lint.RuleWalker { if (option instanceof Array) { option.forEach((browserString: string) => { const browser = this.parseBrowserString(browserString); - result[browser.name.toLowerCase()] = browser; + if (browser !== undefined) { + result[browser.name.toLowerCase()] = browser; + } }); } }); diff --git a/src/reactA11yAnchorsRule.ts b/src/reactA11yAnchorsRule.ts index 9d29ef080..265ca7741 100644 --- a/src/reactA11yAnchorsRule.ts +++ b/src/reactA11yAnchorsRule.ts @@ -99,6 +99,7 @@ class ReactA11yAnchorsRuleWalker extends Lint.RuleWalker { const differentHrefSameText: IAnchorInfo[] = []; while (this.anchorInfoList.length > 0) { + // tslint:disable-next-line:no-non-null-assertion const current: IAnchorInfo = this.anchorInfoList.shift()!; this.anchorInfoList.forEach( (anchorInfo: IAnchorInfo): void => { diff --git a/src/reactA11yImageButtonHasAltRule.ts b/src/reactA11yImageButtonHasAltRule.ts index ec867a38f..a9483d55b 100644 --- a/src/reactA11yImageButtonHasAltRule.ts +++ b/src/reactA11yImageButtonHasAltRule.ts @@ -56,13 +56,12 @@ class ReactA11yImageButtonHasAltWalker extends Lint.RuleWalker { const attributes: { [propName: string]: ts.JsxAttribute } = getJsxAttributesFromJsxElement(node); const typeAttribute: ts.JsxAttribute = attributes[TYPE_STRING]; - if ( - !typeAttribute || - typeAttribute.initializer === undefined || - !isStringLiteral(typeAttribute.initializer) || - getStringLiteral(typeAttribute) === undefined || - getStringLiteral(typeAttribute)!.toLowerCase() !== 'image' - ) { + if (!typeAttribute || typeAttribute.initializer === undefined || !isStringLiteral(typeAttribute.initializer)) { + return; + } + + const stringLiteral = getStringLiteral(typeAttribute); + if (stringLiteral === undefined || stringLiteral.toLowerCase() !== 'image') { return; } diff --git a/src/reactA11yLangRule.ts b/src/reactA11yLangRule.ts index 4a21df58c..b4693a875 100644 --- a/src/reactA11yLangRule.ts +++ b/src/reactA11yLangRule.ts @@ -216,7 +216,7 @@ class ReactA11yLangRuleWalker extends Lint.RuleWalker { if (attribute.kind === ts.SyntaxKind.JsxAttribute) { if (attribute.name.getText() === 'lang') { langFound = true; - if (attribute.initializer!.kind === ts.SyntaxKind.StringLiteral) { + if (attribute.initializer !== undefined && attribute.initializer.kind === ts.SyntaxKind.StringLiteral) { const langText: string = ((attribute).initializer).text; if (LANGUAGE_CODES.indexOf(langText) === -1) { this.addFailureAt(parent.getStart(), parent.getWidth(), FAILURE_WRONG_LANG_CODE + langText); diff --git a/src/reactNoDangerousHtmlRule.ts b/src/reactNoDangerousHtmlRule.ts index 0e9809f5d..e08df0b34 100644 --- a/src/reactNoDangerousHtmlRule.ts +++ b/src/reactNoDangerousHtmlRule.ts @@ -61,7 +61,6 @@ class NoDangerousHtmlWalker extends Lint.RuleWalker { } protected visitPropertyAssignment(node: ts.PropertyAssignment): void { - super.visitPropertyAssignment(node); const keyNode: ts.DeclarationName = node.name; if (keyNode.kind === ts.SyntaxKind.Identifier) { diff --git a/src/utils/ScopedSymbolTrackingWalker.ts b/src/utils/ScopedSymbolTrackingWalker.ts index 2e5c5ee51..bb353ca6e 100644 --- a/src/utils/ScopedSymbolTrackingWalker.ts +++ b/src/utils/ScopedSymbolTrackingWalker.ts @@ -109,7 +109,11 @@ export class ScopedSymbolTrackingWalker extends Lint.RuleWalker { protected visitModuleDeclaration(node: ts.ModuleDeclaration): void { this.scope = new Scope(this.scope); - this.scope.addGlobalScope(node.body!, this.getSourceFile(), this.getOptions()); + + if (node.body !== undefined) { + this.scope.addGlobalScope(node.body, this.getSourceFile(), this.getOptions()); + } + super.visitModuleDeclaration(node); this.scope = this.scope.parent; } @@ -181,11 +185,15 @@ export class ScopedSymbolTrackingWalker extends Lint.RuleWalker { } protected visitVariableDeclaration(node: ts.VariableDeclaration): void { + // this.scope is always set upon entering a source file, so we know it exists here + // tslint:disable:no-non-null-assertion if (AstUtils.isDeclarationFunctionType(node)) { this.scope!.addFunctionSymbol(node.name.getText()); } else { this.scope!.addNonFunctionSymbol(node.name.getText()); } + // tslint:enable:no-non-null-assertion + super.visitVariableDeclaration(node); } } diff --git a/tslint.json b/tslint.json index c8ed7ae45..369b2fd0d 100644 --- a/tslint.json +++ b/tslint.json @@ -20,7 +20,6 @@ "no-inferrable-types": false, "no-internal-module": false, "no-namespace": false, - "no-non-null-assertion": false, "no-unbound-method": false, "no-unsafe-any": false, "prefer-for-of": false,