refactor: use view engine also for NgModuleFactorys (#16658)

* refactor(core): provide error message in stack for reflective DI

Fixes #16355

* fix(compiler): make AOT work with `noUnusedParameters`

Fixes #15532

* refactor: use view engine also for `NgModuleFactory`s

This is a prerequisite for being able to mock providers
in AOTed code later on.
This commit is contained in:
Tobias Bosch
2017-05-11 10:26:02 -07:00
committed by Jason Aden
parent b9521b568f
commit ce1d7c4a6e
25 changed files with 800 additions and 604 deletions

View File

@ -54,8 +54,13 @@ export class CodegenComponentFactoryResolver implements ComponentFactoryResolver
}
resolveComponentFactory<T>(component: {new (...args: any[]): T}): ComponentFactory<T> {
let factory = this._factories.get(component) || this._parent.resolveComponentFactory(component);
let factory = this._factories.get(component);
if (!factory && this._parent) {
factory = this._parent.resolveComponentFactory(component);
}
if (!factory) {
throw noComponentFactoryError(component);
}
return new ComponentFactoryBoundToModule(factory, this._ngModule);
}
}

View File

@ -6,12 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Injector, THROW_IF_NOT_FOUND} from '../di/injector';
import {Injector} from '../di/injector';
import {Type} from '../type';
import {stringify} from '../util';
import {ComponentFactory} from './component_factory';
import {CodegenComponentFactoryResolver, ComponentFactoryBoundToModule, ComponentFactoryResolver} from './component_factory_resolver';
import {ComponentFactoryResolver} from './component_factory_resolver';
/**
@ -50,76 +48,16 @@ export abstract class NgModuleRef<T> {
abstract onDestroy(callback: () => void): void;
}
export interface InternalNgModuleRef<T> extends NgModuleRef<T> {
// Note: we are using the prefix _ as NgModuleData is an NgModuleRef and therefore directly
// exposed to the user.
_bootstrapComponents: Type<any>[];
}
/**
* @experimental
*/
export class NgModuleFactory<T> {
constructor(
private _injectorClass: {new (parentInjector: Injector): NgModuleInjector<T>},
private _moduleType: Type<T>) {}
get moduleType(): Type<T> { return this._moduleType; }
create(parentInjector: Injector|null): NgModuleRef<T> {
const instance = new this._injectorClass(parentInjector || Injector.NULL);
instance.create();
return instance;
}
}
const _UNDEFINED = new Object();
export abstract class NgModuleInjector<T> implements Injector, NgModuleRef<T> {
bootstrapFactories: ComponentFactory<any>[];
instance: T;
private _destroyListeners: (() => void)[] = [];
private _destroyed: boolean = false;
private _cmpFactoryResolver: CodegenComponentFactoryResolver;
constructor(
public parent: Injector, factories: ComponentFactory<any>[],
bootstrapFactories: ComponentFactory<any>[]) {
this.bootstrapFactories =
bootstrapFactories.map(f => new ComponentFactoryBoundToModule(f, this));
this._cmpFactoryResolver = new CodegenComponentFactoryResolver(
factories, parent.get(ComponentFactoryResolver, ComponentFactoryResolver.NULL), this);
}
create() { this.instance = this.createInternal(); }
abstract createInternal(): T;
get(token: any, notFoundValue: any = THROW_IF_NOT_FOUND): any {
if (token === Injector || token === NgModuleRef) {
return this;
}
if (token === ComponentFactoryResolver) {
return this._cmpFactoryResolver;
}
const result = this.getInternal(token, _UNDEFINED);
return result === _UNDEFINED ? this.parent.get(token, notFoundValue) : result;
}
abstract getInternal(token: any, notFoundValue: any): any;
get injector(): Injector { return this; }
get componentFactoryResolver(): ComponentFactoryResolver { return this._cmpFactoryResolver; }
destroy(): void {
if (this._destroyed) {
throw new Error(
`The ng module ${stringify(this.instance.constructor)} has already been destroyed.`);
}
this._destroyed = true;
this.destroyInternal();
this._destroyListeners.forEach((listener) => listener());
}
onDestroy(callback: () => void): void { this._destroyListeners.push(callback); }
abstract destroyInternal(): void;
export abstract class NgModuleFactory<T> {
abstract get moduleType(): Type<T>;
abstract create(parentInjector: Injector|null): NgModuleRef<T>;
}