fix(ivy): TestBed.get(Compiler) throws "Error: Runtime compiler is not loaded" (#27223)

BREAKING CHANGE:

The public API for `DebugNode` was accidentally too broad. This change removes
1. Public constructor. Since `DebugNode` is a way for Angular to communicate information
   on to the developer there is no reason why the developer should ever need to
   Instantiate the `DebugNode`
2. We are also removing `removeChild`, `addChild`, `insertBefore`, and `insertChildAfter`.
   All of these methods are used by Angular to constructor the correct `DebugNode` tree.
   There is no reason why the developer should ever be constructing a `DebugNode` tree
   And these methods should have never been made public.
3. All properties have been change to `readonly` since `DebugNode` is used by Angular
   to communicate to developer and there is no reason why these APIs should be writable.

While technically breaking change we don’t expect anyone to be effected by this change.

PR Close #27223
This commit is contained in:
Misko Hevery 2018-11-21 21:14:06 -08:00 committed by Jason Aden
parent 60e403bf6d
commit 39e426cde3
34 changed files with 1648 additions and 1468 deletions

View File

@ -144,22 +144,21 @@ describe('insert/remove', () => {
expect(fixture.nativeElement).toHaveText('projected foo');
}));
fixmeIvy('FW-561: Runtime compiler is not loaded') &&
it('should resolve components from other modules, if supplied', async(() => {
const compiler = TestBed.get(Compiler) as Compiler;
let fixture = TestBed.createComponent(TestComponent);
it('should resolve components from other modules, if supplied', async(() => {
const compiler = TestBed.get(Compiler) as Compiler;
let fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('');
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('');
fixture.componentInstance.module = compiler.compileModuleSync(TestModule2);
fixture.componentInstance.currentComponent = Module2InjectedComponent;
fixture.componentInstance.module = compiler.compileModuleSync(TestModule2);
fixture.componentInstance.currentComponent = Module2InjectedComponent;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('baz');
}));
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('baz');
}));
fixmeIvy('FW-561: Runtime compiler is not loaded') &&
fixmeIvy('FW-739: destroy on NgModuleRef is not being called') &&
it('should clean up moduleRef, if supplied', async(() => {
let destroyed = false;
const compiler = TestBed.get(Compiler) as Compiler;
@ -176,40 +175,38 @@ describe('insert/remove', () => {
expect(moduleRef.destroy).toHaveBeenCalled();
}));
fixmeIvy('FW-561: Runtime compiler is not loaded') &&
it('should not re-create moduleRef when it didn\'t actually change', async(() => {
const compiler = TestBed.get(Compiler) as Compiler;
const fixture = TestBed.createComponent(TestComponent);
it('should not re-create moduleRef when it didn\'t actually change', async(() => {
const compiler = TestBed.get(Compiler) as Compiler;
const fixture = TestBed.createComponent(TestComponent);
fixture.componentInstance.module = compiler.compileModuleSync(TestModule2);
fixture.componentInstance.currentComponent = Module2InjectedComponent;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('baz');
const moduleRef = fixture.componentInstance.ngComponentOutlet['_moduleRef'];
fixture.componentInstance.module = compiler.compileModuleSync(TestModule2);
fixture.componentInstance.currentComponent = Module2InjectedComponent;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('baz');
const moduleRef = fixture.componentInstance.ngComponentOutlet['_moduleRef'];
fixture.componentInstance.currentComponent = Module2InjectedComponent2;
fixture.detectChanges();
fixture.componentInstance.currentComponent = Module2InjectedComponent2;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('baz2');
expect(moduleRef).toBe(fixture.componentInstance.ngComponentOutlet['_moduleRef']);
}));
expect(fixture.nativeElement).toHaveText('baz2');
expect(moduleRef).toBe(fixture.componentInstance.ngComponentOutlet['_moduleRef']);
}));
fixmeIvy('FW-561: Runtime compiler is not loaded') &&
it('should re-create moduleRef when changed', async(() => {
const compiler = TestBed.get(Compiler) as Compiler;
const fixture = TestBed.createComponent(TestComponent);
fixture.componentInstance.module = compiler.compileModuleSync(TestModule2);
fixture.componentInstance.currentComponent = Module2InjectedComponent;
fixture.detectChanges();
it('should re-create moduleRef when changed', async(() => {
const compiler = TestBed.get(Compiler) as Compiler;
const fixture = TestBed.createComponent(TestComponent);
fixture.componentInstance.module = compiler.compileModuleSync(TestModule2);
fixture.componentInstance.currentComponent = Module2InjectedComponent;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('baz');
expect(fixture.nativeElement).toHaveText('baz');
fixture.componentInstance.module = compiler.compileModuleSync(TestModule3);
fixture.componentInstance.currentComponent = Module3InjectedComponent;
fixture.detectChanges();
fixture.componentInstance.module = compiler.compileModuleSync(TestModule3);
fixture.componentInstance.currentComponent = Module3InjectedComponent;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('bat');
}));
expect(fixture.nativeElement).toHaveText('bat');
}));
});
const TEST_TOKEN = new InjectionToken('TestToken');

View File

@ -114,12 +114,9 @@ export {
i18nEnd as ɵi18nEnd,
i18nApply as ɵi18nApply,
i18nPostprocess as ɵi18nPostprocess,
WRAP_RENDERER_FACTORY2 as ɵWRAP_RENDERER_FACTORY2,
setClassMetadata as ɵsetClassMetadata,
} from './render3/index';
export { Render3DebugRendererFactory2 as ɵRender3DebugRendererFactory2 } from './render3/debug';
export {
compileComponent as ɵcompileComponent,

View File

@ -7,6 +7,11 @@
*/
import {Injector} from '../di';
import {DirectiveDef} from '../render3';
import {assertDomNode} from '../render3/assert';
import {getComponent, getInjector, getLocalRefs, loadContext} from '../render3/discovery_utils';
import {TNode, TNodeFlags} from '../render3/interfaces/node';
import {TVIEW} from '../render3/interfaces/view';
import {DebugContext} from '../view/index';
export class EventListener {
@ -16,12 +21,26 @@ export class EventListener {
/**
* @publicApi
*/
export class DebugNode {
listeners: EventListener[] = [];
parent: DebugElement|null = null;
export interface DebugNode {
readonly listeners: EventListener[];
readonly parent: DebugElement|null;
readonly nativeNode: any;
readonly injector: Injector;
readonly componentInstance: any;
readonly context: any;
readonly references: {[key: string]: any};
readonly providerTokens: any[];
}
export class DebugNode__PRE_R3__ {
readonly listeners: EventListener[] = [];
readonly parent: DebugElement|null = null;
readonly nativeNode: any;
private readonly _debugContext: DebugContext;
constructor(public nativeNode: any, parent: DebugNode|null, private _debugContext: DebugContext) {
if (parent && parent instanceof DebugElement) {
constructor(nativeNode: any, parent: DebugNode|null, _debugContext: DebugContext) {
this._debugContext = _debugContext;
this.nativeNode = nativeNode;
if (parent && parent instanceof DebugElement__PRE_R3__) {
parent.addChild(this);
}
}
@ -40,14 +59,29 @@ export class DebugNode {
/**
* @publicApi
*/
export class DebugElement extends DebugNode {
name !: string;
properties: {[key: string]: any} = {};
attributes: {[key: string]: string | null} = {};
classes: {[key: string]: boolean} = {};
styles: {[key: string]: string | null} = {};
childNodes: DebugNode[] = [];
nativeElement: any;
export interface DebugElement extends DebugNode {
readonly name: string;
readonly properties: {[key: string]: any};
readonly attributes: {[key: string]: string | null};
readonly classes: {[key: string]: boolean};
readonly styles: {[key: string]: string | null};
readonly childNodes: DebugNode[];
readonly nativeElement: any;
readonly children: DebugElement[];
query(predicate: Predicate<DebugElement>): DebugElement;
queryAll(predicate: Predicate<DebugElement>): DebugElement[];
queryAllNodes(predicate: Predicate<DebugNode>): DebugNode[];
triggerEventHandler(eventName: string, eventObj: any): void;
}
export class DebugElement__PRE_R3__ extends DebugNode__PRE_R3__ implements DebugElement {
readonly name !: string;
readonly properties: {[key: string]: any} = {};
readonly attributes: {[key: string]: string | null} = {};
readonly classes: {[key: string]: boolean} = {};
readonly styles: {[key: string]: string | null} = {};
readonly childNodes: DebugNode[] = [];
readonly nativeElement: any;
constructor(nativeNode: any, parent: any, _debugContext: DebugContext) {
super(nativeNode, parent, _debugContext);
@ -57,14 +91,14 @@ export class DebugElement extends DebugNode {
addChild(child: DebugNode) {
if (child) {
this.childNodes.push(child);
child.parent = this;
(child as{parent: DebugNode}).parent = this;
}
}
removeChild(child: DebugNode) {
const childIndex = this.childNodes.indexOf(child);
if (childIndex !== -1) {
child.parent = null;
(child as{parent: DebugNode | null}).parent = null;
this.childNodes.splice(childIndex, 1);
}
}
@ -75,9 +109,9 @@ export class DebugElement extends DebugNode {
this.childNodes.splice(siblingIndex + 1, 0, ...newChildren);
newChildren.forEach(c => {
if (c.parent) {
c.parent.removeChild(c);
(c.parent as DebugElement__PRE_R3__).removeChild(c);
}
c.parent = this;
(child as{parent: DebugNode}).parent = this;
});
}
}
@ -88,9 +122,9 @@ export class DebugElement extends DebugNode {
this.addChild(newChild);
} else {
if (newChild.parent) {
newChild.parent.removeChild(newChild);
(newChild.parent as DebugElement__PRE_R3__).removeChild(newChild);
}
newChild.parent = this;
(newChild as{parent: DebugNode}).parent = this;
this.childNodes.splice(refIndex, 0, newChild);
}
}
@ -113,7 +147,9 @@ export class DebugElement extends DebugNode {
}
get children(): DebugElement[] {
return this.childNodes.filter((node) => node instanceof DebugElement) as DebugElement[];
return this
.childNodes //
.filter((node) => node instanceof DebugElement__PRE_R3__) as DebugElement[];
}
triggerEventHandler(eventName: string, eventObj: any) {
@ -135,7 +171,7 @@ export function asNativeElements(debugEls: DebugElement[]): any {
function _queryElementChildren(
element: DebugElement, predicate: Predicate<DebugElement>, matches: DebugElement[]) {
element.childNodes.forEach(node => {
if (node instanceof DebugElement) {
if (node instanceof DebugElement__PRE_R3__) {
if (predicate(node)) {
matches.push(node);
}
@ -146,27 +182,215 @@ function _queryElementChildren(
function _queryNodeChildren(
parentNode: DebugNode, predicate: Predicate<DebugNode>, matches: DebugNode[]) {
if (parentNode instanceof DebugElement) {
if (parentNode instanceof DebugElement__PRE_R3__) {
parentNode.childNodes.forEach(node => {
if (predicate(node)) {
matches.push(node);
}
if (node instanceof DebugElement) {
if (node instanceof DebugElement__PRE_R3__) {
_queryNodeChildren(node, predicate, matches);
}
});
}
}
function notImplemented(): Error {
throw new Error('Missing proper ivy implementation.');
}
class DebugNode__POST_R3__ implements DebugNode {
readonly nativeNode: Node;
constructor(nativeNode: Node) { this.nativeNode = nativeNode; }
get parent(): DebugElement|null {
const parent = this.nativeNode.parentNode as HTMLElement;
return parent ? new DebugElement__POST_R3__(parent) : null;
}
get injector(): Injector { return getInjector(this.nativeNode); }
get componentInstance(): any {
const nativeElement = this.nativeNode;
return nativeElement && getComponent(nativeElement as HTMLElement);
}
get context(): any {
// https://angular-team.atlassian.net/browse/FW-719
throw notImplemented();
}
get listeners(): EventListener[] {
// TODO: add real implementation;
// https://angular-team.atlassian.net/browse/FW-719
return [];
}
get references(): {[key: string]: any;} { return getLocalRefs(this.nativeNode); }
get providerTokens(): any[] {
// TODO move to discoverable utils
const context = loadContext(this.nativeNode as HTMLElement, false) !;
if (!context) return [];
const lView = context.lViewData;
const tView = lView[TVIEW];
const tNode = tView.data[context.nodeIndex] as TNode;
const providerTokens: any[] = [];
const nodeFlags = tNode.flags;
const startIndex = nodeFlags >> TNodeFlags.DirectiveStartingIndexShift;
const directiveCount = nodeFlags & TNodeFlags.DirectiveCountMask;
const endIndex = startIndex + directiveCount;
for (let i = startIndex; i < endIndex; i++) {
let value = tView.data[i];
if (isDirectiveDefHack(value)) {
// The fact that we sometimes store Type and sometimes DirectiveDef in this location is a
// design flaw. We should always store same type so that we can be monomorphic. The issue
// is that for Components/Directives we store the def instead the type. The correct behavior
// is that we should always be storing injectable type in this location.
value = value.type;
}
providerTokens.push(value);
}
return providerTokens;
}
}
class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugElement {
constructor(nativeNode: Element) {
ngDevMode && assertDomNode(nativeNode);
super(nativeNode);
}
get nativeElement(): Element|null {
return this.nativeNode.nodeType == Node.ELEMENT_NODE ? this.nativeNode as Element : null;
}
get name(): string { return (this.nativeElement as HTMLElement).nodeName; }
get properties(): {[key: string]: any;} {
const context = loadContext(this.nativeNode) !;
const lView = context.lViewData;
const tView = lView[TVIEW];
const tNode = tView.data[context.nodeIndex] as TNode;
const properties = {};
// TODO: https://angular-team.atlassian.net/browse/FW-681
// Missing implementation here...
return properties;
}
get attributes(): {[key: string]: string | null;} {
// https://angular-team.atlassian.net/browse/FW-719
throw notImplemented();
}
get classes(): {[key: string]: boolean;} {
// https://angular-team.atlassian.net/browse/FW-719
throw notImplemented();
}
get styles(): {[key: string]: string | null;} {
// https://angular-team.atlassian.net/browse/FW-719
throw notImplemented();
}
get childNodes(): DebugNode[] {
const childNodes = this.nativeNode.childNodes;
const children: DebugNode[] = [];
for (let i = 0; i < childNodes.length; i++) {
const element = childNodes[i];
children.push(getDebugNode__POST_R3__(element));
}
return children;
}
get children(): DebugElement[] {
const nativeElement = this.nativeElement;
if (!nativeElement) return [];
const childNodes = nativeElement.children;
const children: DebugElement[] = [];
for (let i = 0; i < childNodes.length; i++) {
const element = childNodes[i];
children.push(getDebugNode__POST_R3__(element));
}
return children;
}
query(predicate: Predicate<DebugElement>): DebugElement {
const results = this.queryAll(predicate);
return results[0] || null;
}
queryAll(predicate: Predicate<DebugElement>): DebugElement[] {
const matches: DebugElement[] = [];
_queryNodeChildrenR3(this, predicate, matches, true);
return matches;
}
queryAllNodes(predicate: Predicate<DebugNode>): DebugNode[] {
const matches: DebugNode[] = [];
_queryNodeChildrenR3(this, predicate, matches, false);
return matches;
}
triggerEventHandler(eventName: string, eventObj: any): void {
// This is a hack implementation. The correct implementation would bypass the DOM and `TNode`
// information to invoke the listeners directly.
// https://angular-team.atlassian.net/browse/FW-719
const event = document.createEvent('MouseEvent');
event.initEvent(eventName, true, true);
(this.nativeElement as HTMLElement).dispatchEvent(event);
}
}
/**
* This function should not exist because it is megamorphic and only mostly correct.
*
* See call site for more info.
*/
function isDirectiveDefHack(obj: any): obj is DirectiveDef<any> {
return obj.type !== undefined && obj.template !== undefined && obj.declaredInputs !== undefined;
}
function _queryNodeChildrenR3(
parentNode: DebugNode, predicate: Predicate<DebugNode>, matches: DebugNode[],
elementsOnly: boolean) {
if (parentNode instanceof DebugElement__POST_R3__) {
parentNode.childNodes.forEach(node => {
if (predicate(node)) {
matches.push(node);
}
if (node instanceof DebugElement__POST_R3__) {
if (elementsOnly ? node.nativeElement : true) {
_queryNodeChildrenR3(node, predicate, matches, elementsOnly);
}
}
});
}
}
// Need to keep the nodes in a global Map so that multiple angular apps are supported.
const _nativeNodeToDebugNode = new Map<any, DebugNode>();
function getDebugNode__PRE_R3__(nativeNode: any): DebugNode|null {
return _nativeNodeToDebugNode.get(nativeNode) || null;
}
export function getDebugNode__POST_R3__(nativeNode: Element): DebugElement__POST_R3__;
export function getDebugNode__POST_R3__(nativeNode: Node): DebugNode__POST_R3__;
export function getDebugNode__POST_R3__(nativeNode: null): null;
export function getDebugNode__POST_R3__(nativeNode: any): DebugNode|null {
if (nativeNode instanceof Node) {
return nativeNode.nodeType == Node.ELEMENT_NODE ?
new DebugElement__POST_R3__(nativeNode as Element) :
new DebugNode__POST_R3__(nativeNode);
}
return null;
}
/**
* @publicApi
*/
export function getDebugNode(nativeNode: any): DebugNode|null {
return _nativeNodeToDebugNode.get(nativeNode) || null;
}
export const getDebugNode: (nativeNode: any) => DebugNode | null = getDebugNode__PRE_R3__;
export function getAllDebugNodes(): DebugNode[] {
return Array.from(_nativeNodeToDebugNode.values());
@ -187,3 +411,13 @@ export function removeDebugNodeFromIndex(node: DebugNode) {
* @publicApi
*/
export interface Predicate<T> { (value: T): boolean; }
/**
* @publicApi
*/
export const DebugNode: {new (...args: any[]): DebugNode} = DebugNode__PRE_R3__ as any;
/**
* @publicApi
*/
export const DebugElement: {new (...args: any[]): DebugElement} = DebugElement__PRE_R3__ as any;

View File

@ -11,6 +11,7 @@ import {InjectionToken} from '../di/injection_token';
import {StaticProvider} from '../di/provider';
import {MissingTranslationStrategy} from '../i18n/tokens';
import {ViewEncapsulation} from '../metadata';
import {NgModuleFactory as NgModuleFactoryR3} from '../render3/ng_module_ref';
import {Type} from '../type';
import {ComponentFactory} from './component_factory';
@ -34,6 +35,42 @@ function _throwError() {
throw new Error(`Runtime compiler is not loaded`);
}
const Compiler_compileModuleSync__PRE_R3__: <T>(moduleType: Type<T>) => NgModuleFactory<T> =
_throwError as any;
export const Compiler_compileModuleSync__POST_R3__: <T>(moduleType: Type<T>) =>
NgModuleFactory<T> = function<T>(moduleType: Type<T>): NgModuleFactory<T> {
return new NgModuleFactoryR3(moduleType);
};
const Compiler_compileModuleSync = Compiler_compileModuleSync__PRE_R3__;
const Compiler_compileModuleAsync__PRE_R3__: <T>(moduleType: Type<T>) =>
Promise<NgModuleFactory<T>> = _throwError as any;
export const Compiler_compileModuleAsync__POST_R3__: <T>(moduleType: Type<T>) =>
Promise<NgModuleFactory<T>> = function<T>(moduleType: Type<T>): Promise<NgModuleFactory<T>> {
return Promise.resolve(Compiler_compileModuleSync__POST_R3__(moduleType));
};
const Compiler_compileModuleAsync = Compiler_compileModuleAsync__PRE_R3__;
const Compiler_compileModuleAndAllComponentsSync__PRE_R3__: <T>(moduleType: Type<T>) =>
ModuleWithComponentFactories<T> = _throwError as any;
export const Compiler_compileModuleAndAllComponentsSync__POST_R3__: <T>(moduleType: Type<T>) =>
ModuleWithComponentFactories<T> = function<T>(moduleType: Type<T>):
ModuleWithComponentFactories<T> {
return new ModuleWithComponentFactories(Compiler_compileModuleSync__POST_R3__(moduleType), []);
};
const Compiler_compileModuleAndAllComponentsSync =
Compiler_compileModuleAndAllComponentsSync__PRE_R3__;
const Compiler_compileModuleAndAllComponentsAsync__PRE_R3__: <T>(moduleType: Type<T>) =>
Promise<ModuleWithComponentFactories<T>> = _throwError as any;
export const Compiler_compileModuleAndAllComponentsAsync__POST_R3__: <T>(moduleType: Type<T>) =>
Promise<ModuleWithComponentFactories<T>> = function<T>(moduleType: Type<T>):
Promise<ModuleWithComponentFactories<T>> {
return Promise.resolve(Compiler_compileModuleAndAllComponentsSync__POST_R3__(moduleType));
};
const Compiler_compileModuleAndAllComponentsAsync =
Compiler_compileModuleAndAllComponentsAsync__PRE_R3__;
/**
* Low-level service for running the angular compiler during runtime
* to create {@link ComponentFactory}s, which
@ -51,27 +88,25 @@ export class Compiler {
* Compiles the given NgModule and all of its components. All templates of the components listed
* in `entryComponents` have to be inlined.
*/
compileModuleSync<T>(moduleType: Type<T>): NgModuleFactory<T> { throw _throwError(); }
compileModuleSync: <T>(moduleType: Type<T>) => NgModuleFactory<T> = Compiler_compileModuleSync;
/**
* Compiles the given NgModule and all of its components
*/
compileModuleAsync<T>(moduleType: Type<T>): Promise<NgModuleFactory<T>> { throw _throwError(); }
compileModuleAsync:
<T>(moduleType: Type<T>) => Promise<NgModuleFactory<T>> = Compiler_compileModuleAsync;
/**
* Same as {@link #compileModuleSync} but also creates ComponentFactories for all components.
*/
compileModuleAndAllComponentsSync<T>(moduleType: Type<T>): ModuleWithComponentFactories<T> {
throw _throwError();
}
compileModuleAndAllComponentsSync: <T>(moduleType: Type<T>) => ModuleWithComponentFactories<T> =
Compiler_compileModuleAndAllComponentsSync;
/**
* Same as {@link #compileModuleAsync} but also creates ComponentFactories for all components.
*/
compileModuleAndAllComponentsAsync<T>(moduleType: Type<T>):
Promise<ModuleWithComponentFactories<T>> {
throw _throwError();
}
compileModuleAndAllComponentsAsync: <T>(moduleType: Type<T>) =>
Promise<ModuleWithComponentFactories<T>> = Compiler_compileModuleAndAllComponentsAsync;
/**
* Clears all caches.

View File

@ -90,7 +90,7 @@ export interface AttributeDecorator {
* ]
* ```
*
*
* @publicApi
*/
(name: string): any;
new (name: string): Attribute;

View File

@ -83,3 +83,7 @@ function throwError(msg: string): never {
debugger; // Left intentionally for better debugger experience.
throw new Error(`ASSERTION ERROR: ${msg}`);
}
export function assertDomNode(node: any) {
assertEqual(node instanceof Node, true, 'The provided value must be an instance of a DOM Node');
}

View File

@ -13,10 +13,8 @@ import {Injector} from '../di/injector';
import {Sanitizer} from '../sanitization/security';
import {assertComponentType, assertDefined} from './assert';
import {getContext} from './context_discovery';
import {getComponentDef} from './definition';
import {diPublicInInjector, getOrCreateNodeInjectorForNode} from './di';
import {getHostElement} from './discovery_utils';
import {publishDefaultGlobalUtils} from './global_utils';
import {queueInitHooks, queueLifecycleHooks} from './hooks';
import {CLEAN_PROMISE, createLViewData, createNodeAtIndex, createTView, getOrCreateTView, initNodeFlags, instantiateRootComponent, locateHostElement, prefillHostVars, queueComponentIndexForCheck, refreshDescendantViews} from './instructions';
@ -26,7 +24,7 @@ import {PlayerHandler} from './interfaces/player';
import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
import {CONTEXT, HEADER_OFFSET, HOST, HOST_NODE, INJECTOR, LViewData, LViewFlags, RootContext, RootContextFlags, TVIEW} from './interfaces/view';
import {enterView, leaveView, resetComponentState} from './state';
import {defaultScheduler, getRootView, readElementValue, readPatchedLViewData, stringify} from './util';
import {defaultScheduler, getRootView, readPatchedLViewData, stringify} from './util';
@ -123,15 +121,15 @@ export function renderComponent<T>(
const renderer = rendererFactory.createRenderer(hostRNode, componentDef);
const rootView: LViewData = createLViewData(
null, renderer, createTView(-1, null, 1, 0, null, null, null), rootContext, rootFlags,
undefined, opts.injector || null);
null, createTView(-1, null, 1, 0, null, null, null), rootContext, rootFlags, rendererFactory,
renderer, undefined, opts.injector || null);
const oldView = enterView(rootView, null);
let component: T;
try {
if (rendererFactory.begin) rendererFactory.begin();
const componentView =
createRootComponentView(hostRNode, componentDef, rootView, renderer, sanitizer);
const componentView = createRootComponentView(
hostRNode, componentDef, rootView, rendererFactory, renderer, sanitizer);
component = createRootComponent(
componentView, componentDef, rootView, rootContext, opts.hostFeatures || null);
@ -156,15 +154,17 @@ export function renderComponent<T>(
* @returns Component view created
*/
export function createRootComponentView(
rNode: RElement | null, def: ComponentDef<any>, rootView: LViewData, renderer: Renderer3,
rNode: RElement | null, def: ComponentDef<any>, rootView: LViewData,
rendererFactory: RendererFactory3, renderer: Renderer3,
sanitizer?: Sanitizer | null): LViewData {
resetComponentState();
const tView = rootView[TVIEW];
const componentView = createLViewData(
rootView, renderer,
rootView,
getOrCreateTView(
def.template, def.consts, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery),
null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, sanitizer);
null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, rendererFactory, renderer,
sanitizer);
const tNode = createNodeAtIndex(0, TNodeType.Element, rNode, null, null);
if (tView.firstTemplatePass) {

View File

@ -15,6 +15,7 @@ import {ComponentFactoryResolver as viewEngine_ComponentFactoryResolver} from '.
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 {Sanitizer} from '../sanitization/security';
import {Type} from '../type';
import {VERSION} from '../version';
import {assertComponentType, assertDefined} from './assert';
@ -25,6 +26,7 @@ import {createLViewData, createNodeAtIndex, createTView, createViewNode, element
import {ComponentDef, RenderFlags} from './interfaces/definition';
import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType} from './interfaces/node';
import {RElement, RendererFactory3, domRendererFactory3, isProceduralRenderer} from './interfaces/renderer';
import {SanitizerFn} from './interfaces/sanitization';
import {HEADER_OFFSET, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
import {enterView, leaveView} from './state';
import {defaultScheduler, getTNode} from './util';
@ -66,13 +68,6 @@ export const SCHEDULER = new InjectionToken<((fn: () => void) => void)>('SCHEDUL
factory: () => defaultScheduler,
});
/**
* 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');
const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
function createChainedInjector(rootViewInjector: Injector, moduleInjector: Injector): Injector {
@ -121,10 +116,11 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
const isInternalRootView = rootSelectorOrNode === undefined;
let rendererFactory: RendererFactory3;
let sanitizer: Sanitizer|null = null;
if (ngModule) {
const wrapper = ngModule.injector.get(WRAP_RENDERER_FACTORY2, (v: RendererFactory2) => v);
rendererFactory = wrapper(ngModule.injector.get(RendererFactory2)) as RendererFactory3;
rendererFactory = ngModule.injector.get(RendererFactory2) as RendererFactory3;
sanitizer = ngModule.injector.get(Sanitizer, null);
} else {
rendererFactory = domRendererFactory3;
}
@ -151,8 +147,8 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
// Create the root view. Uses empty TView and ContentTemplate.
const rootView: LViewData = createLViewData(
null, renderer, createTView(-1, null, 1, 0, null, null, null), rootContext, rootFlags,
undefined, rootViewInjector);
null, createTView(-1, null, 1, 0, null, null, null), rootContext, rootFlags,
rendererFactory, renderer, sanitizer, rootViewInjector);
// rootView is the parent when bootstrapping
const oldView = enterView(rootView, null);
@ -162,8 +158,8 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
try {
if (rendererFactory.begin) rendererFactory.begin();
const componentView =
createRootComponentView(hostRNode, this.componentDef, rootView, renderer);
const componentView = createRootComponentView(
hostRNode, this.componentDef, rootView, rendererFactory, renderer);
tElementNode = getTNode(0, rootView) as TElementNode;
// Transform the arrays of native nodes into a structure that can be consumed by the

View File

@ -7,7 +7,7 @@
*/
import './ng_dev_mode';
import {assertEqual} from './assert';
import {assertDomNode} from './assert';
import {EMPTY_ARRAY} from './definition';
import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context';
import {TNode, TNodeFlags} from './interfaces/node';
@ -95,7 +95,7 @@ export function getContext(target: any): LContext|null {
}
} else {
const rElement = target as RElement;
ngDevMode && assertDomElement(rElement);
ngDevMode && assertDomNode(rElement);
// if the context is not found then we need to traverse upwards up the DOM
// to find the nearest element that has already been monkey patched with data
@ -262,12 +262,6 @@ function findViaDirective(lViewData: LViewData, directiveInstance: {}): number {
return -1;
}
function assertDomElement(element: any) {
assertEqual(
element && (element.nodeType == Node.ELEMENT_NODE || element.nodeType == Node.TEXT_NODE),
true, 'The provided value must be an instance of an HTMLElement');
}
/**
* Returns a list of directives extracted from the given view based on the
* provided list of directive index values.

View File

@ -1,81 +0,0 @@
/**
* @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 {getComponent, getInjector, getLocalRefs, loadContext} from './discovery_utils';
import {DirectiveDef} from './interfaces/definition';
import {TNode, TNodeFlags} from './interfaces/node';
import {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 = (nativeElement: any) => new Render3DebugContext(nativeElement);
return renderer;
}
}
/**
* Stores context information about view nodes.
*
* Used in tests to retrieve information those nodes.
*/
class Render3DebugContext implements DebugContext {
constructor(private _nativeNode: any) {}
get nodeIndex(): number|null { return loadContext(this._nativeNode).nodeIndex; }
get view(): any { return loadContext(this._nativeNode).lViewData; }
get injector(): Injector { return getInjector(this._nativeNode); }
get component(): any { return getComponent(this._nativeNode); }
get providerTokens(): any[] {
const lDebugCtx = loadContext(this._nativeNode);
const lViewData = lDebugCtx.lViewData;
const tNode = lViewData[TVIEW].data[lDebugCtx.nodeIndex] as TNode;
const directivesCount = tNode.flags & TNodeFlags.DirectiveCountMask;
if (directivesCount > 0) {
const directiveIdxStart = tNode.flags >> TNodeFlags.DirectiveStartingIndexShift;
const directiveIdxEnd = directiveIdxStart + directivesCount;
const viewDirectiveDefs = this.view[TVIEW].data;
const directiveDefs =
viewDirectiveDefs.slice(directiveIdxStart, directiveIdxEnd) as DirectiveDef<any>[];
return directiveDefs.map(directiveDef => directiveDef.type);
}
return [];
}
get references(): {[key: string]: any} { return getLocalRefs(this._nativeNode); }
// TODO(pk): check previous implementation and re-implement
get context(): any { throw new Error('Not implemented in ivy'); }
// TODO(pk): check previous implementation and re-implement
get componentRenderElement(): any { throw new Error('Not implemented in ivy'); }
// TODO(pk): check previous implementation and re-implement
get renderNode(): any { throw new Error('Not implemented in ivy'); }
// TODO(pk): check previous implementation and re-implement
logError(console: Console, ...values: any[]): void { console.error(...values); }
}

View File

@ -20,7 +20,7 @@ import {NO_PARENT_INJECTOR, NodeInjectorFactory, PARENT_INJECTOR, RelativeInject
import {AttributeMarker, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType} from './interfaces/node';
import {DECLARATION_VIEW, HOST_NODE, INJECTOR, LViewData, TData, TVIEW, TView} from './interfaces/view';
import {assertNodeOfPossibleTypes} from './node_assert';
import {getPreviousOrParentTNode, getViewData, setTNodeAndViewData} from './state';
import {_getViewData, getPreviousOrParentTNode, getViewData, setTNodeAndViewData} from './state';
import {getParentInjectorIndex, getParentInjectorView, hasParentInjector, isComponent, stringify} from './util';
/**
@ -556,13 +556,19 @@ export class NodeInjector implements Injector {
constructor(
private _tNode: TElementNode|TContainerNode|TElementContainerNode,
private _hostView: LViewData) {
this._injectorIndex = getOrCreateNodeInjectorForNode(_tNode, _hostView);
private _lView: LViewData) {
this._injectorIndex = getOrCreateNodeInjectorForNode(_tNode, _lView);
}
get(token: any): any {
setTNodeAndViewData(this._tNode, this._hostView);
return getOrCreateInjectable(this._tNode, this._hostView, token);
const previousTNode = getPreviousOrParentTNode();
const previousLView = _getViewData();
setTNodeAndViewData(this._tNode, this._lView);
try {
return getOrCreateInjectable(this._tNode, this._lView, token);
} finally {
setTNodeAndViewData(previousTNode, previousLView);
}
}
}

View File

@ -141,9 +141,11 @@ export function getDirectives(target: {}): Array<{}> {
* Throws if a given target doesn't have associated LContext.
*
*/
export function loadContext(target: {}): LContext {
export function loadContext(target: {}): LContext;
export function loadContext(target: {}, throwOnNotFound: false): LContext|null;
export function loadContext(target: {}, throwOnNotFound: boolean = true): LContext|null {
const context = getContext(target);
if (!context) {
if (!context && throwOnNotFound) {
throw new Error(
ngDevMode ? `Unable to find context associated with ${stringify(target)}` :
'Invalid ng target');

View File

@ -13,7 +13,7 @@ import {NgOnChangesFeature} from './features/ng_onchanges_feature';
import {ProvidersFeature} from './features/providers_feature';
import {BaseDef, ComponentDef, ComponentDefWithMeta, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveDefWithMeta, DirectiveType, PipeDef, PipeDefWithMeta} from './interfaces/definition';
export {ComponentFactory, ComponentFactoryResolver, ComponentRef, WRAP_RENDERER_FACTORY2, injectComponentFactoryResolver} from './component_ref';
export {ComponentFactory, ComponentFactoryResolver, ComponentRef, injectComponentFactoryResolver} from './component_ref';
export {getFactoryOf, getInheritedFactory} from './di';
export {RenderFlags} from './interfaces/definition';
export {CssSelectorList} from './interfaces/projection';

View File

@ -32,11 +32,11 @@ import {LQueries} from './interfaces/query';
import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, RendererFactory3, isProceduralRenderer} from './interfaces/renderer';
import {SanitizerFn} from './interfaces/sanitization';
import {StylingIndex} from './interfaces/styling';
import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, HOST_NODE, INJECTOR, LViewData, LViewFlags, NEXT, OpaqueViewState, PARENT, QUERIES, RENDERER, RootContext, RootContextFlags, SANITIZER, TAIL, TVIEW, TView} from './interfaces/view';
import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, HOST_NODE, INJECTOR, LViewData, LViewFlags, NEXT, OpaqueViewState, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, RootContext, RootContextFlags, SANITIZER, TAIL, TVIEW, TView} from './interfaces/view';
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
import {appendChild, appendProjectedNode, createTextNode, findComponentView, getLViewChild, getRenderParent, insertView, removeView} from './node_manipulation';
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
import {assertDataInRange, assertHasParent, assertPreviousIsParent, decreaseElementDepthCount, enterView, getBindingsEnabled, getCheckNoChangesMode, getCleanup, getContextViewData, getCreationMode, getCurrentQueries, getCurrentSanitizer, getElementDepthCount, getFirstTemplatePass, getIsParent, getPreviousOrParentTNode, getRenderer, getRendererFactory, getTView, getTViewCleanup, getViewData, increaseElementDepthCount, leaveView, nextContextImpl, resetComponentState, setBindingRoot, setCheckNoChangesMode, setCurrentQueries, setFirstTemplatePass, setIsParent, setPreviousOrParentTNode, setRenderer, setRendererFactory} from './state';
import {assertDataInRange, assertHasParent, assertPreviousIsParent, decreaseElementDepthCount, enterView, getBindingsEnabled, getCheckNoChangesMode, getCleanup, getContextViewData, getCreationMode, getCurrentQueries, getCurrentSanitizer, getElementDepthCount, getFirstTemplatePass, getIsParent, getPreviousOrParentTNode, getRenderer, getRendererFactory, getTView, getTViewCleanup, getViewData, increaseElementDepthCount, leaveView, nextContextImpl, resetComponentState, setBindingRoot, setCheckNoChangesMode, setCurrentQueries, setFirstTemplatePass, setIsParent, setPreviousOrParentTNode} from './state';
import {createStylingContextTemplate, renderStyleAndClassBindings, updateClassProp as updateElementClassProp, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling/class_and_style_bindings';
import {BoundPlayerFactory} from './styling/player_factory';
import {getStylingContext} from './styling/util';
@ -155,17 +155,20 @@ function refreshChildComponents(components: number[] | null, rf: RenderFlags | n
}
export function createLViewData<T>(
parentViewData: LViewData | null, renderer: Renderer3, tView: TView, context: T | null,
flags: LViewFlags, sanitizer?: Sanitizer | null, injector?: Injector | null): LViewData {
const instance = tView.blueprint.slice() as LViewData;
instance[FLAGS] = flags | LViewFlags.CreationMode | LViewFlags.Attached | LViewFlags.RunInit;
instance[PARENT] = instance[DECLARATION_VIEW] = parentViewData;
instance[CONTEXT] = context;
instance[INJECTOR as any] =
injector === undefined ? (parentViewData ? parentViewData[INJECTOR] : null) : injector;
instance[RENDERER] = renderer;
instance[SANITIZER] = sanitizer || null;
return instance;
parentLView: LViewData | null, tView: TView, context: T | null, flags: LViewFlags,
rendererFactory?: RendererFactory3 | null, renderer?: Renderer3 | null,
sanitizer?: Sanitizer | null, injector?: Injector | null): LViewData {
const lView = tView.blueprint.slice() as LViewData;
lView[FLAGS] = flags | LViewFlags.CreationMode | LViewFlags.Attached | LViewFlags.RunInit;
lView[PARENT] = lView[DECLARATION_VIEW] = parentLView;
lView[CONTEXT] = context;
lView[RENDERER_FACTORY] = (rendererFactory || parentLView && parentLView[RENDERER_FACTORY]) !;
ngDevMode && assertDefined(lView[RENDERER_FACTORY], 'RendererFactory is required');
lView[RENDERER] = (renderer || parentLView && parentLView[RENDERER]) !;
ngDevMode && assertDefined(lView[RENDERER], 'Renderer is required');
lView[SANITIZER] = sanitizer || parentLView && parentLView[SANITIZER] || null !;
lView[INJECTOR as any] = injector || parentLView && parentLView[INJECTOR] || null;
return lView;
}
/**
@ -285,20 +288,19 @@ export function renderTemplate<T>(
sanitizer?: Sanitizer | null): LViewData {
if (hostView == null) {
resetComponentState();
setRendererFactory(providedRendererFactory);
const renderer = providedRendererFactory.createRenderer(null, null);
setRenderer(renderer);
// We need to create a root view so it's possible to look up the host element through its index
const lView = createLViewData(
null, renderer, createTView(-1, null, 1, 0, null, null, null), {},
LViewFlags.CheckAlways | LViewFlags.IsRoot);
enterView(lView, null);
const hostLView = createLViewData(
null, createTView(-1, null, 1, 0, null, null, null), {},
LViewFlags.CheckAlways | LViewFlags.IsRoot, providedRendererFactory, renderer);
enterView(hostLView, null); // SUSPECT! why do we need to enter the View?
const componentTView =
getOrCreateTView(templateFn, consts, vars, directives || null, pipes || null, null);
hostView = createLViewData(
lView, renderer, componentTView, context, LViewFlags.CheckAlways, sanitizer);
hostLView, componentTView, context, LViewFlags.CheckAlways, providedRendererFactory,
renderer, sanitizer);
hostView[HOST_NODE] = createNodeAtIndex(0, TNodeType.Element, hostNode, null, null);
}
renderComponentOrTemplate(hostView, context, null, templateFn);
@ -319,8 +321,7 @@ export function createEmbeddedViewAndNode<T>(
setIsParent(true);
setPreviousOrParentTNode(null !);
const lView = createLViewData(
declarationView, renderer, tView, context, LViewFlags.CheckAlways, getCurrentSanitizer());
const lView = createLViewData(declarationView, tView, context, LViewFlags.CheckAlways);
lView[DECLARATION_VIEW] = declarationView;
if (queries) {
@ -403,7 +404,7 @@ export function nextContext<T = any>(level: number = 1): T {
function renderComponentOrTemplate<T>(
hostView: LViewData, componentOrContext: T, rf: RenderFlags | null,
templateFn?: ComponentTemplate<T>) {
const rendererFactory = getRendererFactory();
const rendererFactory = hostView[RENDERER_FACTORY];
const oldView = enterView(hostView, hostView[HOST_NODE]);
try {
if (rendererFactory.begin) {
@ -765,7 +766,6 @@ export function createError(text: string, token: any) {
export function locateHostElement(
factory: RendererFactory3, elementOrSelector: RElement | string): RElement|null {
ngDevMode && assertDataInRange(-1);
setRendererFactory(factory);
const defaultRenderer = factory.createRenderer(null, null);
const rNode = typeof elementOrSelector === 'string' ?
(isProceduralRenderer(defaultRenderer) ?
@ -1671,11 +1671,12 @@ function addComponentLogic<T>(
// Only component views should be added to the view tree directly. Embedded views are
// accessed through their containers because they may be removed / re-added later.
const rendererFactory = getRendererFactory();
const componentView = addToViewTree(
viewData, previousOrParentTNode.index as number,
createLViewData(
getViewData(), getRendererFactory().createRenderer(native as RElement, def), tView, null,
def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, getCurrentSanitizer()));
getViewData(), tView, null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways,
rendererFactory, getRendererFactory().createRenderer(native as RElement, def)));
componentView[HOST_NODE] = previousOrParentTNode as TElementNode;
@ -2002,9 +2003,9 @@ export function embeddedViewStart(viewBlockId: number, consts: number, vars: num
} else {
// When we create a new LView, we always reset the state of the instructions.
viewToRender = createLViewData(
getViewData(), getRenderer(),
getViewData(),
getOrCreateEmbeddedTView(viewBlockId, consts, vars, containerTNode as TContainerNode), null,
LViewFlags.CheckAlways, getCurrentSanitizer());
LViewFlags.CheckAlways);
if (lContainer[QUERIES]) {
viewToRender[QUERIES] = lContainer[QUERIES] !.createView();

View File

@ -17,13 +17,10 @@ import {I18nUpdateOpCodes, TI18n} from './i18n';
import {TElementNode, TNode, TViewNode} from './node';
import {PlayerHandler} from './player';
import {LQueries} from './query';
import {RElement, Renderer3} from './renderer';
import {RElement, Renderer3, RendererFactory3} from './renderer';
import {StylingContext} from './styling';
/** Size of LViewData's header. Necessary to adjust for it when setting slots. */
export const HEADER_OFFSET = 17;
// Below are constants for LViewData indices to help us look up LViewData members
// without having to remember the specific indices.
// Uglify will inline these when minifying so there shouldn't be a cost.
@ -33,17 +30,21 @@ export const PARENT = 2;
export const NEXT = 3;
export const QUERIES = 4;
export const HOST = 5;
export const HOST_NODE = 6;
export const HOST_NODE = 6; // Rename to `T_HOST`?
export const BINDING_INDEX = 7;
export const CLEANUP = 8;
export const CONTEXT = 9;
export const INJECTOR = 10;
export const RENDERER = 11;
export const SANITIZER = 12;
export const TAIL = 13;
export const CONTAINER_INDEX = 14;
export const CONTENT_QUERIES = 15;
export const DECLARATION_VIEW = 16;
export const RENDERER_FACTORY = 11;
export const RENDERER = 12;
export const SANITIZER = 13;
export const TAIL = 14;
export const CONTAINER_INDEX = 15;
export const CONTENT_QUERIES = 16;
export const DECLARATION_VIEW = 17;
/** Size of LViewData's header. Necessary to adjust for it when setting slots. */
export const HEADER_OFFSET = 18;
// This interface replaces the real LViewData interface if it is an arg or a
// return value of a public instruction. This ensures we don't need to expose
@ -149,6 +150,9 @@ export interface LViewData extends Array<any> {
/** An optional Module Injector to be used as fall back after Element Injectors are consulted. */
readonly[INJECTOR]: Injector|null;
/** Renderer to be used for this view. */
[RENDERER_FACTORY]: RendererFactory3;
/** Renderer to be used for this view. */
[RENDERER]: Renderer3;

View File

@ -8,6 +8,7 @@
import {ModuleWithProviders, NgModule, NgModuleDef, NgModuleTransitiveScopes} from '../../metadata/ng_module';
import {Type} from '../../type';
import {assertDefined} from '../assert';
import {getComponentDef, getDirectiveDef, getNgModuleDef, getPipeDef} from '../definition';
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_INJECTOR_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from '../fields';
import {ComponentDef} from '../interfaces/definition';
@ -32,6 +33,8 @@ export function compileNgModule(moduleType: Type<any>, ngModule: NgModule = {}):
* Compiles and adds the `ngModuleDef` and `ngInjectorDef` properties to the module class.
*/
export function compileNgModuleDefs(moduleType: Type<any>, ngModule: NgModule): void {
ngDevMode && assertDefined(moduleType, 'Required value moduleType');
ngDevMode && assertDefined(ngModule, 'Required value ngModule');
const declarations: Type<any>[] = flatten(ngModule.declarations || EMPTY_ARRAY);
let ngModuleDef: any = null;

View File

@ -13,7 +13,7 @@ import {executeHooks} from './hooks';
import {TElementNode, TNode, TNodeFlags, TViewNode} from './interfaces/node';
import {LQueries} from './interfaces/query';
import {Renderer3, RendererFactory3} from './interfaces/renderer';
import {BINDING_INDEX, CLEANUP, CONTEXT, DECLARATION_VIEW, FLAGS, HOST_NODE, LViewData, LViewFlags, OpaqueViewState, QUERIES, RENDERER, SANITIZER, TVIEW, TView} from './interfaces/view';
import {BINDING_INDEX, CLEANUP, CONTEXT, DECLARATION_VIEW, FLAGS, HOST_NODE, LViewData, LViewFlags, OpaqueViewState, QUERIES, RENDERER, RENDERER_FACTORY, SANITIZER, TVIEW, TView} from './interfaces/view';
import {assertDataInRangeInternal, isContentQueryHost} from './util';
/**
@ -51,10 +51,6 @@ export function getRendererFactory(): RendererFactory3 {
return rendererFactory;
}
export function setRendererFactory(factory: RendererFactory3): void {
rendererFactory = factory;
}
export function getCurrentSanitizer(): Sanitizer|null {
return viewData && viewData[SANITIZER];
}
@ -357,6 +353,7 @@ export function enterView(
creationMode = newView && (newView[FLAGS] & LViewFlags.CreationMode) === LViewFlags.CreationMode;
firstTemplatePass = newView && tView.firstTemplatePass;
bindingRootIndex = newView && tView.bindingStartIndex;
rendererFactory = newView && newView[RENDERER_FACTORY];
renderer = newView && newView[RENDERER];
previousOrParentTNode = hostTNode !;

View File

@ -13,7 +13,7 @@ import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, InternalViewRef as viewEn
import {checkNoChanges, checkNoChangesInRootView, detectChanges, detectChangesInRootView, markViewDirty, storeCleanupFn, viewAttached} from './instructions';
import {TNode, TNodeType, TViewNode} from './interfaces/node';
import {FLAGS, HOST, HOST_NODE, LViewData, LViewFlags, PARENT} from './interfaces/view';
import {FLAGS, HOST, HOST_NODE, LViewData, LViewFlags, PARENT, RENDERER_FACTORY} from './interfaces/view';
import {destroyLView} from './node_manipulation';
import {getRendererFactory} from './state';
import {getNativeByTNode} from './util';
@ -241,7 +241,7 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int
* See {@link ChangeDetectorRef#detach detach} for more information.
*/
detectChanges(): void {
const rendererFactory = getRendererFactory();
const rendererFactory = this._view[RENDERER_FACTORY];
if (rendererFactory.begin) {
rendererFactory.begin();
}

View File

@ -60,7 +60,7 @@ export interface TrustedUrlString extends TrustedString { [BRAND]: BypassType.Ur
export interface TrustedResourceUrlString extends TrustedString { [BRAND]: BypassType.ResourceUrl; }
export function allowSanitizationBypass(value: any, type: BypassType): boolean {
return (value instanceof String && (value as TrustedStyleString)[BRAND] === type) ? true : false;
return (value instanceof String && (value as TrustedStyleString)[BRAND] === type);
}
/**

View File

@ -6,13 +6,12 @@
* found in the LICENSE file at https://angular.io/license
*/
import {DebugElement, DebugNode, EventListener, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from '../debug/debug_node';
import {DebugElement__PRE_R3__, DebugNode__PRE_R3__, EventListener, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from '../debug/debug_node';
import {Injector} from '../di';
import {InjectableDef, getInjectableDef} from '../di/defs';
import {InjectableType} from '../di/injectable';
import {ErrorHandler} from '../error_handler';
import {isDevMode} from '../is_dev_mode';
import {ivyEnabled} from '../ivy_switch';
import {ComponentFactory} from '../linker/component_factory';
import {NgModuleRef} from '../linker/ng_module_factory';
import {Renderer2, RendererFactory2, RendererStyleFlags2, RendererType2} from '../render/api';
@ -700,8 +699,8 @@ export class DebugRenderer2 implements Renderer2 {
const el = this.delegate.createElement(name, namespace);
const debugCtx = this.createDebugContext(el);
if (debugCtx) {
const debugEl = new DebugElement(el, null, debugCtx);
debugEl.name = name;
const debugEl = new DebugElement__PRE_R3__(el, null, debugCtx);
(debugEl as{name: string}).name = name;
indexDebugNode(debugEl);
}
return el;
@ -711,7 +710,7 @@ export class DebugRenderer2 implements Renderer2 {
const comment = this.delegate.createComment(value);
const debugCtx = this.createDebugContext(comment);
if (debugCtx) {
indexDebugNode(new DebugNode(comment, null, debugCtx));
indexDebugNode(new DebugNode__PRE_R3__(comment, null, debugCtx));
}
return comment;
}
@ -720,7 +719,7 @@ export class DebugRenderer2 implements Renderer2 {
const text = this.delegate.createText(value);
const debugCtx = this.createDebugContext(text);
if (debugCtx) {
indexDebugNode(new DebugNode(text, null, debugCtx));
indexDebugNode(new DebugNode__PRE_R3__(text, null, debugCtx));
}
return text;
}
@ -728,7 +727,7 @@ export class DebugRenderer2 implements Renderer2 {
appendChild(parent: any, newChild: any): void {
const debugEl = getDebugNode(parent);
const debugChildEl = getDebugNode(newChild);
if (debugEl && debugChildEl && debugEl instanceof DebugElement) {
if (debugEl && debugChildEl && debugEl instanceof DebugElement__PRE_R3__) {
debugEl.addChild(debugChildEl);
}
this.delegate.appendChild(parent, newChild);
@ -738,7 +737,7 @@ export class DebugRenderer2 implements Renderer2 {
const debugEl = getDebugNode(parent);
const debugChildEl = getDebugNode(newChild);
const debugRefEl = getDebugNode(refChild) !;
if (debugEl && debugChildEl && debugEl instanceof DebugElement) {
if (debugEl && debugChildEl && debugEl instanceof DebugElement__PRE_R3__) {
debugEl.insertBefore(debugRefEl, debugChildEl);
}
@ -748,7 +747,7 @@ export class DebugRenderer2 implements Renderer2 {
removeChild(parent: any, oldChild: any): void {
const debugEl = getDebugNode(parent);
const debugChildEl = getDebugNode(oldChild);
if (debugEl && debugChildEl && debugEl instanceof DebugElement) {
if (debugEl && debugChildEl && debugEl instanceof DebugElement__PRE_R3__) {
debugEl.removeChild(debugChildEl);
}
this.delegate.removeChild(parent, oldChild);
@ -756,16 +755,16 @@ export class DebugRenderer2 implements Renderer2 {
selectRootElement(selectorOrNode: string|any, preserveContent?: boolean): any {
const el = this.delegate.selectRootElement(selectorOrNode, preserveContent);
const debugCtx = getCurrentDebugContext() || (ivyEnabled ? this.createDebugContext(el) : null);
const debugCtx = getCurrentDebugContext();
if (debugCtx) {
indexDebugNode(new DebugElement(el, null, debugCtx));
indexDebugNode(new DebugElement__PRE_R3__(el, null, debugCtx));
}
return el;
}
setAttribute(el: any, name: string, value: string, namespace?: string): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
if (debugEl && debugEl instanceof DebugElement__PRE_R3__) {
const fullName = namespace ? namespace + ':' + name : name;
debugEl.attributes[fullName] = value;
}
@ -774,7 +773,7 @@ export class DebugRenderer2 implements Renderer2 {
removeAttribute(el: any, name: string, namespace?: string): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
if (debugEl && debugEl instanceof DebugElement__PRE_R3__) {
const fullName = namespace ? namespace + ':' + name : name;
debugEl.attributes[fullName] = null;
}
@ -783,7 +782,7 @@ export class DebugRenderer2 implements Renderer2 {
addClass(el: any, name: string): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
if (debugEl && debugEl instanceof DebugElement__PRE_R3__) {
debugEl.classes[name] = true;
}
this.delegate.addClass(el, name);
@ -791,7 +790,7 @@ export class DebugRenderer2 implements Renderer2 {
removeClass(el: any, name: string): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
if (debugEl && debugEl instanceof DebugElement__PRE_R3__) {
debugEl.classes[name] = false;
}
this.delegate.removeClass(el, name);
@ -799,7 +798,7 @@ export class DebugRenderer2 implements Renderer2 {
setStyle(el: any, style: string, value: any, flags: RendererStyleFlags2): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
if (debugEl && debugEl instanceof DebugElement__PRE_R3__) {
debugEl.styles[style] = value;
}
this.delegate.setStyle(el, style, value, flags);
@ -807,7 +806,7 @@ export class DebugRenderer2 implements Renderer2 {
removeStyle(el: any, style: string, flags: RendererStyleFlags2): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
if (debugEl && debugEl instanceof DebugElement__PRE_R3__) {
debugEl.styles[style] = null;
}
this.delegate.removeStyle(el, style, flags);
@ -815,7 +814,7 @@ export class DebugRenderer2 implements Renderer2 {
setProperty(el: any, name: string, value: any): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
if (debugEl && debugEl instanceof DebugElement__PRE_R3__) {
debugEl.properties[name] = value;
}
this.delegate.setProperty(el, name, value);

View File

@ -176,6 +176,9 @@
{
"name": "RENDERER"
},
{
"name": "RENDERER_FACTORY"
},
{
"name": "RENDER_PARENT"
},
@ -611,9 +614,6 @@
{
"name": "getCurrentQueries"
},
{
"name": "getCurrentSanitizer"
},
{
"name": "getDirectiveDef"
},
@ -1145,9 +1145,6 @@
{
"name": "setProp"
},
{
"name": "setRendererFactory"
},
{
"name": "setStyle"
},

View File

@ -107,6 +107,9 @@
{
"name": "RENDERER"
},
{
"name": "RENDERER_FACTORY"
},
{
"name": "RENDER_PARENT"
},
@ -320,9 +323,6 @@
{
"name": "getRenderer"
},
{
"name": "getRendererFactory"
},
{
"name": "getRootContext"
},
@ -458,9 +458,6 @@
{
"name": "setPreviousOrParentTNode"
},
{
"name": "setRendererFactory"
},
{
"name": "setTNodeAndViewData"
},

View File

@ -356,6 +356,9 @@
{
"name": "RENDERER"
},
{
"name": "RENDERER_FACTORY"
},
{
"name": "RENDER_PARENT"
},
@ -392,6 +395,9 @@
{
"name": "SafeSubscriber"
},
{
"name": "Sanitizer"
},
{
"name": "Self"
},
@ -455,9 +461,6 @@
{
"name": "ViewEncapsulation"
},
{
"name": "WRAP_RENDERER_FACTORY2"
},
{
"name": "_CLEAN_PROMISE"
},
@ -548,6 +551,9 @@
{
"name": "_enable_super_gross_mode_that_will_cause_bad_things"
},
{
"name": "_getViewData"
},
{
"name": "_global"
},
@ -950,9 +956,6 @@
{
"name": "getRenderer"
},
{
"name": "getRendererFactory"
},
{
"name": "getRootContext"
},
@ -1322,9 +1325,6 @@
{
"name": "setPreviousOrParentTNode"
},
{
"name": "setRendererFactory"
},
{
"name": "setRootDomAdapter"
},

View File

@ -170,6 +170,9 @@
{
"name": "RENDERER"
},
{
"name": "RENDERER_FACTORY"
},
{
"name": "RENDER_PARENT"
},
@ -659,9 +662,6 @@
{
"name": "getCurrentQueries"
},
{
"name": "getCurrentSanitizer"
},
{
"name": "getCurrentView"
},
@ -1166,9 +1166,6 @@
{
"name": "setProp"
},
{
"name": "setRendererFactory"
},
{
"name": "setStyle"
},

View File

@ -137,6 +137,24 @@
{
"name": "Compiler"
},
{
"name": "Compiler_compileModuleAndAllComponentsAsync"
},
{
"name": "Compiler_compileModuleAndAllComponentsSync"
},
{
"name": "Compiler_compileModuleAndAllComponentsSync__POST_R3__"
},
{
"name": "Compiler_compileModuleAsync"
},
{
"name": "Compiler_compileModuleSync"
},
{
"name": "Compiler_compileModuleSync__POST_R3__"
},
{
"name": "ComponentFactory"
},
@ -209,6 +227,12 @@
{
"name": "DateType"
},
{
"name": "DebugElement__POST_R3__"
},
{
"name": "DebugNode__POST_R3__"
},
{
"name": "DecimalPipe"
},
@ -446,6 +470,9 @@
{
"name": "MergeMapSubscriber"
},
{
"name": "ModuleWithComponentFactories"
},
{
"name": "MulticastOperator"
},
@ -698,6 +725,9 @@
{
"name": "RENDERER"
},
{
"name": "RENDERER_FACTORY"
},
{
"name": "RENDER_PARENT"
},
@ -950,9 +980,6 @@
{
"name": "ViewRef"
},
{
"name": "WRAP_RENDERER_FACTORY2"
},
{
"name": "WrappedValue"
},
@ -1136,6 +1163,9 @@
{
"name": "_enable_super_gross_mode_that_will_cause_bad_things"
},
{
"name": "_getViewData"
},
{
"name": "_global"
},
@ -1151,9 +1181,6 @@
{
"name": "_localeFactory"
},
{
"name": "_nativeNodeToDebugNode"
},
{
"name": "_ngProbeTokensToMap"
},
@ -1163,6 +1190,9 @@
{
"name": "_promiseStrategy"
},
{
"name": "_queryNodeChildrenR3"
},
{
"name": "_randomChar"
},
@ -1184,9 +1214,6 @@
{
"name": "_testabilityGetter"
},
{
"name": "_throwError"
},
{
"name": "addComponentLogic"
},
@ -1481,6 +1508,9 @@
{
"name": "directiveInject"
},
{
"name": "discoverLocalRefs"
},
{
"name": "domRendererFactory3"
},
@ -1565,6 +1595,12 @@
{
"name": "findViaComponent"
},
{
"name": "findViaDirective"
},
{
"name": "findViaNativeElement"
},
{
"name": "firstTemplatePass"
},
@ -1646,6 +1682,12 @@
{
"name": "getClosureSafeProperty"
},
{
"name": "getComponent"
},
{
"name": "getComponentAtNodeIndex"
},
{
"name": "getComponentDef"
},
@ -1658,6 +1700,9 @@
{
"name": "getContainerRenderParent"
},
{
"name": "getContext"
},
{
"name": "getContextViewData"
},
@ -1670,9 +1715,6 @@
{
"name": "getCurrentQueries"
},
{
"name": "getCurrentSanitizer"
},
{
"name": "getCurrentView"
},
@ -1694,9 +1736,21 @@
{
"name": "getDebugNode"
},
{
"name": "getDebugNode__POST_R3__"
},
{
"name": "getDirectiveDef"
},
{
"name": "getDirectiveEndIndex"
},
{
"name": "getDirectiveStartIndex"
},
{
"name": "getDirectivesAtNodeIndex"
},
{
"name": "getElementDepthCount"
},
@ -1727,6 +1781,9 @@
{
"name": "getInjectableDef"
},
{
"name": "getInjector"
},
{
"name": "getInjectorDef"
},
@ -1745,6 +1802,9 @@
{
"name": "getLastDefinedValue"
},
{
"name": "getLocalRefs"
},
{
"name": "getLocaleCurrencies"
},
@ -2075,6 +2135,9 @@
{
"name": "isComponentDef"
},
{
"name": "isComponentInstance"
},
{
"name": "isContextDirty"
},
@ -2093,6 +2156,12 @@
{
"name": "isDifferent"
},
{
"name": "isDirectiveDefHack"
},
{
"name": "isDirectiveInstance"
},
{
"name": "isDirty"
},
@ -2195,6 +2264,9 @@
{
"name": "listener"
},
{
"name": "loadContext"
},
{
"name": "loadInternal"
},
@ -2288,6 +2360,9 @@
{
"name": "noopScope"
},
{
"name": "notImplemented"
},
{
"name": "observable"
},
@ -2531,9 +2606,6 @@
{
"name": "setProp"
},
{
"name": "setRendererFactory"
},
{
"name": "setRootDomAdapter"
},
@ -2660,6 +2732,9 @@
{
"name": "trackByIdentity"
},
{
"name": "traverseNextElement"
},
{
"name": "tryCatch"
},

View File

@ -940,24 +940,26 @@ function declareTests(config?: {useJit: boolean}) {
expect(getDOM().getProperty(tc.nativeElement, 'id')).toEqual('newId');
});
it('should not use template variables for expressions in hostProperties', () => {
@Directive({selector: '[host-properties]', host: {'[id]': 'id', '[title]': 'unknownProp'}})
class DirectiveWithHostProps {
id = 'one';
}
fixmeIvy('FW-681: not possible to retrieve host property bindings from TView') &&
it('should not use template variables for expressions in hostProperties', () => {
@Directive(
{selector: '[host-properties]', host: {'[id]': 'id', '[title]': 'unknownProp'}})
class DirectiveWithHostProps {
id = 'one';
}
const fixture =
TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithHostProps]})
.overrideComponent(
MyComp,
{set: {template: `<div *ngFor="let id of ['forId']" host-properties></div>`}})
.createComponent(MyComp);
fixture.detectChanges();
const fixture =
TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithHostProps]})
.overrideComponent(MyComp, {
set: {template: `<div *ngFor="let id of ['forId']" host-properties></div>`}
})
.createComponent(MyComp);
fixture.detectChanges();
const tc = fixture.debugElement.children[0];
expect(tc.properties['id']).toBe('one');
expect(tc.properties['title']).toBe(undefined);
});
const tc = fixture.debugElement.children[0];
expect(tc.properties['id']).toBe('one');
expect(tc.properties['title']).toBe(undefined);
});
fixmeIvy('FW-725: Pipes in host bindings fail with a cryptic error') &&
it('should not allow pipes in hostProperties', () => {
@ -1113,7 +1115,7 @@ function declareTests(config?: {useJit: boolean}) {
.toHaveText('dynamic greet');
}));
fixmeIvy('FW-561: Runtime compiler is not loaded') &&
fixmeIvy('FW-707: TestBed: No LViewData in getParentInjectorLocation') &&
it('should create a component that has been freshly compiled', () => {
@Component({template: ''})
class RootComp {
@ -1153,7 +1155,7 @@ function declareTests(config?: {useJit: boolean}) {
expect(compRef.instance.someToken).toBe('someRootValue');
});
fixmeIvy('FW-561: Runtime compiler is not loaded') &&
fixmeIvy('FW-707: TestBed: No LViewData in getParentInjectorLocation') &&
it('should create a component with the passed NgModuleRef', () => {
@Component({template: ''})
class RootComp {
@ -1194,7 +1196,7 @@ function declareTests(config?: {useJit: boolean}) {
expect(compRef.instance.someToken).toBe('someValue');
});
fixmeIvy('FW-561: Runtime compiler is not loaded') &&
fixmeIvy('FW-707: TestBed: No LViewData in getParentInjectorLocation') &&
it('should create a component with the NgModuleRef of the ComponentFactoryResolver',
() => {
@Component({template: ''})

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,7 @@ import {defineComponent} from '../../src/render3/definition';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, text, textBinding} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {ComponentFixture, TemplateFixture, createComponent, renderToHtml} from './render_util';
import {ComponentFixture, TemplateFixture, createComponent} from './render_util';
describe('JS control flow', () => {
it('should work with if block', () => {

View File

@ -2021,8 +2021,8 @@ describe('di', () => {
describe('getOrCreateNodeInjector', () => {
it('should handle initial undefined state', () => {
const contentView = createLViewData(
null, null !, createTView(-1, null, 1, 0, null, null, null), null,
LViewFlags.CheckAlways);
null, createTView(-1, null, 1, 0, null, null, null), null, LViewFlags.CheckAlways,
{} as any, {} as any);
const oldView = enterView(contentView, null);
try {
const parentTNode = createNodeAtIndex(0, TNodeType.Element, null, null, null);

View File

@ -33,8 +33,8 @@ describe('style and class based bindings', () => {
const rootContext =
createRootContext(requestAnimationFrame.bind(window), playerHandler || null);
const lViewData = createLViewData(
null, domRendererFactory3.createRenderer(element, null),
createTView(-1, null, 1, 0, null, null, null), rootContext, LViewFlags.IsRoot);
null, createTView(-1, null, 1, 0, null, null, null), rootContext, LViewFlags.IsRoot,
domRendererFactory3, domRendererFactory3.createRenderer(element, null));
return lViewData;
}

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Component, Directive, Injector, NgModule, NgZone, Pipe, PlatformRef, Provider, RendererFactory2, SchemaMetadata, Type, ɵInjectableDef as InjectableDef, ɵNgModuleDef as NgModuleDef, ɵNgModuleTransitiveScopes as NgModuleTransitiveScopes, ɵRender3ComponentFactory as ComponentFactory, ɵRender3DebugRendererFactory2 as Render3DebugRendererFactory2, ɵRender3NgModuleRef as NgModuleRef, ɵWRAP_RENDERER_FACTORY2 as WRAP_RENDERER_FACTORY2, ɵcompileComponent as compileComponent, ɵcompileDirective as compileDirective, ɵcompileNgModuleDefs as compileNgModuleDefs, ɵcompilePipe as compilePipe, ɵgetInjectableDef as getInjectableDef, ɵpatchComponentDefWithScope as patchComponentDefWithScope, ɵstringify as stringify} from '@angular/core';
import {Component, Directive, Injector, NgModule, NgZone, Pipe, PlatformRef, Provider, RendererFactory2, SchemaMetadata, Type, ɵInjectableDef as InjectableDef, ɵNgModuleDef as NgModuleDef, ɵNgModuleTransitiveScopes as NgModuleTransitiveScopes, ɵRender3ComponentFactory as ComponentFactory, ɵRender3NgModuleRef as NgModuleRef, ɵcompileComponent as compileComponent, ɵcompileDirective as compileDirective, ɵcompileNgModuleDefs as compileNgModuleDefs, ɵcompilePipe as compilePipe, ɵgetInjectableDef as getInjectableDef, ɵpatchComponentDefWithScope as patchComponentDefWithScope, ɵstringify as stringify} from '@angular/core';
import {ComponentFixture} from './component_fixture';
import {MetadataOverride} from './metadata_override';
@ -423,13 +423,8 @@ export class TestBedRender3 implements Injector, TestBed {
private _createTestModule(): Type<any> {
const rootProviderOverrides = this._rootProviderOverrides;
const rendererFactoryWrapper = {
provide: WRAP_RENDERER_FACTORY2,
useFactory: () => (rf: RendererFactory2) => new Render3DebugRendererFactory2(rf),
};
@NgModule({
providers: [...rootProviderOverrides, rendererFactoryWrapper],
providers: [...rootProviderOverrides],
jit: true,
})
class RootScopeModule {

File diff suppressed because it is too large Load Diff

View File

@ -36,20 +36,20 @@ describe('RouterPreloader', () => {
});
});
fixmeIvy('FW-561: Runtime compiler is not loaded') &&
it('should work',
fakeAsync(inject(
[NgModuleFactoryLoader, RouterPreloader, Router],
(loader: SpyNgModuleFactoryLoader, preloader: RouterPreloader, router: Router) => {
loader.stubbedModules = {expected: LoadedModule};
preloader.preload().subscribe(() => {});
it('should work',
fakeAsync(inject(
[NgModuleFactoryLoader, RouterPreloader, Router],
(loader: SpyNgModuleFactoryLoader, preloader: RouterPreloader, router: Router) => {
loader.stubbedModules = {expected: LoadedModule};
tick();
preloader.preload().subscribe(() => {});
const c = router.config;
expect((c[0] as any)._loadedConfig).not.toBeDefined();
})));
tick();
const c = router.config;
expect((c[0] as any)._loadedConfig).not.toBeDefined();
})));
});
describe('should preload configurations', () => {
@ -60,7 +60,8 @@ describe('RouterPreloader', () => {
});
});
fixmeIvy('FW-561: Runtime compiler is not loaded') &&
fixmeIvy('unknown') &&
it('should work',
fakeAsync(inject(
[NgModuleFactoryLoader, RouterPreloader, Router, NgModuleRef],
@ -200,21 +201,21 @@ describe('RouterPreloader', () => {
});
});
fixmeIvy('FW-561: Runtime compiler is not loaded') &&
it('should work',
fakeAsync(inject(
[NgModuleFactoryLoader, RouterPreloader, Router],
(loader: SpyNgModuleFactoryLoader, preloader: RouterPreloader, router: Router) => {
loader.stubbedModules = {expected2: LoadedModule};
preloader.preload().subscribe(() => {});
it('should work',
fakeAsync(inject(
[NgModuleFactoryLoader, RouterPreloader, Router],
(loader: SpyNgModuleFactoryLoader, preloader: RouterPreloader, router: Router) => {
loader.stubbedModules = {expected2: LoadedModule};
tick();
preloader.preload().subscribe(() => {});
const c = router.config;
expect((c[0] as any)._loadedConfig).not.toBeDefined();
expect((c[1] as any)._loadedConfig).toBeDefined();
})));
tick();
const c = router.config;
expect((c[0] as any)._loadedConfig).not.toBeDefined();
expect((c[1] as any)._loadedConfig).toBeDefined();
})));
});
describe('should copy loaded configs', () => {
@ -230,22 +231,22 @@ describe('RouterPreloader', () => {
});
});
fixmeIvy('FW-561: Runtime compiler is not loaded') &&
it('should work',
fakeAsync(inject(
[NgModuleFactoryLoader, RouterPreloader, Router],
(loader: SpyNgModuleFactoryLoader, preloader: RouterPreloader, router: Router) => {
loader.stubbedModules = {expected: LoadedModule};
preloader.preload().subscribe(() => {});
it('should work',
fakeAsync(inject(
[NgModuleFactoryLoader, RouterPreloader, Router],
(loader: SpyNgModuleFactoryLoader, preloader: RouterPreloader, router: Router) => {
loader.stubbedModules = {expected: LoadedModule};
tick();
preloader.preload().subscribe(() => {});
const c = router.config as{_loadedConfig: LoadedRouterConfig}[];
expect(c[0]._loadedConfig).toBeDefined();
expect(c[0]._loadedConfig !.routes).not.toBe(configs);
expect(c[0]._loadedConfig !.routes[0]).not.toBe(configs[0]);
expect(c[0]._loadedConfig !.routes[0].component).toBe(configs[0].component);
})));
tick();
const c = router.config as{_loadedConfig: LoadedRouterConfig}[];
expect(c[0]._loadedConfig).toBeDefined();
expect(c[0]._loadedConfig !.routes).not.toBe(configs);
expect(c[0]._loadedConfig !.routes[0]).not.toBe(configs[0]);
expect(c[0]._loadedConfig !.routes[0].component).toBe(configs[0].component);
})));
});
});

View File

@ -76,12 +76,12 @@ export interface CollectionChangeRecord<V> extends IterableChangeRecord<V> {
}
export declare class Compiler {
compileModuleAndAllComponentsAsync: <T>(moduleType: Type<T>) => Promise<ModuleWithComponentFactories<T>>;
compileModuleAndAllComponentsSync: <T>(moduleType: Type<T>) => ModuleWithComponentFactories<T>;
compileModuleAsync: <T>(moduleType: Type<T>) => Promise<NgModuleFactory<T>>;
compileModuleSync: <T>(moduleType: Type<T>) => NgModuleFactory<T>;
clearCache(): void;
clearCacheFor(type: Type<any>): void;
compileModuleAndAllComponentsAsync<T>(moduleType: Type<T>): Promise<ModuleWithComponentFactories<T>>;
compileModuleAndAllComponentsSync<T>(moduleType: Type<T>): ModuleWithComponentFactories<T>;
compileModuleAsync<T>(moduleType: Type<T>): Promise<NgModuleFactory<T>>;
compileModuleSync<T>(moduleType: Type<T>): NgModuleFactory<T>;
getModuleId(moduleType: Type<any>): string | undefined;
}
@ -188,48 +188,50 @@ export declare function createPlatformFactory(parentPlatformFactory: ((extraProv
export declare const CUSTOM_ELEMENTS_SCHEMA: SchemaMetadata;
export declare class DebugElement extends DebugNode {
attributes: {
export interface DebugElement extends DebugNode {
readonly attributes: {
[key: string]: string | null;
};
childNodes: DebugNode[];
readonly childNodes: DebugNode[];
readonly children: DebugElement[];
classes: {
readonly classes: {
[key: string]: boolean;
};
name: string;
nativeElement: any;
properties: {
readonly name: string;
readonly nativeElement: any;
readonly properties: {
[key: string]: any;
};
styles: {
readonly styles: {
[key: string]: string | null;
};
constructor(nativeNode: any, parent: any, _debugContext: DebugContext);
addChild(child: DebugNode): void;
insertBefore(refChild: DebugNode, newChild: DebugNode): void;
insertChildrenAfter(child: DebugNode, newChildren: DebugNode[]): void;
query(predicate: Predicate<DebugElement>): DebugElement;
queryAll(predicate: Predicate<DebugElement>): DebugElement[];
queryAllNodes(predicate: Predicate<DebugNode>): DebugNode[];
removeChild(child: DebugNode): void;
triggerEventHandler(eventName: string, eventObj: any): void;
}
export declare class DebugNode {
export declare const DebugElement: {
new (...args: any[]): DebugElement;
};
export interface DebugNode {
readonly componentInstance: any;
readonly context: any;
readonly injector: Injector;
listeners: EventListener[];
nativeNode: any;
parent: DebugElement | null;
readonly listeners: EventListener[];
readonly nativeNode: any;
readonly parent: DebugElement | null;
readonly providerTokens: any[];
readonly references: {
[key: string]: any;
};
constructor(nativeNode: any, parent: DebugNode | null, _debugContext: DebugContext);
}
export declare const DebugNode: {
new (...args: any[]): DebugNode;
};
/** @deprecated */
export declare class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChanges<V> {
readonly collection: V[] | Iterable<V> | null;
@ -330,7 +332,7 @@ export interface ForwardRefFn {
(): any;
}
export declare function getDebugNode(nativeNode: any): DebugNode | null;
export declare const getDebugNode: (nativeNode: any) => DebugNode | null;
export declare function getModuleFactory(id: string): NgModuleFactory<any>;