fix(ivy): ngcc - empower Esm5ReflectionHost to analyze ModuleWithProviders functions (#29092)

In ESM5 code, static methods appear as property assignments onto the constructor
function. For example:

```
var MyClass = (function() {
  function MyClass () {}
  MyClass.staticMethod = function() {};
  return MyClass;
})();
```

This commit teaches ngcc how to process these forms when searching
for `ModuleWithProviders` functions that need to be updated in the typings
files.

PR Close #29092
This commit is contained in:
Pete Bacon Darwin
2019-03-20 13:47:58 +00:00
committed by Matias Niemelä
parent 68f9d705f8
commit b48d6e1b13
5 changed files with 154 additions and 27 deletions

View File

@ -10,7 +10,7 @@ import * as ts from 'typescript';
import {ReferencesRegistry} from '../../../src/ngtsc/annotations';
import {Reference} from '../../../src/ngtsc/imports';
import {Declaration} from '../../../src/ngtsc/reflection';
import {NgccReflectionHost} from '../host/ngcc_host';
import {ModuleWithProvidersFunction, NgccReflectionHost} from '../host/ngcc_host';
import {isDefined} from '../utils';
export interface ModuleWithProvidersInfo {
@ -38,7 +38,7 @@ export class ModuleWithProvidersAnalyzer {
rootFiles.forEach(f => {
const fns = this.host.getModuleWithProvidersFunctions(f);
fns && fns.forEach(fn => {
const dtsFn = this.getDtsDeclaration(fn.declaration);
const dtsFn = this.getDtsDeclarationForFunction(fn);
const typeParam = dtsFn.type && ts.isTypeReferenceNode(dtsFn.type) &&
dtsFn.type.typeArguments && dtsFn.type.typeArguments[0] ||
null;
@ -82,28 +82,27 @@ export class ModuleWithProvidersAnalyzer {
return program.getRootFileNames().map(f => program.getSourceFile(f)).filter(isDefined);
}
private getDtsDeclaration(fn: ts.SignatureDeclaration) {
private getDtsDeclarationForFunction(fn: ModuleWithProvidersFunction) {
let dtsFn: ts.Declaration|null = null;
const containerClass = this.host.getClassSymbol(fn.parent);
const fnName = fn.name && ts.isIdentifier(fn.name) && fn.name.text;
if (containerClass && fnName) {
const containerClass = fn.container && this.host.getClassSymbol(fn.container);
if (containerClass) {
const dtsClass = this.host.getDtsDeclaration(containerClass.valueDeclaration);
// Get the declaration of the matching static method
dtsFn = dtsClass && ts.isClassDeclaration(dtsClass) ?
dtsClass.members
.find(
member => ts.isMethodDeclaration(member) && ts.isIdentifier(member.name) &&
member.name.text === fnName) as ts.Declaration :
member.name.text === fn.name) as ts.Declaration :
null;
} else {
dtsFn = this.host.getDtsDeclaration(fn);
dtsFn = this.host.getDtsDeclaration(fn.declaration);
}
if (!dtsFn) {
throw new Error(`Matching type declaration for ${fn.getText()} is missing`);
throw new Error(`Matching type declaration for ${fn.declaration.getText()} is missing`);
}
if (!isFunctionOrMethod(dtsFn)) {
throw new Error(
`Matching type declaration for ${fn.getText()} is not a function: ${dtsFn.getText()}`);
`Matching type declaration for ${fn.declaration.getText()} is not a function: ${dtsFn.getText()}`);
}
return dtsFn;
}