feat(core): add undecorated classes migration schematic (#31650)

Introduces a new migration schematic that follows the given
migration plan: https://hackmd.io/@alx/S1XKqMZeS.

First case: The schematic detects decorated directives which
inherit a constructor. The migration ensures that all base
classes until the class with the explicit constructor are
properly decorated with "@Directive()" or "@Component". In
case one of these classes is not decorated, the schematic
adds the abstract "@Directive()" decorator automatically.

Second case: The schematic detects undecorated declarations
and copies the inherited "@Directive()", "@Component" or
"@Pipe" decorator to the undecorated derived class. This
involves non-trivial import rewriting, identifier aliasing
and AOT metadata serializing
(as decorators are not always part of source files)

PR Close #31650
This commit is contained in:
Paul Gschwendtner
2019-07-24 12:07:07 +02:00
committed by Kara Erickson
parent 5064dc75ac
commit 024c31da25
22 changed files with 3107 additions and 0 deletions

View File

@ -15,6 +15,7 @@ export type CallExpressionDecorator = ts.Decorator & {
export interface NgDecorator {
name: string;
moduleName: string;
node: CallExpressionDecorator;
importNode: ts.ImportDeclaration;
}
@ -30,6 +31,7 @@ export function getAngularDecorators(
.map(({node, importData}) => ({
node: node as CallExpressionDecorator,
name: importData !.name,
moduleName: importData !.importModule,
importNode: importData !.node
}));
}

View File

@ -30,3 +30,8 @@ export function findParentClassDeclaration(node: ts.Node): ts.ClassDeclaration|n
}
return node;
}
/** Checks whether the given class declaration has an explicit constructor or not. */
export function hasExplicitConstructor(node: ts.ClassDeclaration): boolean {
return node.members.some(ts.isConstructorDeclaration);
}

View File

@ -0,0 +1,20 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as ts from 'typescript';
export function getValueSymbolOfDeclaration(node: ts.Node, typeChecker: ts.TypeChecker): ts.Symbol|
undefined {
let symbol = typeChecker.getSymbolAtLocation(node);
while (symbol && symbol.flags & ts.SymbolFlags.Alias) {
symbol = typeChecker.getAliasedSymbol(symbol);
}
return symbol;
}