feat(ivy): generate ngInjectorDef for @NgModule in AOT mode (#24632)
This change generates ngInjectorDef as well as ngModuleDef for @NgModule annotated types, reflecting the dual nature of @NgModules as both compilation scopes and as DI configuration containers. This required implementing ngInjectorDef compilation in @angular/compiler as well as allowing for multiple generated definitions for a single decorator in the core of ngtsc. PR Close #24632
This commit is contained in:

committed by
Jason Aden

parent
166d90d2a9
commit
ae9418c7de
@ -116,7 +116,7 @@ export class ComponentDecoratorHandler implements DecoratorHandler<R3ComponentMe
|
||||
|
||||
const res = compileComponentFromMetadata(analysis, pool, makeBindingParser());
|
||||
return {
|
||||
field: 'ngComponentDef',
|
||||
name: 'ngComponentDef',
|
||||
initializer: res.expression,
|
||||
statements: pool.statements,
|
||||
type: res.type,
|
||||
|
@ -44,7 +44,7 @@ export class DirectiveDecoratorHandler implements DecoratorHandler<R3DirectiveMe
|
||||
const pool = new ConstantPool();
|
||||
const res = compileDirectiveFromMetadata(analysis, pool, makeBindingParser());
|
||||
return {
|
||||
field: 'ngDirectiveDef',
|
||||
name: 'ngDirectiveDef',
|
||||
initializer: res.expression,
|
||||
statements: pool.statements,
|
||||
type: res.type,
|
||||
|
@ -35,7 +35,7 @@ export class InjectableDecoratorHandler implements DecoratorHandler<R3Injectable
|
||||
compile(node: ts.ClassDeclaration, analysis: R3InjectableMetadata): CompileResult {
|
||||
const res = compileIvyInjectable(analysis);
|
||||
return {
|
||||
field: 'ngInjectableDef',
|
||||
name: 'ngInjectableDef',
|
||||
initializer: res.expression,
|
||||
statements: [],
|
||||
type: res.type,
|
||||
|
@ -6,29 +6,36 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ConstantPool, Expression, R3DirectiveMetadata, R3NgModuleMetadata, WrappedNodeExpr, compileNgModule, makeBindingParser, parseTemplate} from '@angular/compiler';
|
||||
import {ConstantPool, Expression, LiteralArrayExpr, R3DirectiveMetadata, R3InjectorMetadata, R3NgModuleMetadata, WrappedNodeExpr, compileInjector, compileNgModule, makeBindingParser, parseTemplate} from '@angular/compiler';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {Decorator} from '../../host';
|
||||
import {Decorator, ReflectionHost} from '../../host';
|
||||
import {Reference, ResolvedValue, reflectObjectLiteral, staticallyResolve} from '../../metadata';
|
||||
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
|
||||
|
||||
import {SelectorScopeRegistry} from './selector_scope';
|
||||
import {isAngularCore, referenceToExpression} from './util';
|
||||
import {getConstructorDependencies, isAngularCore, referenceToExpression} from './util';
|
||||
|
||||
export interface NgModuleAnalysis {
|
||||
ngModuleDef: R3NgModuleMetadata;
|
||||
ngInjectorDef: R3InjectorMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles @NgModule annotations to ngModuleDef fields.
|
||||
*
|
||||
* TODO(alxhub): handle injector side of things as well.
|
||||
*/
|
||||
export class NgModuleDecoratorHandler implements DecoratorHandler<R3NgModuleMetadata> {
|
||||
constructor(private checker: ts.TypeChecker, private scopeRegistry: SelectorScopeRegistry) {}
|
||||
export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalysis> {
|
||||
constructor(
|
||||
private checker: ts.TypeChecker, private reflector: ReflectionHost,
|
||||
private scopeRegistry: SelectorScopeRegistry) {}
|
||||
|
||||
detect(decorators: Decorator[]): Decorator|undefined {
|
||||
return decorators.find(decorator => decorator.name === 'NgModule' && isAngularCore(decorator));
|
||||
}
|
||||
|
||||
analyze(node: ts.ClassDeclaration, decorator: Decorator): AnalysisOutput<R3NgModuleMetadata> {
|
||||
analyze(node: ts.ClassDeclaration, decorator: Decorator): AnalysisOutput<NgModuleAnalysis> {
|
||||
if (decorator.args === null || decorator.args.length !== 1) {
|
||||
throw new Error(`Incorrect number of arguments to @NgModule decorator`);
|
||||
}
|
||||
@ -66,26 +73,51 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<R3NgModuleMeta
|
||||
|
||||
const context = node.getSourceFile();
|
||||
|
||||
const ngModuleDef: R3NgModuleMetadata = {
|
||||
type: new WrappedNodeExpr(node.name !),
|
||||
bootstrap: [],
|
||||
declarations: declarations.map(decl => referenceToExpression(decl, context)),
|
||||
exports: exports.map(exp => referenceToExpression(exp, context)),
|
||||
imports: imports.map(imp => referenceToExpression(imp, context)),
|
||||
emitInline: false,
|
||||
};
|
||||
|
||||
const providers: Expression = ngModule.has('providers') ?
|
||||
new WrappedNodeExpr(ngModule.get('providers') !) :
|
||||
new LiteralArrayExpr([]);
|
||||
|
||||
const ngInjectorDef: R3InjectorMetadata = {
|
||||
name: node.name !.text,
|
||||
type: new WrappedNodeExpr(node.name !),
|
||||
deps: getConstructorDependencies(node, this.reflector), providers,
|
||||
imports: new LiteralArrayExpr(
|
||||
[...imports, ...exports].map(imp => referenceToExpression(imp, context))),
|
||||
};
|
||||
|
||||
return {
|
||||
analysis: {
|
||||
type: new WrappedNodeExpr(node.name !),
|
||||
bootstrap: [],
|
||||
declarations: declarations.map(decl => referenceToExpression(decl, context)),
|
||||
exports: exports.map(exp => referenceToExpression(exp, context)),
|
||||
imports: imports.map(imp => referenceToExpression(imp, context)),
|
||||
emitInline: false,
|
||||
ngModuleDef, ngInjectorDef,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
compile(node: ts.ClassDeclaration, analysis: R3NgModuleMetadata): CompileResult {
|
||||
const res = compileNgModule(analysis);
|
||||
return {
|
||||
field: 'ngModuleDef',
|
||||
initializer: res.expression,
|
||||
statements: [],
|
||||
type: res.type,
|
||||
};
|
||||
compile(node: ts.ClassDeclaration, analysis: NgModuleAnalysis): CompileResult[] {
|
||||
const ngInjectorDef = compileInjector(analysis.ngInjectorDef);
|
||||
const ngModuleDef = compileNgModule(analysis.ngModuleDef);
|
||||
return [
|
||||
{
|
||||
name: 'ngModuleDef',
|
||||
initializer: ngModuleDef.expression,
|
||||
statements: [],
|
||||
type: ngModuleDef.type,
|
||||
},
|
||||
{
|
||||
name: 'ngInjectorDef',
|
||||
initializer: ngInjectorDef.expression,
|
||||
statements: [],
|
||||
type: ngInjectorDef.type,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user