feat(ivy): @NgModule -> ngInjectorDef compilation (#22458)
This adds compilation of @NgModule providers and imports into ngInjectorDef statements in generated code. All @NgModule annotations will be compiled and the @NgModule decorators removed from the resultant js output. All @Injectables will also be compiled in Ivy mode, and the decorator removed. PR Close #22458
This commit is contained in:

committed by
Miško Hevery

parent
688096b7a3
commit
6ef9f2278f
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, CompileInjectableMetadata, CompileNgModuleMetadata, CompileNgModuleSummary, CompilePipeMetadata, CompilePipeSummary, CompileProviderMetadata, CompileStylesheetMetadata, CompileSummaryKind, CompileTypeMetadata, CompileTypeSummary, componentFactoryName, flatten, identifierName, templateSourceUrl, tokenReference} from '../compile_metadata';
|
||||
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, CompileInjectableMetadata, CompileNgModuleMetadata, CompileNgModuleSummary, CompilePipeMetadata, CompilePipeSummary, CompileProviderMetadata, CompileShallowModuleMetadata, CompileStylesheetMetadata, CompileSummaryKind, CompileTypeMetadata, CompileTypeSummary, componentFactoryName, flatten, identifierName, templateSourceUrl, tokenReference} from '../compile_metadata';
|
||||
import {CompilerConfig} from '../config';
|
||||
import {ConstantPool} from '../constant_pool';
|
||||
import {ViewEncapsulation} from '../core';
|
||||
@ -20,6 +20,7 @@ import {NgModuleCompiler} from '../ng_module_compiler';
|
||||
import {OutputEmitter} from '../output/abstract_emitter';
|
||||
import * as o from '../output/output_ast';
|
||||
import {ParseError} from '../parse_util';
|
||||
import {compileNgModule as compileIvyModule} from '../render3/r3_module_compiler';
|
||||
import {compilePipe as compileIvyPipe} from '../render3/r3_pipe_compiler';
|
||||
import {OutputMode} from '../render3/r3_types';
|
||||
import {compileComponent as compileIvyComponent, compileDirective as compileIvyDirective} from '../render3/r3_view_compiler';
|
||||
@ -57,7 +58,7 @@ export class AotCompiler {
|
||||
|
||||
constructor(
|
||||
private _config: CompilerConfig, private _options: AotCompilerOptions,
|
||||
private _host: AotCompilerHost, private _reflector: StaticReflector,
|
||||
private _host: AotCompilerHost, readonly reflector: StaticReflector,
|
||||
private _metadataResolver: CompileMetadataResolver, private _templateParser: TemplateParser,
|
||||
private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler,
|
||||
private _typeCheckCompiler: TypeCheckCompiler, private _ngModuleCompiler: NgModuleCompiler,
|
||||
@ -283,7 +284,7 @@ export class AotCompiler {
|
||||
private _externalIdentifierReferences(references: o.ExternalReference[]): StaticSymbol[] {
|
||||
const result: StaticSymbol[] = [];
|
||||
for (let reference of references) {
|
||||
const token = createTokenForExternalReference(this._reflector, reference);
|
||||
const token = createTokenForExternalReference(this.reflector, reference);
|
||||
if (token.identifier) {
|
||||
result.push(token.identifier.reference);
|
||||
}
|
||||
@ -332,28 +333,49 @@ export class AotCompiler {
|
||||
return messageBundle;
|
||||
}
|
||||
|
||||
emitAllPartialModules({ngModuleByPipeOrDirective, files}: NgAnalyzedModules): PartialModule[] {
|
||||
// Using reduce like this is a select many pattern (where map is a select pattern)
|
||||
return files.reduce<PartialModule[]>((r, file) => {
|
||||
r.push(...this._emitPartialModule(
|
||||
file.fileName, ngModuleByPipeOrDirective, file.directives, file.pipes, file.ngModules,
|
||||
file.injectables));
|
||||
return r;
|
||||
}, []);
|
||||
emitAllPartialModules(
|
||||
{ngModuleByPipeOrDirective, files}: NgAnalyzedModules,
|
||||
r3Files: NgAnalyzedFileWithInjectables[]): PartialModule[] {
|
||||
const contextMap = new Map<string, OutputContext>();
|
||||
|
||||
const getContext = (fileName: string): OutputContext => {
|
||||
if (!contextMap.has(fileName)) {
|
||||
contextMap.set(fileName, this._createOutputContext(fileName));
|
||||
}
|
||||
return contextMap.get(fileName) !;
|
||||
};
|
||||
|
||||
files.forEach(
|
||||
file => this._compilePartialModule(
|
||||
file.fileName, ngModuleByPipeOrDirective, file.directives, file.pipes, file.ngModules,
|
||||
file.injectables, getContext(file.fileName)));
|
||||
r3Files.forEach(
|
||||
file => this._compileShallowModules(
|
||||
file.fileName, file.shallowModules, getContext(file.fileName)));
|
||||
|
||||
return Array.from(contextMap.values())
|
||||
.map(context => ({
|
||||
fileName: context.genFilePath,
|
||||
statements: [...context.constantPool.statements, ...context.statements],
|
||||
}));
|
||||
}
|
||||
|
||||
private _emitPartialModule(
|
||||
private _compileShallowModules(
|
||||
fileName: string, shallowModules: CompileShallowModuleMetadata[],
|
||||
context: OutputContext): void {
|
||||
shallowModules.forEach(module => compileIvyModule(context, module, this._injectableCompiler));
|
||||
}
|
||||
|
||||
private _compilePartialModule(
|
||||
fileName: string, ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>,
|
||||
directives: StaticSymbol[], pipes: StaticSymbol[], ngModules: CompileNgModuleMetadata[],
|
||||
injectables: CompileInjectableMetadata[]): PartialModule[] {
|
||||
injectables: CompileInjectableMetadata[], context: OutputContext): void {
|
||||
const classes: o.ClassStmt[] = [];
|
||||
const errors: ParseError[] = [];
|
||||
|
||||
const context = this._createOutputContext(fileName);
|
||||
const hostBindingParser = new BindingParser(
|
||||
this._templateParser.expressionParser, DEFAULT_INTERPOLATION_CONFIG, null !, [], errors);
|
||||
|
||||
|
||||
// Process all components and directives
|
||||
directives.forEach(directiveType => {
|
||||
const directiveMetadata = this._metadataResolver.getDirectiveMetadata(directiveType);
|
||||
@ -366,28 +388,22 @@ export class AotCompiler {
|
||||
const {template: parsedTemplate, pipes: parsedPipes} =
|
||||
this._parseTemplate(directiveMetadata, module, module.transitiveModule.directives);
|
||||
compileIvyComponent(
|
||||
context, directiveMetadata, parsedPipes, parsedTemplate, this._reflector,
|
||||
context, directiveMetadata, parsedPipes, parsedTemplate, this.reflector,
|
||||
hostBindingParser, OutputMode.PartialClass);
|
||||
} else {
|
||||
compileIvyDirective(
|
||||
context, directiveMetadata, this._reflector, hostBindingParser,
|
||||
OutputMode.PartialClass);
|
||||
context, directiveMetadata, this.reflector, hostBindingParser, OutputMode.PartialClass);
|
||||
}
|
||||
});
|
||||
|
||||
pipes.forEach(pipeType => {
|
||||
const pipeMetadata = this._metadataResolver.getPipeMetadata(pipeType);
|
||||
if (pipeMetadata) {
|
||||
compileIvyPipe(context, pipeMetadata, this._reflector, OutputMode.PartialClass);
|
||||
compileIvyPipe(context, pipeMetadata, this.reflector, OutputMode.PartialClass);
|
||||
}
|
||||
});
|
||||
|
||||
injectables.forEach(injectable => this._injectableCompiler.compile(injectable, context));
|
||||
|
||||
if (context.statements && context.statements.length > 0) {
|
||||
return [{fileName, statements: [...context.constantPool.statements, ...context.statements]}];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
emitAllPartialModules2(files: NgAnalyzedFileWithInjectables[]): PartialModule[] {
|
||||
@ -531,14 +547,14 @@ export class AotCompiler {
|
||||
if (this._options.locale) {
|
||||
const normalizedLocale = this._options.locale.replace(/_/g, '-');
|
||||
providers.push({
|
||||
token: createTokenForExternalReference(this._reflector, Identifiers.LOCALE_ID),
|
||||
token: createTokenForExternalReference(this.reflector, Identifiers.LOCALE_ID),
|
||||
useValue: normalizedLocale,
|
||||
});
|
||||
}
|
||||
|
||||
if (this._options.i18nFormat) {
|
||||
providers.push({
|
||||
token: createTokenForExternalReference(this._reflector, Identifiers.TRANSLATIONS_FORMAT),
|
||||
token: createTokenForExternalReference(this.reflector, Identifiers.TRANSLATIONS_FORMAT),
|
||||
useValue: this._options.i18nFormat
|
||||
});
|
||||
}
|
||||
@ -682,12 +698,12 @@ export class AotCompiler {
|
||||
listLazyRoutes(entryRoute?: string, analyzedModules?: NgAnalyzedModules): LazyRoute[] {
|
||||
const self = this;
|
||||
if (entryRoute) {
|
||||
const symbol = parseLazyRoute(entryRoute, this._reflector).referencedModule;
|
||||
const symbol = parseLazyRoute(entryRoute, this.reflector).referencedModule;
|
||||
return visitLazyRoute(symbol);
|
||||
} else if (analyzedModules) {
|
||||
const allLazyRoutes: LazyRoute[] = [];
|
||||
for (const ngModule of analyzedModules.ngModules) {
|
||||
const lazyRoutes = listLazyRoutes(ngModule, this._reflector);
|
||||
const lazyRoutes = listLazyRoutes(ngModule, this.reflector);
|
||||
for (const lazyRoute of lazyRoutes) {
|
||||
allLazyRoutes.push(lazyRoute);
|
||||
}
|
||||
@ -707,7 +723,7 @@ export class AotCompiler {
|
||||
}
|
||||
seenRoutes.add(symbol);
|
||||
const lazyRoutes = listLazyRoutes(
|
||||
self._metadataResolver.getNgModuleMetadata(symbol, true) !, self._reflector);
|
||||
self._metadataResolver.getNgModuleMetadata(symbol, true) !, self.reflector);
|
||||
for (const lazyRoute of lazyRoutes) {
|
||||
allLazyRoutes.push(lazyRoute);
|
||||
visitLazyRoute(lazyRoute.referencedModule, seenRoutes, allLazyRoutes);
|
||||
@ -748,6 +764,7 @@ export interface NgAnalyzedModules {
|
||||
export interface NgAnalyzedFileWithInjectables {
|
||||
fileName: string;
|
||||
injectables: CompileInjectableMetadata[];
|
||||
shallowModules: CompileShallowModuleMetadata[];
|
||||
}
|
||||
|
||||
export interface NgAnalyzedFile {
|
||||
@ -868,6 +885,7 @@ export function analyzeFileForInjectables(
|
||||
host: NgAnalyzeModulesHost, staticSymbolResolver: StaticSymbolResolver,
|
||||
metadataResolver: CompileMetadataResolver, fileName: string): NgAnalyzedFileWithInjectables {
|
||||
const injectables: CompileInjectableMetadata[] = [];
|
||||
const shallowModules: CompileShallowModuleMetadata[] = [];
|
||||
if (staticSymbolResolver.hasDecorators(fileName)) {
|
||||
staticSymbolResolver.getSymbolsOf(fileName).forEach((symbol) => {
|
||||
const resolvedSymbol = staticSymbolResolver.resolveSymbol(symbol);
|
||||
@ -883,11 +901,17 @@ export function analyzeFileForInjectables(
|
||||
if (injectable) {
|
||||
injectables.push(injectable);
|
||||
}
|
||||
} else if (metadataResolver.isNgModule(symbol)) {
|
||||
isNgSymbol = true;
|
||||
const module = metadataResolver.getShallowModuleMetadata(symbol);
|
||||
if (module) {
|
||||
shallowModules.push(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return {fileName, injectables};
|
||||
return {fileName, injectables, shallowModules};
|
||||
}
|
||||
|
||||
function isValueExportingNonSourceFile(host: NgAnalyzeModulesHost, metadata: any): boolean {
|
||||
|
@ -90,7 +90,8 @@ export function createAotCompiler(
|
||||
const compiler = new AotCompiler(
|
||||
config, options, compilerHost, staticReflector, resolver, tmplParser,
|
||||
new StyleCompiler(urlResolver), viewCompiler, typeCheckCompiler,
|
||||
new NgModuleCompiler(staticReflector), new InjectableCompiler(staticReflector),
|
||||
new TypeScriptEmitter(), summaryResolver, symbolResolver);
|
||||
new NgModuleCompiler(staticReflector),
|
||||
new InjectableCompiler(staticReflector, !!options.enableIvy), new TypeScriptEmitter(),
|
||||
summaryResolver, symbolResolver);
|
||||
return {compiler, reflector: staticReflector};
|
||||
}
|
||||
|
@ -18,4 +18,5 @@ export interface AotCompilerOptions {
|
||||
fullTemplateTypeCheck?: boolean;
|
||||
allowEmptyCodegenFiles?: boolean;
|
||||
strictInjectionParameters?: boolean;
|
||||
enableIvy?: boolean;
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ function shouldIgnore(value: any): boolean {
|
||||
*/
|
||||
export class StaticReflector implements CompileReflector {
|
||||
private annotationCache = new Map<StaticSymbol, any[]>();
|
||||
private shallowAnnotationCache = new Map<StaticSymbol, any[]>();
|
||||
private propertyCache = new Map<StaticSymbol, {[key: string]: any[]}>();
|
||||
private parameterCache = new Map<StaticSymbol, any[]>();
|
||||
private methodCache = new Map<StaticSymbol, {[key: string]: boolean}>();
|
||||
@ -106,8 +107,9 @@ export class StaticReflector implements CompileReflector {
|
||||
this.symbolResolver.getSymbolByModule(moduleUrl, name, containingFile));
|
||||
}
|
||||
|
||||
tryFindDeclaration(moduleUrl: string, name: string): StaticSymbol {
|
||||
return this.symbolResolver.ignoreErrorsFor(() => this.findDeclaration(moduleUrl, name));
|
||||
tryFindDeclaration(moduleUrl: string, name: string, containingFile?: string): StaticSymbol {
|
||||
return this.symbolResolver.ignoreErrorsFor(
|
||||
() => this.findDeclaration(moduleUrl, name, containingFile));
|
||||
}
|
||||
|
||||
findSymbolDeclaration(symbol: StaticSymbol): StaticSymbol {
|
||||
@ -135,7 +137,21 @@ export class StaticReflector implements CompileReflector {
|
||||
}
|
||||
|
||||
public annotations(type: StaticSymbol): any[] {
|
||||
let annotations = this.annotationCache.get(type);
|
||||
return this._annotations(
|
||||
type, (type: StaticSymbol, decorators: any) => this.simplify(type, decorators),
|
||||
this.annotationCache);
|
||||
}
|
||||
|
||||
public shallowAnnotations(type: StaticSymbol): any[] {
|
||||
return this._annotations(
|
||||
type, (type: StaticSymbol, decorators: any) => this.simplify(type, decorators, true),
|
||||
this.shallowAnnotationCache);
|
||||
}
|
||||
|
||||
private _annotations(
|
||||
type: StaticSymbol, simplify: (type: StaticSymbol, decorators: any) => any,
|
||||
annotationCache: Map<StaticSymbol, any[]>): any[] {
|
||||
let annotations = annotationCache.get(type);
|
||||
if (!annotations) {
|
||||
annotations = [];
|
||||
const classMetadata = this.getTypeMetadata(type);
|
||||
@ -146,7 +162,7 @@ export class StaticReflector implements CompileReflector {
|
||||
}
|
||||
let ownAnnotations: any[] = [];
|
||||
if (classMetadata['decorators']) {
|
||||
ownAnnotations = this.simplify(type, classMetadata['decorators']);
|
||||
ownAnnotations = simplify(type, classMetadata['decorators']);
|
||||
annotations.push(...ownAnnotations);
|
||||
}
|
||||
if (parentType && !this.summaryResolver.isLibraryFile(type.filePath) &&
|
||||
@ -169,7 +185,7 @@ export class StaticReflector implements CompileReflector {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.annotationCache.set(type, annotations.filter(ann => !!ann));
|
||||
annotationCache.set(type, annotations.filter(ann => !!ann));
|
||||
}
|
||||
return annotations;
|
||||
}
|
||||
@ -414,7 +430,7 @@ export class StaticReflector implements CompileReflector {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public simplify(context: StaticSymbol, value: any): any {
|
||||
public simplify(context: StaticSymbol, value: any, lazy: boolean = false): any {
|
||||
const self = this;
|
||||
let scope = BindingScope.empty;
|
||||
const calling = new Map<StaticSymbol, boolean>();
|
||||
@ -775,7 +791,7 @@ export class StaticReflector implements CompileReflector {
|
||||
|
||||
let result: any;
|
||||
try {
|
||||
result = simplifyInContext(context, value, 0, 0);
|
||||
result = simplifyInContext(context, value, 0, lazy ? 1 : 0);
|
||||
} catch (e) {
|
||||
if (this.errorRecorder) {
|
||||
this.reportError(e, context);
|
||||
|
@ -527,6 +527,14 @@ export interface CompileNgModuleSummary extends CompileTypeSummary {
|
||||
modules: CompileTypeMetadata[];
|
||||
}
|
||||
|
||||
export class CompileShallowModuleMetadata {
|
||||
type: CompileTypeMetadata;
|
||||
|
||||
rawExports: any;
|
||||
rawImports: any;
|
||||
rawProviders: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Metadata regarding compilation of a module.
|
||||
*/
|
||||
|
@ -15,6 +15,7 @@ import * as o from './output/output_ast';
|
||||
export abstract class CompileReflector {
|
||||
abstract parameters(typeOrFunc: /*Type*/ any): any[][];
|
||||
abstract annotations(typeOrFunc: /*Type*/ any): any[];
|
||||
abstract shallowAnnotations(typeOrFunc: /*Type*/ any): any[];
|
||||
abstract tryAnnotations(typeOrFunc: /*Type*/ any): any[];
|
||||
abstract propMetadata(typeOrFunc: /*Type*/ any): {[key: string]: any[]};
|
||||
abstract hasLifecycleHook(type: any, lcProperty: string): boolean;
|
||||
|
@ -62,6 +62,7 @@ export class Identifiers {
|
||||
|
||||
};
|
||||
static inject: o.ExternalReference = {name: 'inject', moduleName: CORE};
|
||||
static INJECTOR: o.ExternalReference = {name: 'INJECTOR', moduleName: CORE};
|
||||
static Injector: o.ExternalReference = {name: 'Injector', moduleName: CORE};
|
||||
static defineInjectable: o.ExternalReference = {name: 'defineInjectable', moduleName: CORE};
|
||||
static ViewEncapsulation: o.ExternalReference = {
|
||||
@ -88,7 +89,6 @@ export class Identifiers {
|
||||
static inlineInterpolate: o.ExternalReference = {
|
||||
name: 'ɵinlineInterpolate',
|
||||
moduleName: CORE,
|
||||
|
||||
};
|
||||
static interpolate: o.ExternalReference = {name: 'ɵinterpolate', moduleName: CORE};
|
||||
static EMPTY_ARRAY: o.ExternalReference = {name: 'ɵEMPTY_ARRAY', moduleName: CORE};
|
||||
|
@ -6,6 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {StaticSymbol} from './aot/static_symbol';
|
||||
import {CompileInjectableMetadata, CompileNgModuleMetadata, CompileProviderMetadata, identifierName} from './compile_metadata';
|
||||
import {CompileReflector} from './compile_reflector';
|
||||
import {InjectFlags, NodeFlags} from './core';
|
||||
@ -29,7 +30,10 @@ function mapEntry(key: string, value: o.Expression): MapEntry {
|
||||
}
|
||||
|
||||
export class InjectableCompiler {
|
||||
constructor(private reflector: CompileReflector) {}
|
||||
private tokenInjector: StaticSymbol;
|
||||
constructor(private reflector: CompileReflector, private alwaysGenerateDef: boolean) {
|
||||
this.tokenInjector = reflector.resolveExternalReference(Identifiers.Injector);
|
||||
}
|
||||
|
||||
private depsArray(deps: any[], ctx: OutputContext): o.Expression[] {
|
||||
return deps.map(dep => {
|
||||
@ -55,7 +59,16 @@ export class InjectableCompiler {
|
||||
}
|
||||
}
|
||||
}
|
||||
const tokenExpr = typeof token === 'string' ? o.literal(token) : ctx.importExpr(token);
|
||||
|
||||
let tokenExpr: o.Expression;
|
||||
if (typeof token === 'string') {
|
||||
tokenExpr = o.literal(token);
|
||||
} else if (token === this.tokenInjector && this.alwaysGenerateDef) {
|
||||
tokenExpr = o.importExpr(Identifiers.INJECTOR);
|
||||
} else {
|
||||
tokenExpr = ctx.importExpr(token);
|
||||
}
|
||||
|
||||
if (flags !== InjectFlags.Default || defaultValue !== undefined) {
|
||||
args = [tokenExpr, o.literal(defaultValue), o.literal(flags)];
|
||||
} else {
|
||||
@ -65,7 +78,7 @@ export class InjectableCompiler {
|
||||
});
|
||||
}
|
||||
|
||||
private factoryFor(injectable: CompileInjectableMetadata, ctx: OutputContext): o.Expression {
|
||||
factoryFor(injectable: CompileInjectableMetadata, ctx: OutputContext): o.Expression {
|
||||
let retValue: o.Expression;
|
||||
if (injectable.useExisting) {
|
||||
retValue = o.importExpr(Identifiers.inject).callFn([ctx.importExpr(injectable.useExisting)]);
|
||||
@ -90,8 +103,10 @@ export class InjectableCompiler {
|
||||
|
||||
injectableDef(injectable: CompileInjectableMetadata, ctx: OutputContext): o.Expression {
|
||||
let providedIn: o.Expression = o.NULL_EXPR;
|
||||
if (injectable.providedIn) {
|
||||
if (typeof injectable.providedIn === 'string') {
|
||||
if (injectable.providedIn !== undefined) {
|
||||
if (injectable.providedIn === null) {
|
||||
providedIn = o.NULL_EXPR;
|
||||
} else if (typeof injectable.providedIn === 'string') {
|
||||
providedIn = o.literal(injectable.providedIn);
|
||||
} else {
|
||||
providedIn = ctx.importExpr(injectable.providedIn);
|
||||
@ -106,7 +121,7 @@ export class InjectableCompiler {
|
||||
}
|
||||
|
||||
compile(injectable: CompileInjectableMetadata, ctx: OutputContext): void {
|
||||
if (injectable.providedIn) {
|
||||
if (this.alwaysGenerateDef || injectable.providedIn !== undefined) {
|
||||
const className = identifierName(injectable.type) !;
|
||||
const clazz = new o.ClassStmt(
|
||||
className, null,
|
||||
|
@ -12,9 +12,9 @@ import {assertArrayOfStrings, assertInterpolationSymbols} from './assertions';
|
||||
import * as cpl from './compile_metadata';
|
||||
import {CompileReflector} from './compile_reflector';
|
||||
import {CompilerConfig} from './config';
|
||||
import {ChangeDetectionStrategy, Component, Directive, Injectable, ModuleWithProviders, Provider, Query, SchemaMetadata, Type, ViewEncapsulation, createAttribute, createComponent, createHost, createInject, createInjectable, createInjectionToken, createOptional, createSelf, createSkipSelf} from './core';
|
||||
import {ChangeDetectionStrategy, Component, Directive, Injectable, ModuleWithProviders, Provider, Query, SchemaMetadata, Type, ViewEncapsulation, createAttribute, createComponent, createHost, createInject, createInjectable, createInjectionToken, createNgModule, createOptional, createSelf, createSkipSelf} from './core';
|
||||
import {DirectiveNormalizer} from './directive_normalizer';
|
||||
import {DirectiveResolver} from './directive_resolver';
|
||||
import {DirectiveResolver, findLast} from './directive_resolver';
|
||||
import {Identifiers} from './identifiers';
|
||||
import {getAllLifecycleHooks} from './lifecycle_reflector';
|
||||
import {HtmlParser} from './ml_parser/html_parser';
|
||||
@ -44,6 +44,7 @@ export class CompileMetadataResolver {
|
||||
private _pipeCache = new Map<Type, cpl.CompilePipeMetadata>();
|
||||
private _ngModuleCache = new Map<Type, cpl.CompileNgModuleMetadata>();
|
||||
private _ngModuleOfTypes = new Map<Type, Type>();
|
||||
private _shallowModuleCache = new Map<Type, cpl.CompileShallowModuleMetadata>();
|
||||
|
||||
constructor(
|
||||
private _config: CompilerConfig, private _htmlParser: HtmlParser,
|
||||
@ -477,6 +478,26 @@ export class CompileMetadataResolver {
|
||||
return Promise.all(loading);
|
||||
}
|
||||
|
||||
getShallowModuleMetadata(moduleType: any): cpl.CompileShallowModuleMetadata|null {
|
||||
let compileMeta = this._shallowModuleCache.get(moduleType);
|
||||
if (compileMeta) {
|
||||
return compileMeta;
|
||||
}
|
||||
|
||||
const ngModuleMeta =
|
||||
findLast(this._reflector.shallowAnnotations(moduleType), createNgModule.isTypeOf);
|
||||
|
||||
compileMeta = {
|
||||
type: this._getTypeMetadata(moduleType),
|
||||
rawExports: ngModuleMeta.exports,
|
||||
rawImports: ngModuleMeta.imports,
|
||||
rawProviders: ngModuleMeta.providers,
|
||||
};
|
||||
|
||||
this._shallowModuleCache.set(moduleType, compileMeta);
|
||||
return compileMeta;
|
||||
}
|
||||
|
||||
getNgModuleMetadata(
|
||||
moduleType: any, throwIfNotFound = true,
|
||||
alreadyCollecting: Set<any>|null = null): cpl.CompileNgModuleMetadata|null {
|
||||
|
29
packages/compiler/src/output/map_util.ts
Normal file
29
packages/compiler/src/output/map_util.ts
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import * as o from './output_ast';
|
||||
|
||||
export type MapEntry = {
|
||||
key: string,
|
||||
quoted: boolean,
|
||||
value: o.Expression
|
||||
};
|
||||
|
||||
export type MapLiteral = MapEntry[];
|
||||
|
||||
export function mapEntry(key: string, value: o.Expression): MapEntry {
|
||||
return {key, value, quoted: false};
|
||||
}
|
||||
|
||||
export function mapLiteral(obj: {[key: string]: o.Expression}): o.Expression {
|
||||
return o.literalMap(Object.keys(obj).map(key => ({
|
||||
key,
|
||||
quoted: false,
|
||||
value: obj[key],
|
||||
})));
|
||||
}
|
@ -102,6 +102,11 @@ export class Identifiers {
|
||||
moduleName: CORE,
|
||||
};
|
||||
|
||||
static defineInjector: o.ExternalReference = {
|
||||
name: 'defineInjector',
|
||||
moduleName: CORE,
|
||||
};
|
||||
|
||||
static definePipe: o.ExternalReference = {name: 'ɵdefinePipe', moduleName: CORE};
|
||||
|
||||
static query: o.ExternalReference = {name: 'ɵQ', moduleName: CORE};
|
||||
|
60
packages/compiler/src/render3/r3_module_compiler.ts
Normal file
60
packages/compiler/src/render3/r3_module_compiler.ts
Normal file
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {StaticSymbol} from '../aot/static_symbol';
|
||||
import {CompileShallowModuleMetadata, identifierName} from '../compile_metadata';
|
||||
import {InjectableCompiler} from '../injectable_compiler';
|
||||
import {mapLiteral} from '../output/map_util';
|
||||
import * as o from '../output/output_ast';
|
||||
import {OutputContext} from '../util';
|
||||
|
||||
import {Identifiers as R3} from './r3_identifiers';
|
||||
|
||||
const EMPTY_ARRAY = o.literalArr([]);
|
||||
|
||||
function convertMetaToOutput(meta: any, ctx: OutputContext): o.Expression {
|
||||
if (Array.isArray(meta)) {
|
||||
return o.literalArr(meta.map(entry => convertMetaToOutput(entry, ctx)));
|
||||
} else if (meta instanceof StaticSymbol) {
|
||||
return ctx.importExpr(meta);
|
||||
} else if (meta == null) {
|
||||
return o.literal(meta);
|
||||
} else {
|
||||
throw new Error(`Internal error: Unsupported or unknown metadata: ${meta}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function compileNgModule(
|
||||
ctx: OutputContext, ngModule: CompileShallowModuleMetadata,
|
||||
injectableCompiler: InjectableCompiler): void {
|
||||
const className = identifierName(ngModule.type) !;
|
||||
|
||||
const rawImports = ngModule.rawImports ? [ngModule.rawImports] : [];
|
||||
const rawExports = ngModule.rawExports ? [ngModule.rawExports] : [];
|
||||
|
||||
const injectorDefArg = mapLiteral({
|
||||
'factory':
|
||||
injectableCompiler.factoryFor({type: ngModule.type, symbol: ngModule.type.reference}, ctx),
|
||||
'providers': convertMetaToOutput(ngModule.rawProviders, ctx),
|
||||
'imports': convertMetaToOutput([...rawImports, ...rawExports], ctx),
|
||||
});
|
||||
|
||||
const injectorDef = o.importExpr(R3.defineInjector).callFn([injectorDefArg]);
|
||||
|
||||
ctx.statements.push(new o.ClassStmt(
|
||||
/* name */ className,
|
||||
/* parent */ null,
|
||||
/* fields */[new o.ClassField(
|
||||
/* name */ 'ngInjectorDef',
|
||||
/* type */ o.INFERRED_TYPE,
|
||||
/* modifiers */[o.StmtModifier.Static],
|
||||
/* initializer */ injectorDef, )],
|
||||
/* getters */[],
|
||||
/* constructorMethod */ new o.ClassMethod(null, [], []),
|
||||
/* methods */[]));
|
||||
}
|
Reference in New Issue
Block a user