Skip to content

Commit fe64211

Browse files
devversionjelbourn
authored andcommitted
fix(ng-update): do not throw if imports without named bindings are used (#12866) (#12984)
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 #11571
1 parent 4ddbde9 commit fe64211

File tree

2 files changed

+35
-14
lines changed

2 files changed

+35
-14
lines changed

src/lib/schematics/update/material/typescript-specifiers.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ export function isMaterialExportDeclaration(node: ts.Node) {
2727

2828
/** Whether the declaration is part of Angular Material. */
2929
function isMaterialDeclaration(declaration: ts.ImportDeclaration | ts.ExportDeclaration) {
30+
if (!declaration.moduleSpecifier) {
31+
return false;
32+
}
33+
3034
const moduleSpecifier = declaration.moduleSpecifier.getText();
3135
return moduleSpecifier.indexOf(materialModuleSpecifier) !== -1 ||
3236
moduleSpecifier.indexOf(cdkModuleSpecifier) !== -1;

src/lib/schematics/update/rules/checkImportMiscRule.ts

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,43 @@ import * as ts from 'typescript';
1212
import {isMaterialImportDeclaration} from '../material/typescript-specifiers';
1313

1414
/**
15-
* Rule that walks through every identifier that is part of Angular Material and replaces the
16-
* outdated name with the new one.
15+
* Rule that detects import declarations that refer to outdated identifiers from Angular Material
16+
* or the CDK which cannot be updated automatically.
1717
*/
1818
export class Rule extends Rules.TypedRule {
1919
applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): RuleFailure[] {
20-
return this.applyWithWalker(new CheckImportMiscWalker(sourceFile, this.getOptions(), program));
20+
return this.applyWithWalker(new Walker(sourceFile, this.getOptions(), program));
2121
}
2222
}
2323

24-
export class CheckImportMiscWalker extends ProgramAwareRuleWalker {
25-
visitImportDeclaration(declaration: ts.ImportDeclaration) {
26-
if (isMaterialImportDeclaration(declaration)) {
27-
declaration.importClause.namedBindings.forEachChild(n => {
28-
let importName = n.getFirstToken() && n.getFirstToken().getText();
29-
if (importName === 'SHOW_ANIMATION' || importName === 'HIDE_ANIMATION') {
30-
this.addFailureAtNode(
31-
n,
32-
`Found deprecated symbol "${red(importName)}" which has been removed`);
33-
}
34-
});
24+
export class Walker extends ProgramAwareRuleWalker {
25+
26+
visitImportDeclaration(node: ts.ImportDeclaration) {
27+
if (!isMaterialImportDeclaration(node) ||
28+
!node.importClause ||
29+
!node.importClause.namedBindings) {
30+
return;
31+
}
32+
33+
const namedBindings = node.importClause.namedBindings;
34+
35+
if (ts.isNamedImports(namedBindings)) {
36+
this._checkAnimationConstants(namedBindings);
3537
}
3638
}
39+
40+
/**
41+
* Checks for named imports that refer to the deleted animation constants.
42+
* https://github.com/angular/material2/commit/9f3bf274c4f15f0b0fbd8ab7dbf1a453076e66d9
43+
*/
44+
private _checkAnimationConstants(namedImports: ts.NamedImports) {
45+
namedImports.elements.filter(element => ts.isIdentifier(element.name)).forEach(element => {
46+
const importName = element.name.text;
47+
48+
if (importName === 'SHOW_ANIMATION' || importName === 'HIDE_ANIMATION') {
49+
this.addFailureAtNode(element,
50+
`Found deprecated symbol "${red(importName)}" which has been removed`);
51+
}
52+
});
53+
}
3754
}

0 commit comments

Comments
 (0)