fix(ivy): ngcc - identify all ESM5 decorated classes (#27848)
In ESM5 decorated classes can be indicated by calls to `__decorate()`. Previously the `ReflectionHost.findDecoratedClasses()` call would identify helper calls of the form: ``` SomeClass = tslib_1.__decorate(...); ``` But it was missing calls of the form: ``` SomeClass = SomeClass_1 = tslib_1.__decorate(...); ``` This form is common in `@NgModule()` decorations, where the class being decorated is referenced inside the decorator or another member. This commit now ensures that a chain of assignments, of any length, is now identified as a class decoration if it results in a call to `__decorate()`. Fixes #27841 PR Close #27848
This commit is contained in:

committed by
Andrew Kushnir

parent
d505468fb7
commit
e31afb7118
@ -661,8 +661,10 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
|
||||
*/
|
||||
protected getHelperCall(statement: ts.Statement, helperName: string): ts.CallExpression|null {
|
||||
if (ts.isExpressionStatement(statement)) {
|
||||
const expression =
|
||||
isAssignmentStatement(statement) ? statement.expression.right : statement.expression;
|
||||
let expression = statement.expression;
|
||||
while (isAssignment(expression)) {
|
||||
expression = expression.right;
|
||||
}
|
||||
if (ts.isCallExpression(expression) && getCalleeName(expression) === helperName) {
|
||||
return expression;
|
||||
}
|
||||
|
@ -304,6 +304,27 @@ describe('Esm5ReflectionHost [import helper style]', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('findDecoratedClasses', () => {
|
||||
it('should return an array of all decorated classes in the given source file', () => {
|
||||
const program = makeTestProgram(...fileSystem.files);
|
||||
const host = new Esm5ReflectionHost(false, program.getTypeChecker());
|
||||
|
||||
const ngModuleFile = program.getSourceFile('/ngmodule.js') !;
|
||||
const ngModuleClasses = host.findDecoratedClasses(ngModuleFile);
|
||||
expect(ngModuleClasses.length).toEqual(1);
|
||||
const ngModuleClass = ngModuleClasses.find(c => c.name === 'HttpClientXsrfModule') !;
|
||||
expect(ngModuleClass.decorators.map(decorator => decorator.name)).toEqual(['NgModule']);
|
||||
|
||||
const someDirectiveFile = program.getSourceFile('/some_directive.js') !;
|
||||
const someDirectiveClasses = host.findDecoratedClasses(someDirectiveFile);
|
||||
expect(someDirectiveClasses.length).toEqual(1);
|
||||
const someDirectiveClass = someDirectiveClasses.find(c => c.name === 'SomeDirective') !;
|
||||
expect(someDirectiveClass.decorators.map(decorator => decorator.name)).toEqual([
|
||||
'Directive'
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDeclarationOfIdentifier', () => {
|
||||
it('should return the declaration of a locally defined identifier', () => {
|
||||
const program = makeTestProgram(fileSystem.files[0]);
|
||||
|
Reference in New Issue
Block a user