@ -15,6 +15,8 @@ export {
|
||||
detectChanges as ɵdetectChanges,
|
||||
renderComponent as ɵrenderComponent,
|
||||
ComponentType as ɵComponentType,
|
||||
ComponentFactory as ɵRender3ComponentFactory,
|
||||
ComponentRef as ɵRender3ComponentRef,
|
||||
DirectiveType as ɵDirectiveType,
|
||||
RenderFlags as ɵRenderFlags,
|
||||
directiveInject as ɵdirectiveInject,
|
||||
@ -29,6 +31,7 @@ export {
|
||||
InheritDefinitionFeature as ɵInheritDefinitionFeature,
|
||||
NgOnChangesFeature as ɵNgOnChangesFeature,
|
||||
NgModuleType as ɵNgModuleType,
|
||||
NgModuleRef as ɵRender3NgModuleRef,
|
||||
CssSelectorList as ɵCssSelectorList,
|
||||
markDirty as ɵmarkDirty,
|
||||
NgModuleFactory as ɵNgModuleFactory,
|
||||
@ -95,6 +98,7 @@ export {
|
||||
ld as ɵld,
|
||||
Pp as ɵPp,
|
||||
ComponentDef as ɵComponentDef,
|
||||
ComponentDefInternal as ɵComponentDefInternal,
|
||||
DirectiveDef as ɵDirectiveDef,
|
||||
PipeDef as ɵPipeDef,
|
||||
whenRendered as ɵwhenRendered,
|
||||
@ -112,14 +116,38 @@ export {
|
||||
iM as ɵiM,
|
||||
I18nInstruction as ɵI18nInstruction,
|
||||
I18nExpInstruction as ɵI18nExpInstruction,
|
||||
WRAP_RENDERER_FACTORY2 as ɵWRAP_RENDERER_FACTORY2,
|
||||
Render3DebugRendererFactory2 as ɵRender3DebugRendererFactory2,
|
||||
} from './render3/index';
|
||||
export {NgModuleDef as ɵNgModuleDef} from './metadata/ng_module';
|
||||
|
||||
|
||||
export {
|
||||
compileNgModuleDefs as ɵcompileNgModuleDefs,
|
||||
patchComponentDefWithScope as ɵpatchComponentDefWithScope,
|
||||
} from './render3/jit/module';
|
||||
|
||||
export {
|
||||
compileComponent as ɵcompileComponent,
|
||||
compileDirective as ɵcompileDirective,
|
||||
} from './render3/jit/directive';
|
||||
|
||||
export {
|
||||
compilePipe as ɵcompilePipe,
|
||||
} from './render3/jit/pipe';
|
||||
|
||||
export {
|
||||
NgModuleDef as ɵNgModuleDef,
|
||||
NgModuleDefInternal as ɵNgModuleDefInternal,
|
||||
NgModuleTransitiveScopes as ɵNgModuleTransitiveScopes,
|
||||
} from './metadata/ng_module';
|
||||
|
||||
export {
|
||||
sanitizeHtml as ɵsanitizeHtml,
|
||||
sanitizeStyle as ɵsanitizeStyle,
|
||||
sanitizeUrl as ɵsanitizeUrl,
|
||||
sanitizeResourceUrl as ɵsanitizeResourceUrl,
|
||||
} from './sanitization/sanitization';
|
||||
|
||||
export {
|
||||
bypassSanitizationTrustHtml as ɵbypassSanitizationTrustHtml,
|
||||
bypassSanitizationTrustStyle as ɵbypassSanitizationTrustStyle,
|
||||
@ -127,4 +155,4 @@ export {
|
||||
bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl,
|
||||
bypassSanitizationTrustResourceUrl as ɵbypassSanitizationTrustResourceUrl,
|
||||
} from './sanitization/bypass';
|
||||
// clang-format on
|
||||
// clang-format on
|
@ -6,12 +6,12 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ChangeDetectorRef} from '../change_detection/change_detector_ref';
|
||||
import {ChangeDetectorRef as ViewEngine_ChangeDetectorRef} from '../change_detection/change_detector_ref';
|
||||
import {InjectionToken} from '../di/injection_token';
|
||||
import {Injector, inject} from '../di/injector';
|
||||
import {ComponentFactory as viewEngine_ComponentFactory, ComponentRef as viewEngine_ComponentRef} from '../linker/component_factory';
|
||||
import {ComponentFactoryResolver as viewEngine_ComponentFactoryResolver} from '../linker/component_factory_resolver';
|
||||
import {ElementRef} from '../linker/element_ref';
|
||||
import {ElementRef as viewEngine_ElementRef} from '../linker/element_ref';
|
||||
import {NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory';
|
||||
import {RendererFactory2} from '../render/api';
|
||||
import {Type} from '../type';
|
||||
@ -21,7 +21,7 @@ import {LifecycleHooksFeature, createRootContext} from './component';
|
||||
import {baseDirectiveCreate, createLNode, createLViewData, createTView, elementCreate, enterView, hostElement, initChangeDetectorIfExisting, locateHostElement, renderEmbeddedTemplate} from './instructions';
|
||||
import {ComponentDefInternal, ComponentType, RenderFlags} from './interfaces/definition';
|
||||
import {LElementNode, TNode, TNodeType} from './interfaces/node';
|
||||
import {RElement, domRendererFactory3} from './interfaces/renderer';
|
||||
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
||||
import {CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
|
||||
import {RootViewRef, ViewRef} from './view_ref';
|
||||
|
||||
@ -55,8 +55,20 @@ export const ROOT_CONTEXT = new InjectionToken<RootContext>(
|
||||
* A change detection scheduler token for {@link RootContext}. This token is the default value used
|
||||
* for the default `RootContext` found in the {@link ROOT_CONTEXT} token.
|
||||
*/
|
||||
export const SCHEDULER = new InjectionToken<((fn: () => void) => void)>(
|
||||
'SCHEDULER_TOKEN', {providedIn: 'root', factory: () => requestAnimationFrame.bind(window)});
|
||||
export const SCHEDULER = new InjectionToken<((fn: () => void) => void)>('SCHEDULER_TOKEN', {
|
||||
providedIn: 'root',
|
||||
factory: () => {
|
||||
const useRaf = typeof requestAnimationFrame !== 'undefined' && typeof window !== 'undefined';
|
||||
return useRaf ? requestAnimationFrame.bind(window) : setTimeout;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* A function used to wrap the `RendererFactory2`.
|
||||
* Used in tests to change the `RendererFactory2` into a `DebugRendererFactory2`.
|
||||
*/
|
||||
export const WRAP_RENDERER_FACTORY2 =
|
||||
new InjectionToken<(rf: RendererFactory2) => RendererFactory2>('WRAP_RENDERER_FACTORY2');
|
||||
|
||||
/**
|
||||
* Render3 implementation of {@link viewEngine_ComponentFactory}.
|
||||
@ -65,9 +77,11 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
|
||||
selector: string;
|
||||
componentType: Type<any>;
|
||||
ngContentSelectors: string[];
|
||||
|
||||
get inputs(): {propName: string; templateName: string;}[] {
|
||||
return toRefArray(this.componentDef.inputs);
|
||||
}
|
||||
|
||||
get outputs(): {propName: string; templateName: string;}[] {
|
||||
return toRefArray(this.componentDef.outputs);
|
||||
}
|
||||
@ -84,8 +98,15 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
|
||||
ngModule?: viewEngine_NgModuleRef<any>|undefined): viewEngine_ComponentRef<T> {
|
||||
const isInternalRootView = rootSelectorOrNode === undefined;
|
||||
|
||||
const rendererFactory =
|
||||
ngModule ? ngModule.injector.get(RendererFactory2) : domRendererFactory3;
|
||||
let rendererFactory: RendererFactory3;
|
||||
|
||||
if (ngModule) {
|
||||
const wrapper = ngModule.injector.get(WRAP_RENDERER_FACTORY2, (v: RendererFactory2) => v);
|
||||
rendererFactory = wrapper(ngModule.injector.get(RendererFactory2)) as RendererFactory3;
|
||||
} else {
|
||||
rendererFactory = domRendererFactory3;
|
||||
}
|
||||
|
||||
const hostNode = isInternalRootView ?
|
||||
elementCreate(this.selector, rendererFactory.createRenderer(null, this.componentDef)) :
|
||||
locateHostElement(rendererFactory, rootSelectorOrNode);
|
||||
@ -116,11 +137,10 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
|
||||
elementNode = hostElement(componentTag, hostNode, this.componentDef);
|
||||
|
||||
// Create directive instance with factory() and store at index 0 in directives array
|
||||
rootContext.components.push(
|
||||
component = baseDirectiveCreate(0, this.componentDef.factory(), this.componentDef) as T);
|
||||
component = baseDirectiveCreate(0, this.componentDef.factory(), this.componentDef);
|
||||
rootContext.components.push(component);
|
||||
initChangeDetectorIfExisting(elementNode.nodeInjector, component, elementNode.data !);
|
||||
(elementNode.data as LViewData)[CONTEXT] = component;
|
||||
|
||||
// TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
|
||||
// executed here?
|
||||
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
|
||||
@ -177,11 +197,11 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
|
||||
*/
|
||||
export class ComponentRef<T> extends viewEngine_ComponentRef<T> {
|
||||
destroyCbs: (() => void)[]|null = [];
|
||||
location: ElementRef<any>;
|
||||
location: viewEngine_ElementRef<any>;
|
||||
injector: Injector;
|
||||
instance: T;
|
||||
hostView: ViewRef<T>;
|
||||
changeDetectorRef: ChangeDetectorRef;
|
||||
changeDetectorRef: ViewEngine_ChangeDetectorRef;
|
||||
componentType: Type<T>;
|
||||
|
||||
constructor(
|
||||
@ -192,7 +212,7 @@ export class ComponentRef<T> extends viewEngine_ComponentRef<T> {
|
||||
this.hostView = this.changeDetectorRef = new RootViewRef<T>(rootView);
|
||||
this.hostView._lViewNode = createLNode(-1, TNodeType.View, null, null, null, rootView);
|
||||
this.injector = injector;
|
||||
this.location = new ElementRef(hostNode);
|
||||
this.location = new viewEngine_ElementRef(hostNode);
|
||||
this.componentType = componentType;
|
||||
}
|
||||
|
||||
@ -205,4 +225,4 @@ export class ComponentRef<T> extends viewEngine_ComponentRef<T> {
|
||||
ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed');
|
||||
this.destroyCbs !.push(callback);
|
||||
}
|
||||
}
|
||||
}
|
115
packages/core/src/render3/debug.ts
Normal file
115
packages/core/src/render3/debug.ts
Normal file
@ -0,0 +1,115 @@
|
||||
/**
|
||||
* @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 {Injector} from '../di/injector';
|
||||
import {Renderer2, RendererType2} from '../render/api';
|
||||
import {DebugContext} from '../view';
|
||||
import {DebugRenderer2, DebugRendererFactory2} from '../view/services';
|
||||
|
||||
import * as di from './di';
|
||||
import {NG_HOST_SYMBOL, _getViewData} from './instructions';
|
||||
import {LElementNode} from './interfaces/node';
|
||||
import {CONTEXT, DIRECTIVES, LViewData, TVIEW} from './interfaces/view';
|
||||
|
||||
/**
|
||||
* Adapts the DebugRendererFactory2 to create a DebugRenderer2 specific for IVY.
|
||||
*
|
||||
* The created DebugRenderer know how to create a Debug Context specific to IVY.
|
||||
*/
|
||||
export class Render3DebugRendererFactory2 extends DebugRendererFactory2 {
|
||||
createRenderer(element: any, renderData: RendererType2|null): Renderer2 {
|
||||
const renderer = super.createRenderer(element, renderData) as DebugRenderer2;
|
||||
renderer.debugContextFactory = () => new Render3DebugContext(_getViewData());
|
||||
return renderer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores context information about view nodes.
|
||||
*
|
||||
* Used in tests to retrieve information those nodes.
|
||||
*/
|
||||
class Render3DebugContext implements DebugContext {
|
||||
readonly nodeIndex: number|null;
|
||||
|
||||
constructor(private viewData: LViewData) {
|
||||
// The LNode will be created next and appended to viewData
|
||||
this.nodeIndex = viewData ? viewData.length : null;
|
||||
}
|
||||
|
||||
get view(): any { return this.viewData; }
|
||||
|
||||
get injector(): Injector {
|
||||
if (this.nodeIndex !== null) {
|
||||
const lElementNode: LElementNode = this.view[this.nodeIndex];
|
||||
const nodeInjector = lElementNode.nodeInjector;
|
||||
|
||||
if (nodeInjector) {
|
||||
return new di.NodeInjector(nodeInjector);
|
||||
}
|
||||
}
|
||||
return Injector.NULL;
|
||||
}
|
||||
|
||||
get component(): any {
|
||||
// TODO(vicb): why/when
|
||||
if (this.nodeIndex === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const tView = this.view[TVIEW];
|
||||
const components: number[]|null = tView.components;
|
||||
|
||||
return (components && components.indexOf(this.nodeIndex) == -1) ?
|
||||
null :
|
||||
this.view[this.nodeIndex].data[CONTEXT];
|
||||
}
|
||||
|
||||
// TODO(vicb): add view providers when supported
|
||||
get providerTokens(): any[] {
|
||||
const matchedDirectives: any[] = [];
|
||||
|
||||
// TODO(vicb): why/when
|
||||
if (this.nodeIndex === null) {
|
||||
return matchedDirectives;
|
||||
}
|
||||
|
||||
const directives = this.view[DIRECTIVES];
|
||||
|
||||
if (directives) {
|
||||
const currentNode = this.view[this.nodeIndex];
|
||||
for (let dirIndex = 0; dirIndex < directives.length; dirIndex++) {
|
||||
const directive = directives[dirIndex];
|
||||
if (directive[NG_HOST_SYMBOL] === currentNode) {
|
||||
matchedDirectives.push(directive.constructor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return matchedDirectives;
|
||||
}
|
||||
|
||||
get references(): {[key: string]: any} {
|
||||
// TODO(vicb): implement retrieving references
|
||||
throw new Error('Not implemented yet in ivy');
|
||||
}
|
||||
|
||||
get context(): any {
|
||||
if (this.nodeIndex === null) {
|
||||
return null;
|
||||
}
|
||||
const lNode = this.view[this.nodeIndex];
|
||||
return lNode.view[CONTEXT];
|
||||
}
|
||||
|
||||
get componentRenderElement(): any { throw new Error('Not implemented in ivy'); }
|
||||
|
||||
get renderNode(): any { throw new Error('Not implemented in ivy'); }
|
||||
|
||||
// TODO(vicb): check previous implementation
|
||||
logError(console: Console, ...values: any[]): void { console.error(...values); }
|
||||
}
|
@ -605,7 +605,7 @@ export function getOrCreateContainerRef(di: LInjector): viewEngine.ViewContainer
|
||||
return di.viewContainerRef;
|
||||
}
|
||||
|
||||
class NodeInjector implements Injector {
|
||||
export class NodeInjector implements Injector {
|
||||
constructor(private _lInjector: LInjector) {}
|
||||
|
||||
get(token: any): any {
|
||||
|
@ -89,7 +89,9 @@ export function NgOnChangesFeature<T>(definition: DirectiveDefInternal<T>): void
|
||||
}
|
||||
|
||||
if (setter) setter.call(this, value);
|
||||
}
|
||||
},
|
||||
// Make the property configurable in dev mode to allow overriding in tests
|
||||
configurable: !!ngDevMode
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -13,13 +13,12 @@ import {NgOnChangesFeature} from './features/ng_onchanges_feature';
|
||||
import {PublicFeature} from './features/public_feature';
|
||||
import {ComponentDef, ComponentDefInternal, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveDefInternal, DirectiveType, PipeDef} from './interfaces/definition';
|
||||
|
||||
export {ComponentFactory, ComponentFactoryResolver, ComponentRef} from './component_ref';
|
||||
export {ComponentFactory, ComponentFactoryResolver, ComponentRef, WRAP_RENDERER_FACTORY2} from './component_ref';
|
||||
export {Render3DebugRendererFactory2} from './debug';
|
||||
export {QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, directiveInject, getFactoryOf, getInheritedFactory, injectAttribute, injectChangeDetectorRef, injectComponentFactoryResolver, injectElementRef, injectTemplateRef, injectViewContainerRef} from './di';
|
||||
export {RenderFlags} from './interfaces/definition';
|
||||
export {CssSelectorList} from './interfaces/projection';
|
||||
|
||||
|
||||
|
||||
// Naming scheme:
|
||||
// - Capital letters are for creating things: T(Text), E(Element), D(Directive), V(View),
|
||||
// C(Container), L(Listener)
|
||||
|
@ -30,8 +30,6 @@ import {StylingContext, allocStylingContext, createStylingContextTemplate, rende
|
||||
import {assertDataInRangeInternal, isDifferent, loadElementInternal, loadInternal, stringify} from './util';
|
||||
import {ViewRef} from './view_ref';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Directive (D) sets a property on all component instances using this constant as a key and the
|
||||
* component's host node (LElement) as the value. This is used in methods like detectChanges to
|
||||
@ -126,16 +124,6 @@ export function getCurrentView(): OpaqueViewState {
|
||||
return viewData as any as OpaqueViewState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function that returns the current LViewData instance.
|
||||
*
|
||||
* The getCurrentView() instruction should be used for anything public.
|
||||
*/
|
||||
export function _getViewData(): LViewData {
|
||||
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
|
||||
return viewData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores `contextViewData` to the given OpaqueViewState instance.
|
||||
*
|
||||
@ -207,6 +195,16 @@ export function getCreationMode(): boolean {
|
||||
*/
|
||||
let viewData: LViewData;
|
||||
|
||||
/**
|
||||
* Internal function that returns the current LViewData instance.
|
||||
*
|
||||
* The getCurrentView() instruction should be used for anything public.
|
||||
*/
|
||||
export function _getViewData(): LViewData {
|
||||
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
|
||||
return viewData;
|
||||
}
|
||||
|
||||
/**
|
||||
* The last viewData retrieved by nextContext().
|
||||
* Allows building nextContext() and reference() calls.
|
||||
|
@ -10,13 +10,12 @@ import {ConstantPool, R3DirectiveMetadata, WrappedNodeExpr, compileComponentFrom
|
||||
|
||||
import {Component, Directive, HostBinding, HostListener, Input, Output} from '../../metadata/directives';
|
||||
import {componentNeedsResolution, maybeQueueResolutionOfComponentResources} from '../../metadata/resource_loading';
|
||||
import {ReflectionCapabilities} from '../../reflection/reflection_capabilities';
|
||||
import {Type} from '../../type';
|
||||
import {stringify} from '../../util';
|
||||
|
||||
import {angularCoreEnv} from './environment';
|
||||
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF} from './fields';
|
||||
import {patchComponentDefWithScope} from './module';
|
||||
import {patchComponentDefWithScope, transitiveScopesFor} from './module';
|
||||
import {getReflect, reflectDependencies} from './util';
|
||||
|
||||
type StringMap = {
|
||||
@ -33,12 +32,12 @@ type StringMap = {
|
||||
* until the global queue has been resolved with a call to `resolveComponentResources`.
|
||||
*/
|
||||
export function compileComponent(type: Type<any>, metadata: Component): void {
|
||||
let def: any = null;
|
||||
let ngComponentDef: any = null;
|
||||
// Metadata may have resources which need to be resolved.
|
||||
maybeQueueResolutionOfComponentResources(metadata);
|
||||
Object.defineProperty(type, NG_COMPONENT_DEF, {
|
||||
get: () => {
|
||||
if (def === null) {
|
||||
if (ngComponentDef === null) {
|
||||
if (componentNeedsResolution(metadata)) {
|
||||
const error = [`Component '${stringify(type)}' is not resolved:`];
|
||||
if (metadata.templateUrl) {
|
||||
@ -78,7 +77,7 @@ export function compileComponent(type: Type<any>, metadata: Component): void {
|
||||
constantPool, makeBindingParser());
|
||||
const preStatements = [...constantPool.statements, ...res.statements];
|
||||
|
||||
def = jitExpression(
|
||||
ngComponentDef = jitExpression(
|
||||
res.expression, angularCoreEnv, `ng://${type.name}/ngComponentDef.js`, preStatements);
|
||||
|
||||
// If component compilation is async, then the @NgModule annotation which declares the
|
||||
@ -86,11 +85,14 @@ export function compileComponent(type: Type<any>, metadata: Component): void {
|
||||
// allows the component to patch itself with directiveDefs from the module after it finishes
|
||||
// compiling.
|
||||
if (hasSelectorScope(type)) {
|
||||
patchComponentDefWithScope(def, type.ngSelectorScope);
|
||||
const scopes = transitiveScopesFor(type.ngSelectorScope);
|
||||
patchComponentDefWithScope(ngComponentDef, scopes);
|
||||
}
|
||||
}
|
||||
return def;
|
||||
return ngComponentDef;
|
||||
},
|
||||
// Make the property configurable in dev mode to allow overriding in tests
|
||||
configurable: !!ngDevMode,
|
||||
});
|
||||
}
|
||||
|
||||
@ -107,23 +109,24 @@ function hasSelectorScope<T>(component: Type<T>): component is Type<T>&
|
||||
* will resolve when compilation completes and the directive becomes usable.
|
||||
*/
|
||||
export function compileDirective(type: Type<any>, directive: Directive): void {
|
||||
let def: any = null;
|
||||
let ngDirectiveDef: any = null;
|
||||
Object.defineProperty(type, NG_DIRECTIVE_DEF, {
|
||||
get: () => {
|
||||
if (def === null) {
|
||||
if (ngDirectiveDef === null) {
|
||||
const constantPool = new ConstantPool();
|
||||
const sourceMapUrl = `ng://${type && type.name}/ngDirectiveDef.js`;
|
||||
const res = compileR3Directive(
|
||||
directiveMetadata(type, directive), constantPool, makeBindingParser());
|
||||
const preStatements = [...constantPool.statements, ...res.statements];
|
||||
def = jitExpression(res.expression, angularCoreEnv, sourceMapUrl, preStatements);
|
||||
ngDirectiveDef = jitExpression(res.expression, angularCoreEnv, sourceMapUrl, preStatements);
|
||||
}
|
||||
return def;
|
||||
return ngDirectiveDef;
|
||||
},
|
||||
// Make the property configurable in dev mode to allow overriding in tests
|
||||
configurable: !!ngDevMode,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function extendsDirectlyFromObject(type: Type<any>): boolean {
|
||||
return Object.getPrototypeOf(type.prototype) === Object.prototype;
|
||||
}
|
||||
|
@ -18,15 +18,28 @@ import {reflectDependencies} from './util';
|
||||
|
||||
const EMPTY_ARRAY: Type<any>[] = [];
|
||||
|
||||
export function compileNgModule(type: Type<any>, ngModule: NgModule): void {
|
||||
/**
|
||||
* Compiles a module in JIT mode.
|
||||
*
|
||||
* This function automatically gets called when a class has a `@NgModule` decorator.
|
||||
*/
|
||||
export function compileNgModule(moduleType: Type<any>, ngModule: NgModule): void {
|
||||
compileNgModuleDefs(moduleType, ngModule);
|
||||
setScopeOnDeclaredComponents(moduleType, ngModule);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles and adds the `ngModuleDef` and `ngInjectorDef` properties to the module class.
|
||||
*/
|
||||
export function compileNgModuleDefs(moduleType: Type<any>, ngModule: NgModule): void {
|
||||
const declarations: Type<any>[] = flatten(ngModule.declarations || EMPTY_ARRAY);
|
||||
|
||||
let ngModuleDef: any = null;
|
||||
Object.defineProperty(type, NG_MODULE_DEF, {
|
||||
Object.defineProperty(moduleType, NG_MODULE_DEF, {
|
||||
get: () => {
|
||||
if (ngModuleDef === null) {
|
||||
const meta: R3NgModuleMetadata = {
|
||||
type: wrap(type),
|
||||
type: wrap(moduleType),
|
||||
bootstrap: flatten(ngModule.bootstrap || EMPTY_ARRAY).map(wrap),
|
||||
declarations: declarations.map(wrapReference),
|
||||
imports: flatten(ngModule.imports || EMPTY_ARRAY)
|
||||
@ -38,21 +51,23 @@ export function compileNgModule(type: Type<any>, ngModule: NgModule): void {
|
||||
emitInline: true,
|
||||
};
|
||||
const res = compileR3NgModule(meta);
|
||||
ngModuleDef =
|
||||
jitExpression(res.expression, angularCoreEnv, `ng://${type.name}/ngModuleDef.js`, []);
|
||||
ngModuleDef = jitExpression(
|
||||
res.expression, angularCoreEnv, `ng://${moduleType.name}/ngModuleDef.js`, []);
|
||||
}
|
||||
return ngModuleDef;
|
||||
},
|
||||
// Make the property configurable in dev mode to allow overriding in tests
|
||||
configurable: !!ngDevMode,
|
||||
});
|
||||
|
||||
let ngInjectorDef: any = null;
|
||||
Object.defineProperty(type, NG_INJECTOR_DEF, {
|
||||
Object.defineProperty(moduleType, NG_INJECTOR_DEF, {
|
||||
get: () => {
|
||||
if (ngInjectorDef === null) {
|
||||
const meta: R3InjectorMetadata = {
|
||||
name: type.name,
|
||||
type: wrap(type),
|
||||
deps: reflectDependencies(type),
|
||||
name: moduleType.name,
|
||||
type: wrap(moduleType),
|
||||
deps: reflectDependencies(moduleType),
|
||||
providers: new WrappedNodeExpr(ngModule.providers || EMPTY_ARRAY),
|
||||
imports: new WrappedNodeExpr([
|
||||
ngModule.imports || EMPTY_ARRAY,
|
||||
@ -61,25 +76,36 @@ export function compileNgModule(type: Type<any>, ngModule: NgModule): void {
|
||||
};
|
||||
const res = compileInjector(meta);
|
||||
ngInjectorDef = jitExpression(
|
||||
res.expression, angularCoreEnv, `ng://${type.name}/ngInjectorDef.js`, res.statements);
|
||||
res.expression, angularCoreEnv, `ng://${moduleType.name}/ngInjectorDef.js`,
|
||||
res.statements);
|
||||
}
|
||||
return ngInjectorDef;
|
||||
},
|
||||
// Make the property configurable in dev mode to allow overriding in tests
|
||||
configurable: !!ngDevMode,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Some declared components may be compiled asynchronously, and thus may not have their
|
||||
* ngComponentDef set yet. If this is the case, then a reference to the module is written into
|
||||
* the `ngSelectorScope` property of the declared type.
|
||||
*/
|
||||
function setScopeOnDeclaredComponents(moduleType: Type<any>, ngModule: NgModule) {
|
||||
const declarations: Type<any>[] = flatten(ngModule.declarations || EMPTY_ARRAY);
|
||||
|
||||
const transitiveScopes = transitiveScopesFor(moduleType);
|
||||
|
||||
declarations.forEach(declaration => {
|
||||
// Some declared components may be compiled asynchronously, and thus may not have their
|
||||
// ngComponentDef set yet. If this is the case, then a reference to the module is written into
|
||||
// the `ngSelectorScope` property of the declared type.
|
||||
if (declaration.hasOwnProperty(NG_COMPONENT_DEF)) {
|
||||
// An `ngComponentDef` field exists - go ahead and patch the component directly.
|
||||
patchComponentDefWithScope(
|
||||
(declaration as Type<any>& {ngComponentDef: ComponentDefInternal<any>}).ngComponentDef,
|
||||
type);
|
||||
const component = declaration as Type<any>& {ngComponentDef: ComponentDefInternal<any>};
|
||||
const componentDef = component.ngComponentDef;
|
||||
patchComponentDefWithScope(componentDef, transitiveScopes);
|
||||
} else if (
|
||||
!declaration.hasOwnProperty(NG_DIRECTIVE_DEF) && !declaration.hasOwnProperty(NG_PIPE_DEF)) {
|
||||
// Set `ngSelectorScope` for future reference when the component compilation finishes.
|
||||
(declaration as Type<any>& {ngSelectorScope?: any}).ngSelectorScope = type;
|
||||
(declaration as Type<any>& {ngSelectorScope?: any}).ngSelectorScope = moduleType;
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -88,13 +114,13 @@ export function compileNgModule(type: Type<any>, ngModule: NgModule): void {
|
||||
* Patch the definition of a component with directives and pipes from the compilation scope of
|
||||
* a given module.
|
||||
*/
|
||||
export function patchComponentDefWithScope<C, M>(
|
||||
componentDef: ComponentDefInternal<C>, module: Type<M>) {
|
||||
componentDef.directiveDefs = () => Array.from(transitiveScopesFor(module).compilation.directives)
|
||||
export function patchComponentDefWithScope<C>(
|
||||
componentDef: ComponentDefInternal<C>, transitiveScopes: NgModuleTransitiveScopes) {
|
||||
componentDef.directiveDefs = () => Array.from(transitiveScopes.compilation.directives)
|
||||
.map(dir => dir.ngDirectiveDef || dir.ngComponentDef)
|
||||
.filter(def => !!def);
|
||||
componentDef.pipeDefs = () =>
|
||||
Array.from(transitiveScopesFor(module).compilation.pipes).map(pipe => pipe.ngPipeDef);
|
||||
Array.from(transitiveScopes.compilation.pipes).map(pipe => pipe.ngPipeDef);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,7 +130,7 @@ export function patchComponentDefWithScope<C, M>(
|
||||
* on modules with components that have not fully compiled yet, but the result should not be used
|
||||
* until they have.
|
||||
*/
|
||||
function transitiveScopesFor<T>(moduleType: Type<T>): NgModuleTransitiveScopes {
|
||||
export function transitiveScopesFor<T>(moduleType: Type<T>): NgModuleTransitiveScopes {
|
||||
if (!isNgModule(moduleType)) {
|
||||
throw new Error(`${moduleType.name} does not have an ngModuleDef`);
|
||||
}
|
||||
|
@ -17,10 +17,10 @@ import {NG_PIPE_DEF} from './fields';
|
||||
import {reflectDependencies} from './util';
|
||||
|
||||
export function compilePipe(type: Type<any>, meta: Pipe): void {
|
||||
let def: any = null;
|
||||
let ngPipeDef: any = null;
|
||||
Object.defineProperty(type, NG_PIPE_DEF, {
|
||||
get: () => {
|
||||
if (def === null) {
|
||||
if (ngPipeDef === null) {
|
||||
const sourceMapUrl = `ng://${stringify(type)}/ngPipeDef.js`;
|
||||
|
||||
const name = type.name;
|
||||
@ -32,9 +32,11 @@ export function compilePipe(type: Type<any>, meta: Pipe): void {
|
||||
pure: meta.pure !== undefined ? meta.pure : true,
|
||||
});
|
||||
|
||||
def = jitExpression(res.expression, angularCoreEnv, sourceMapUrl, res.statements);
|
||||
ngPipeDef = jitExpression(res.expression, angularCoreEnv, sourceMapUrl, res.statements);
|
||||
}
|
||||
return def;
|
||||
}
|
||||
return ngPipeDef;
|
||||
},
|
||||
// Make the property configurable in dev mode to allow overriding in tests
|
||||
configurable: !!ngDevMode,
|
||||
});
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
|
||||
declare global {
|
||||
const ngDevMode: null|NgDevModePerfCounters;
|
||||
interface NgDevModePerfCounters {
|
||||
@ -33,8 +32,6 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
declare let global: any;
|
||||
|
||||
// NOTE: The order here matters: Checking window, then global, then self is important.
|
||||
|
@ -663,8 +663,7 @@ export function getCurrentDebugContext(): DebugContext|null {
|
||||
return _currentView ? new DebugContext_(_currentView, _currentNodeIndex) : null;
|
||||
}
|
||||
|
||||
|
||||
class DebugRendererFactory2 implements RendererFactory2 {
|
||||
export class DebugRendererFactory2 implements RendererFactory2 {
|
||||
constructor(private delegate: RendererFactory2) {}
|
||||
|
||||
createRenderer(element: any, renderData: RendererType2|null): Renderer2 {
|
||||
@ -690,9 +689,21 @@ class DebugRendererFactory2 implements RendererFactory2 {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DebugRenderer2 implements Renderer2 {
|
||||
export class DebugRenderer2 implements Renderer2 {
|
||||
readonly data: {[key: string]: any};
|
||||
|
||||
/**
|
||||
* Factory function used to create a `DebugContext` when a node is created.
|
||||
*
|
||||
* The `DebugContext` allows to retrieve information about the nodes that are useful in tests.
|
||||
*
|
||||
* The factory is configurable so that the `DebugRenderer2` could instantiate either a View Engine
|
||||
* or a Render context.
|
||||
*/
|
||||
debugContextFactory: () => DebugContext | null = getCurrentDebugContext;
|
||||
|
||||
private get debugContext() { return this.debugContextFactory(); }
|
||||
|
||||
constructor(private delegate: Renderer2) { this.data = this.delegate.data; }
|
||||
|
||||
destroyNode(node: any) {
|
||||
@ -706,7 +717,7 @@ class DebugRenderer2 implements Renderer2 {
|
||||
|
||||
createElement(name: string, namespace?: string): any {
|
||||
const el = this.delegate.createElement(name, namespace);
|
||||
const debugCtx = getCurrentDebugContext();
|
||||
const debugCtx = this.debugContext;
|
||||
if (debugCtx) {
|
||||
const debugEl = new DebugElement(el, null, debugCtx);
|
||||
debugEl.name = name;
|
||||
@ -717,7 +728,7 @@ class DebugRenderer2 implements Renderer2 {
|
||||
|
||||
createComment(value: string): any {
|
||||
const comment = this.delegate.createComment(value);
|
||||
const debugCtx = getCurrentDebugContext();
|
||||
const debugCtx = this.debugContext;
|
||||
if (debugCtx) {
|
||||
indexDebugNode(new DebugNode(comment, null, debugCtx));
|
||||
}
|
||||
@ -726,7 +737,7 @@ class DebugRenderer2 implements Renderer2 {
|
||||
|
||||
createText(value: string): any {
|
||||
const text = this.delegate.createText(value);
|
||||
const debugCtx = getCurrentDebugContext();
|
||||
const debugCtx = this.debugContext;
|
||||
if (debugCtx) {
|
||||
indexDebugNode(new DebugNode(text, null, debugCtx));
|
||||
}
|
||||
@ -764,7 +775,7 @@ class DebugRenderer2 implements Renderer2 {
|
||||
|
||||
selectRootElement(selectorOrNode: string|any): any {
|
||||
const el = this.delegate.selectRootElement(selectorOrNode);
|
||||
const debugCtx = getCurrentDebugContext();
|
||||
const debugCtx = this.debugContext;
|
||||
if (debugCtx) {
|
||||
indexDebugNode(new DebugElement(el, null, debugCtx));
|
||||
}
|
||||
|
Reference in New Issue
Block a user