Skip to content

Commit

Permalink
fix(ng-update): do not throw if imports without named bindings are used
Browse files Browse the repository at this point in the history
Currently if someone uses a namespace import or an import without named bindings in an Angular application, the `ng-update` schematics from Angular Material will fail due to missing safety checks before casting.

Fixes angular#11571
  • Loading branch information
devversion committed Aug 28, 2018
1 parent 6aa7727 commit 40df14e
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 14 deletions.
4 changes: 4 additions & 0 deletions src/lib/schematics/update/material/typescript-specifiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
45 changes: 31 additions & 14 deletions src/lib/schematics/update/rules/checkImportMiscRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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`);
}
});
}
}

0 comments on commit 40df14e

Please sign in to comment.