fix(ivy): ngcc - handle prototype pseudo-member from typings file in ESM5 host (#29158)

When processing a JavaScript program, TS may come across a symbol that has
been imported from a TypeScript typings file.

In this case the compiler may pass the ReflectionHost a `prototype` symbol
as an export of the class.

This pseudo-member symbol has no declarations, which previously caused the
code in `Esm5ReflectionHost.reflectMembers()` to crash.

Now we just quietly ignore such a symbol and leave `Esm2015ReflectionHost`
to deal with it.

(As it happens `Esm2015ReflectionHost` also quietly ignores this symbol).

PR Close #29158
This commit is contained in:
Pete Bacon Darwin 2019-03-07 11:44:12 +00:00 committed by Kara Erickson
parent d4728c40d9
commit 142ac41cac
3 changed files with 23 additions and 1 deletions

View File

@ -775,6 +775,9 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
const node = symbol.valueDeclaration || symbol.declarations && symbol.declarations[0];
if (!node) {
// If the symbol has been imported from a TypeScript typings file then the compiler
// may pass the `prototype` symbol as an export of the class.
// But this has no declaration. In this case we just quietly ignore it.
return null;
}

View File

@ -228,7 +228,7 @@ export class Esm5ReflectionHost extends Esm2015ReflectionHost {
protected reflectMembers(symbol: ts.Symbol, decorators?: Decorator[], isStatic?: boolean):
ClassMember[]|null {
const node = symbol.valueDeclaration || symbol.declarations && symbol.declarations[0];
const propertyDefinition = getPropertyDefinition(node);
const propertyDefinition = node && getPropertyDefinition(node);
if (propertyDefinition) {
const members: ClassMember[] = [];
if (propertyDefinition.setter) {

View File

@ -520,6 +520,15 @@ const DECORATED_FILES = [
}
];
const UNWANTED_PROTOTYPE_EXPORT_FILE = {
name: '/library.d.ts',
contents: `
export declare class SomeParam {
someInstanceMethod(): void;
static someStaticProp: any;
}`
};
describe('Esm5ReflectionHost', () => {
describe('getDecoratorsOfDeclaration()', () => {
@ -906,6 +915,16 @@ describe('Esm5ReflectionHost', () => {
expect(decorators[0].args).toEqual([]);
});
});
it('should ignore the prototype pseudo-static property on class imported from typings files',
() => {
const program = makeTestProgram(UNWANTED_PROTOTYPE_EXPORT_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration(
program, UNWANTED_PROTOTYPE_EXPORT_FILE.name, 'SomeParam', ts.isClassDeclaration);
const members = host.getMembersOfClass(classNode);
expect(members.find(m => m.name === 'prototype')).toBeUndefined();
});
});
describe('getConstructorParameters', () => {