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:

committed by
Jason Aden

parent
2f2d5f35bd
commit
c685cc2f0a
@ -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) {
|
||||
|
@ -12,6 +12,8 @@ import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
export interface MetadataProvider { getMetadata(source: ts.SourceFile): ModuleMetadata|undefined; }
|
||||
|
||||
let nodeModulesPath: string;
|
||||
let angularSourcePath: string;
|
||||
let rootPath: string;
|
||||
@ -327,12 +329,13 @@ const DTS = /\.d\.ts$/;
|
||||
const GENERATED_FILES = /\.ngfactory\.ts$|\.ngstyle\.ts$/;
|
||||
|
||||
export class MockAotCompilerHost implements AotCompilerHost {
|
||||
private metadataCollector = new MetadataCollector();
|
||||
private metadataVisible: boolean = true;
|
||||
private dtsAreSource: boolean = true;
|
||||
private resolveModuleNameHost: ts.ModuleResolutionHost;
|
||||
|
||||
constructor(private tsHost: MockCompilerHost) {
|
||||
constructor(
|
||||
private tsHost: MockCompilerHost,
|
||||
private metadataProvider: MetadataProvider = new MetadataCollector()) {
|
||||
this.resolveModuleNameHost = Object.create(tsHost);
|
||||
this.resolveModuleNameHost.fileExists = (fileName) => {
|
||||
fileName = stripNgResourceSuffix(fileName);
|
||||
@ -359,7 +362,7 @@ export class MockAotCompilerHost implements AotCompilerHost {
|
||||
}
|
||||
} else {
|
||||
const sf = this.tsHost.getSourceFile(modulePath, ts.ScriptTarget.Latest);
|
||||
const metadata = this.metadataCollector.getMetadata(sf);
|
||||
const metadata = this.metadataProvider.getMetadata(sf);
|
||||
return metadata ? [metadata] : [];
|
||||
}
|
||||
return undefined;
|
||||
|
Reference in New Issue
Block a user