diff --git a/src/lib/schematics/update/material/typescript-specifiers.ts b/src/lib/schematics/update/material/typescript-specifiers.ts index c9a87fce29c..94e4fd138af 100644 --- a/src/lib/schematics/update/material/typescript-specifiers.ts +++ b/src/lib/schematics/update/material/typescript-specifiers.ts @@ -27,6 +27,10 @@ export function isMaterialExportDeclaration(node: ts.Node) { /** Whether the declaration is part of Angular Material. */ function isMaterialDeclaration(declaration: ts.ImportDeclaration | ts.ExportDeclaration) { + if (!declaration.moduleSpecifier) { + return false; + } + const moduleSpecifier = declaration.moduleSpecifier.getText(); return moduleSpecifier.indexOf(materialModuleSpecifier) !== -1 || moduleSpecifier.indexOf(cdkModuleSpecifier) !== -1; diff --git a/src/lib/schematics/update/rules/checkImportMiscRule.ts b/src/lib/schematics/update/rules/checkImportMiscRule.ts index a209f866534..0abaf64c292 100644 --- a/src/lib/schematics/update/rules/checkImportMiscRule.ts +++ b/src/lib/schematics/update/rules/checkImportMiscRule.ts @@ -12,26 +12,43 @@ import * as ts from 'typescript'; import {isMaterialImportDeclaration} from '../material/typescript-specifiers'; /** - * Rule that walks through every identifier that is part of Angular Material and replaces the - * outdated name with the new one. + * Rule that detects import declarations that refer to outdated identifiers from Angular Material + * or the CDK which cannot be updated automatically. */ export class Rule extends Rules.TypedRule { applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): RuleFailure[] { - return this.applyWithWalker(new CheckImportMiscWalker(sourceFile, this.getOptions(), program)); + return this.applyWithWalker(new Walker(sourceFile, this.getOptions(), program)); } } -export class CheckImportMiscWalker extends ProgramAwareRuleWalker { - visitImportDeclaration(declaration: ts.ImportDeclaration) { - if (isMaterialImportDeclaration(declaration)) { - declaration.importClause.namedBindings.forEachChild(n => { - let importName = n.getFirstToken() && n.getFirstToken().getText(); - if (importName === 'SHOW_ANIMATION' || importName === 'HIDE_ANIMATION') { - this.addFailureAtNode( - n, - `Found deprecated symbol "${red(importName)}" which has been removed`); - } - }); +export class Walker extends ProgramAwareRuleWalker { + + visitImportDeclaration(node: ts.ImportDeclaration) { + if (!isMaterialImportDeclaration(node) || + !node.importClause || + !node.importClause.namedBindings) { + return; + } + + const namedBindings = node.importClause.namedBindings; + + if (ts.isNamedImports(namedBindings)) { + this._checkAnimationConstants(namedBindings); } } + + /** + * Checks for named imports that refer to the deleted animation constants. + * https://github.com/angular/material2/commit/9f3bf274c4f15f0b0fbd8ab7dbf1a453076e66d9 + */ + private _checkAnimationConstants(namedImports: ts.NamedImports) { + namedImports.elements.filter(element => ts.isIdentifier(element.name)).forEach(element => { + const importName = element.name.text; + + if (importName === 'SHOW_ANIMATION' || importName === 'HIDE_ANIMATION') { + this.addFailureAtNode(element, + `Found deprecated symbol "${red(importName)}" which has been removed`); + } + }); + } }