fix(ivy): include "variable-declared" decorated classes in ngcc compilation (#26236)

Previously, classes that were declared via variable declarations,
rather than class declarations, were being excluded from the
parsed classes.

PR Close #26236
This commit is contained in:
Pete Bacon Darwin
2018-09-24 20:27:29 +01:00
committed by Jason Aden
parent 7d08722e80
commit 44c05c05af
2 changed files with 38 additions and 18 deletions

View File

@ -24,20 +24,24 @@ export class Esm2015FileParser implements FileParser {
const moduleSymbol = this.checker.getSymbolAtLocation(file); const moduleSymbol = this.checker.getSymbolAtLocation(file);
const map = new Map<ts.SourceFile, ParsedFile>(); const map = new Map<ts.SourceFile, ParsedFile>();
if (moduleSymbol) { if (moduleSymbol) {
const exportClasses = this.checker.getExportsOfModule(moduleSymbol) const exportedSymbols =
.map(getOriginalSymbol(this.checker)) this.checker.getExportsOfModule(moduleSymbol).map(getOriginalSymbol(this.checker));
.filter(exportSymbol => exportSymbol.flags & ts.SymbolFlags.Class); const exportedDeclarations =
exportedSymbols.map(exportSymbol => exportSymbol.valueDeclaration).filter(isDefined);
const classDeclarations = exportClasses.map(exportSymbol => exportSymbol.valueDeclaration)
.filter(isDefined)
.filter(ts.isClassDeclaration);
const decoratedClasses = const decoratedClasses =
classDeclarations exportedDeclarations
.map(declaration => { .map(declaration => {
const decorators = this.host.getDecoratorsOfDeclaration(declaration); if (ts.isClassDeclaration(declaration) || ts.isVariableDeclaration(declaration)) {
return decorators && declaration.name && const name = declaration.name && ts.isIdentifier(declaration.name) ?
new ParsedClass(declaration.name.text, declaration, decorators); declaration.name.text :
undefined;
const decorators = this.host.getDecoratorsOfDeclaration(declaration);
return decorators && isDefined(name) ?
new ParsedClass(name, declaration, decorators) :
undefined;
}
return undefined;
}) })
.filter(isDefined); .filter(isDefined);

View File

@ -15,6 +15,7 @@ import {makeProgram} from '../helpers/utils';
const BASIC_FILE = { const BASIC_FILE = {
name: '/primary.js', name: '/primary.js',
contents: ` contents: `
import {Directive} from '@angular/core';
class A {} class A {}
A.decorators = [ A.decorators = [
{ type: Directive, args: [{ selector: '[a]' }] } { type: Directive, args: [{ selector: '[a]' }] }
@ -31,12 +32,19 @@ const BASIC_FILE = {
class C {} class C {}
let D = class D {}
D = tslib_1.__decorate([
Directive({ selector: '[d]' }),
OtherD()
], D);
export {D};
export { A, x, C }; export { A, x, C };
` `
}; };
describe('Esm2015PackageParser', () => { describe('Esm2015FileParser', () => {
describe('getDecoratedClasses()', () => { describe('parseFile()', () => {
it('should return an array of object for each class that is exported and decorated', () => { it('should return an array of object for each class that is exported and decorated', () => {
const program = makeProgram(BASIC_FILE); const program = makeProgram(BASIC_FILE);
const host = new Fesm2015ReflectionHost(program.getTypeChecker()); const host = new Fesm2015ReflectionHost(program.getTypeChecker());
@ -46,11 +54,19 @@ describe('Esm2015PackageParser', () => {
expect(parsedFiles.length).toEqual(1); expect(parsedFiles.length).toEqual(1);
const decoratedClasses = parsedFiles[0].decoratedClasses; const decoratedClasses = parsedFiles[0].decoratedClasses;
expect(decoratedClasses.length).toEqual(1); expect(decoratedClasses.length).toEqual(2);
const decoratedClass = decoratedClasses[0];
expect(decoratedClass.name).toEqual('A'); const decoratedClassA = decoratedClasses.find(c => c.name === 'A') !;
expect(ts.isClassDeclaration(decoratedClass.declaration)).toBeTruthy(); expect(decoratedClassA.decorators.map(decorator => decorator.name)).toEqual(['Directive']);
expect(decoratedClass.decorators.map(decorator => decorator.name)).toEqual(['Directive']); expect(decoratedClassA.decorators.map(
decorator => decorator.args && decorator.args.map(arg => arg.getText())))
.toEqual([[`{ selector: '[a]' }`]]);
const decoratedClassD = decoratedClasses.find(c => c.name === 'D') !;
expect(decoratedClassD.decorators.map(decorator => decorator.name)).toEqual(['Directive']);
expect(decoratedClassD.decorators.map(
decorator => decorator.args && decorator.args.map(arg => arg.getText())))
.toEqual([[`{ selector: '[d]' }`]]);
}); });
}); });
}); });