feat(compiler-cli): lower metadata useValue and data literal fields (#18905)

With this commit the compiler will "lower" expressions into exported
variables for values the compiler does not need to know statically
in order to be able to generate a factory. For example:

```
  providers: [{provider: 'token', useValue: calculated()}]
```

produced an error as the expression `calculated()` is not supported
by the compiler because `calculated` is not a
[known function](https://angular.io/guide/metadata#annotationsdecorators)

With this commit this is rewritten, during emit of the .js file, into
something like:

```
export var ɵ0 = calculated();

  ...

  provdiers: [{provider: 'token', useValue: ɵ0}]
```

The compiler then will now generate a reference to the exported `ɵ0`
instead of failing to evaluate `calculated()`.

PR Close #18905
This commit is contained in:
Chuck Jazdzewski
2017-08-23 10:22:17 -07:00
committed by Jason Aden
parent c7e1bda32f
commit 0e64261f26
8 changed files with 324 additions and 28 deletions

View File

@ -35,12 +35,14 @@ export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.T
return ctx.toSource();
}
export type ReferenceFilter = (reference: o.ExternalReference) => boolean;
export class TypeScriptEmitter implements OutputEmitter {
emitStatementsAndContext(
srcFilePath: string, genFilePath: string, stmts: o.Statement[], preamble: string = '',
emitSourceMaps: boolean = true): {sourceText: string, context: EmitterVisitorContext} {
const converter = new _TsEmitterVisitor();
emitSourceMaps: boolean = true,
referenceFilter?: ReferenceFilter): {sourceText: string, context: EmitterVisitorContext} {
const converter = new _TsEmitterVisitor(referenceFilter);
const ctx = EmitterVisitorContext.createRoot();
@ -78,10 +80,11 @@ export class TypeScriptEmitter implements OutputEmitter {
}
}
class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor {
private typeExpression = 0;
constructor() { super(false); }
constructor(private referenceFilter?: ReferenceFilter) { super(false); }
importsWithPrefixes = new Map<string, string>();
reexports = new Map<string, {name: string, as: string}[]>();
@ -377,6 +380,10 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
private _visitIdentifier(
value: o.ExternalReference, typeParams: o.Type[]|null, ctx: EmitterVisitorContext): void {
const {name, moduleName} = value;
if (this.referenceFilter && this.referenceFilter(value)) {
ctx.print(null, '(null as any)');
return;
}
if (moduleName) {
let prefix = this.importsWithPrefixes.get(moduleName);
if (prefix == null) {