refactor(core): add a checkIndex to the compiler view nodes

Each node now has two index: nodeIndex and checkIndex.

nodeIndex is the index in both the view definition and the view data.
checkIndex is the index in in the update function (update directives and update
renderer).

While nodeIndex and checkIndex have the same value for now, having both of them
will allow changing the structure of view definition after compilation (ie for
runtime translations).
This commit is contained in:
Victor Berchet
2017-09-22 14:29:16 -07:00
committed by Alex Rickabaugh
parent caa51950e8
commit 0833b59aab
27 changed files with 666 additions and 781 deletions

View File

@ -6,47 +6,35 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation, getDebugNode} from '@angular/core';
import {DebugContext, NodeDef, NodeFlags, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
import {getDebugNode} from '@angular/core';
import {NodeFlags, anchorDef, asElementData, elementDef} from '@angular/core/src/view/index';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {createRootView, isBrowser} from './helper';
import {compViewDef, createAndGetRootNodes} from './helper';
export function main() {
describe(`View Anchor`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn,
updateRenderer?: ViewUpdateFn): ViewDefinition {
return viewDef(ViewFlags.None, nodes, updateDirectives, updateRenderer);
}
function createAndGetRootNodes(
viewDef: ViewDefinition, ctx?: any): {rootNodes: any[], view: ViewData} {
const view = createRootView(viewDef, ctx);
const rootNodes = rootRenderNodes(view);
return {rootNodes, view};
}
describe('create', () => {
it('should create anchor nodes without parents', () => {
const rootNodes = createAndGetRootNodes(compViewDef([
anchorDef(NodeFlags.None, null !, null !, 0)
anchorDef(NodeFlags.None, null, null, 0)
])).rootNodes;
expect(rootNodes.length).toBe(1);
});
it('should create views with multiple root anchor nodes', () => {
const rootNodes = createAndGetRootNodes(compViewDef([
anchorDef(NodeFlags.None, null !, null !, 0),
anchorDef(NodeFlags.None, null !, null !, 0)
])).rootNodes;
const rootNodes =
createAndGetRootNodes(compViewDef([
anchorDef(NodeFlags.None, null, null, 0), anchorDef(NodeFlags.None, null, null, 0)
])).rootNodes;
expect(rootNodes.length).toBe(2);
});
it('should create anchor nodes with parents', () => {
const rootNodes = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'div'),
anchorDef(NodeFlags.None, null !, null !, 0),
elementDef(0, NodeFlags.None, null, null, 1, 'div'),
anchorDef(NodeFlags.None, null, null, 0),
])).rootNodes;
expect(getDOM().childNodes(rootNodes[0]).length).toBe(1);
});
@ -54,7 +42,7 @@ export function main() {
it('should add debug information to the renderer', () => {
const someContext = new Object();
const {view, rootNodes} = createAndGetRootNodes(
compViewDef([anchorDef(NodeFlags.None, null !, null !, 0)]), someContext);
compViewDef([anchorDef(NodeFlags.None, null, null, 0)]), someContext);
expect(getDebugNode(rootNodes[0]) !.nativeNode).toBe(asElementData(view, 0).renderElement);
});
});

View File

@ -6,11 +6,12 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation} from '@angular/core';
import {ArgumentType, BindingFlags, NodeCheckFn, NodeDef, NodeFlags, OutputType, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewState, ViewUpdateFn, anchorDef, asElementData, asProviderData, directiveDef, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
import {SecurityContext} from '@angular/core';
import {ArgumentType, BindingFlags, NodeCheckFn, NodeFlags, Services, ViewData, ViewFlags, ViewState, asElementData, directiveDef, elementDef, rootRenderNodes} from '@angular/core/src/view/index';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {callMostRecentEventListenerHandler, createRootView, isBrowser, recordNodeToRemove} from './helper';
import {callMostRecentEventListenerHandler, compViewDef, createAndGetRootNodes, createRootView, isBrowser, recordNodeToRemove} from './helper';
/**
@ -21,18 +22,6 @@ const addEventListener = '__zone_symbol__addEventListener';
export function main() {
describe(`Component Views`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function createAndGetRootNodes(viewDef: ViewDefinition): {rootNodes: any[], view: ViewData} {
const view = createRootView(viewDef);
const rootNodes = rootRenderNodes(view);
return {rootNodes, view};
}
it('should create and attach component views', () => {
let instance: AComp = undefined !;
class AComp {
@ -41,11 +30,11 @@ export function main() {
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(
NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !,
0, NodeFlags.None, null, null, 1, 'div', null, null, null, null,
() => compViewDef([
elementDef(NodeFlags.None, null !, null !, 0, 'span'),
elementDef(0, NodeFlags.None, null, null, 0, 'span'),
])),
directiveDef(NodeFlags.Component, null !, 0, AComp, []),
directiveDef(1, NodeFlags.Component, null, 0, AComp, []),
]));
const compView = asElementData(view, 0).componentView;
@ -69,7 +58,7 @@ export function main() {
it('should select root elements based on a selector', () => {
const view = createRootView(
compViewDef([
elementDef(NodeFlags.None, null !, null !, 0, 'div'),
elementDef(0, NodeFlags.None, null, null, 0, 'div'),
]),
{}, [], 'root');
const rootNodes = rootRenderNodes(view);
@ -79,7 +68,7 @@ export function main() {
it('should select root elements based on a node', () => {
const view = createRootView(
compViewDef([
elementDef(NodeFlags.None, null !, null !, 0, 'div'),
elementDef(0, NodeFlags.None, null, null, 0, 'div'),
]),
{}, [], rootNode);
const rootNodes = rootRenderNodes(view);
@ -87,9 +76,9 @@ export function main() {
});
it('should set attributes on the root node', () => {
const view = createRootView(
createRootView(
compViewDef([
elementDef(NodeFlags.None, null !, null !, 0, 'div', [['a', 'b']]),
elementDef(0, NodeFlags.None, null, null, 0, 'div', [['a', 'b']]),
]),
{}, [], rootNode);
expect(rootNode.getAttribute('a')).toBe('b');
@ -97,9 +86,9 @@ export function main() {
it('should clear the content of the root node', () => {
rootNode.appendChild(document.createElement('div'));
const view = createRootView(
createRootView(
compViewDef([
elementDef(NodeFlags.None, null !, null !, 0, 'div', [['a', 'b']]),
elementDef(0, NodeFlags.None, null, null, 0, 'div', [['a', 'b']]),
]),
{}, [], rootNode);
expect(rootNode.childNodes.length).toBe(0);
@ -121,12 +110,12 @@ export function main() {
const {view, rootNodes} = createAndGetRootNodes(
compViewDef([
elementDef(NodeFlags.None, null!, null!, 1, 'div', null!, null!, null!, null!, () => compViewDef(
elementDef(0, NodeFlags.None, null, null, 1, 'div', null, null, null, null, () => compViewDef(
[
elementDef(NodeFlags.None, null!, null!, 0, 'span', null!, [[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]]),
], null!, update
elementDef(0, NodeFlags.None, null, null, 0, 'span', null, [[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]]),
], null, update
)),
directiveDef(NodeFlags.Component, null!, 0, AComp, []),
directiveDef(1, NodeFlags.Component, null, 0, AComp, []),
]));
const compView = asElementData(view, 0).componentView;
@ -155,13 +144,13 @@ export function main() {
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(
NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !,
0, NodeFlags.None, null, null, 1, 'div', null, null, null, null,
() => compViewDef(
[
elementDef(NodeFlags.None, null !, null !, 0, 'span'),
elementDef(0, NodeFlags.None, null, null, 0, 'span'),
],
update)),
directiveDef(NodeFlags.Component, null !, 0, AComp, [], null !, null !),
directiveDef(1, NodeFlags.Component, null, 0, AComp, [], null, null),
]));
const compView = asElementData(view, 0).componentView;
@ -192,17 +181,17 @@ export function main() {
const {view} = createAndGetRootNodes(compViewDef(
[
elementDef(
NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !,
0, NodeFlags.None, null, null, 1, 'div', null, null, null, null,
() => {
return compViewDef(
[
elementDef(
NodeFlags.None, null !, null !, 0, 'span', null !, null !,
0, NodeFlags.None, null, null, 0, 'span', null, null,
[[null !, 'click']]),
],
update, null !, ViewFlags.OnPush);
update, null, ViewFlags.OnPush);
}),
directiveDef(NodeFlags.Component, null !, 0, AComp, [], {a: [0, 'a']}),
directiveDef(1, NodeFlags.Component, null, 0, AComp, [], {a: [0, 'a']}),
],
(check, view) => { check(view, 1, ArgumentType.Inline, compInputValue); }));
@ -245,18 +234,16 @@ export function main() {
const update = jasmine.createSpy('updater');
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null!, null!, 1, 'div', null!, null!, null!, null!, () => compViewDef(
[
elementDef(NodeFlags.None, null!, null!, 0, 'span', null!, [[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]]),
],
null!, update)),
directiveDef(
NodeFlags.Component, null!, 0, AComp, [], null!, null!,
),
elementDef(
0, NodeFlags.None, null, null, 1, 'div', null, null, null, null,
() => compViewDef(
[elementDef(
0, NodeFlags.None, null, null, 0, 'span', null,
[[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]])],
null, update)),
directiveDef(1, NodeFlags.Component, null, 0, AComp, [], null, null, ),
]));
const compView = asElementData(view, 0).componentView;
update.and.callFake((check: NodeCheckFn, view: ViewData) => { throw new Error('Test'); });
expect(() => Services.checkAndUpdateView(view)).toThrowError('Test');
expect(update).toHaveBeenCalled();
@ -280,12 +267,12 @@ export function main() {
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(
NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !,
0, NodeFlags.None, null, null, 1, 'div', null, null, null, null,
() => compViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.OnDestroy, null !, 0, ChildProvider, [])
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(1, NodeFlags.OnDestroy, null, 0, ChildProvider, [])
])),
directiveDef(NodeFlags.Component, null !, 0, AComp, [], null !, null !, ),
directiveDef(1, NodeFlags.Component, null, 0, AComp, [], null, null, ),
]));
Services.destroyView(view);
@ -294,11 +281,8 @@ export function main() {
});
it('should throw on dirty checking destroyed views', () => {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
[
elementDef(NodeFlags.None, null !, null !, 0, 'div'),
],
(view) => {}));
const {view, rootNodes} = createAndGetRootNodes(
compViewDef([elementDef(0, NodeFlags.None, null, null, 0, 'div')]));
Services.destroyView(view);

View File

@ -6,13 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ErrorHandler, Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation, WrappedValue, getDebugNode} from '@angular/core';
import {ErrorHandler, SecurityContext, getDebugNode} from '@angular/core';
import {getDebugContext} from '@angular/core/src/errors';
import {ArgumentType, BindingFlags, DebugContext, NodeDef, NodeFlags, OutputType, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
import {BindingFlags, NodeFlags, Services, ViewData, ViewDefinition, asElementData, elementDef} from '@angular/core/src/view/index';
import {TestBed} from '@angular/core/testing';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {ARG_TYPE_VALUES, callMostRecentEventListenerHandler, checkNodeInlineOrDynamic, createRootView, isBrowser, recordNodeToRemove} from './helper';
import {ARG_TYPE_VALUES, callMostRecentEventListenerHandler, checkNodeInlineOrDynamic, compViewDef, createAndGetRootNodes, isBrowser, recordNodeToRemove} from './helper';
/**
@ -24,23 +25,11 @@ const removeEventListener = '__zone_symbol__removeEventListener';
export function main() {
describe(`View Elements`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function createAndGetRootNodes(
viewDef: ViewDefinition, context?: any): {rootNodes: any[], view: ViewData} {
const view = createRootView(viewDef, context);
const rootNodes = rootRenderNodes(view);
return {rootNodes, view};
}
describe('create', () => {
it('should create elements without parents', () => {
const rootNodes = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 0, 'span')
elementDef(0, NodeFlags.None, null, null, 0, 'span')
])).rootNodes;
expect(rootNodes.length).toBe(1);
expect(getDOM().nodeName(rootNodes[0]).toLowerCase()).toBe('span');
@ -48,16 +37,16 @@ export function main() {
it('should create views with multiple root elements', () => {
const rootNodes = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 0, 'span'),
elementDef(NodeFlags.None, null !, null !, 0, 'span')
elementDef(0, NodeFlags.None, null, null, 0, 'span'),
elementDef(1, NodeFlags.None, null, null, 0, 'span'),
])).rootNodes;
expect(rootNodes.length).toBe(2);
});
it('should create elements with parents', () => {
const rootNodes = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'div'),
elementDef(NodeFlags.None, null !, null !, 0, 'span'),
elementDef(0, NodeFlags.None, null, null, 1, 'div'),
elementDef(1, NodeFlags.None, null, null, 0, 'span'),
])).rootNodes;
expect(rootNodes.length).toBe(1);
const spanEl = getDOM().childNodes(rootNodes[0])[0];
@ -66,7 +55,7 @@ export function main() {
it('should set fixed attributes', () => {
const rootNodes = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 0, 'div', [['title', 'a']]),
elementDef(0, NodeFlags.None, null, null, 0, 'div', [['title', 'a']]),
])).rootNodes;
expect(rootNodes.length).toBe(1);
expect(getDOM().getAttribute(rootNodes[0], 'title')).toBe('a');
@ -75,7 +64,7 @@ export function main() {
it('should add debug information to the renderer', () => {
const someContext = new Object();
const {view, rootNodes} = createAndGetRootNodes(
compViewDef([elementDef(NodeFlags.None, null !, null !, 0, 'div')]), someContext);
compViewDef([elementDef(0, NodeFlags.None, null, null, 0, 'div')]), someContext);
expect(getDebugNode(rootNodes[0]) !.nativeNode).toBe(asElementData(view, 0).renderElement);
});
});
@ -87,13 +76,13 @@ export function main() {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
[
elementDef(
NodeFlags.None, null !, null !, 0, 'input', null !,
0, NodeFlags.None, null, null, 0, 'input', null,
[
[BindingFlags.TypeProperty, 'title', SecurityContext.NONE],
[BindingFlags.TypeProperty, 'value', SecurityContext.NONE]
[BindingFlags.TypeProperty, 'value', SecurityContext.NONE],
]),
],
null !, (check, view) => {
null, (check, view) => {
checkNodeInlineOrDynamic(check, view, 0, inlineDynamic, ['v1', 'v2']);
}));
@ -112,13 +101,13 @@ export function main() {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
[
elementDef(
NodeFlags.None, null !, null !, 0, 'div', null !,
0, NodeFlags.None, null, null, 0, 'div', null,
[
[BindingFlags.TypeElementAttribute, 'a1', SecurityContext.NONE],
[BindingFlags.TypeElementAttribute, 'a2', SecurityContext.NONE]
[BindingFlags.TypeElementAttribute, 'a2', SecurityContext.NONE],
]),
],
null !, (check, view) => {
null, (check, view) => {
checkNodeInlineOrDynamic(check, view, 0, inlineDynamic, ['v1', 'v2']);
}));
@ -137,10 +126,10 @@ export function main() {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
[
elementDef(
NodeFlags.None, null !, null !, 0, 'div', null !,
0, NodeFlags.None, null, null, 0, 'div', null,
[
[BindingFlags.TypeElementClass, 'c1', null !],
[BindingFlags.TypeElementClass, 'c2', null !]
[BindingFlags.TypeElementClass, 'c1', null],
[BindingFlags.TypeElementClass, 'c2', null],
]),
],
(check, view) => {
@ -162,13 +151,13 @@ export function main() {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
[
elementDef(
NodeFlags.None, null !, null !, 0, 'div', null !,
0, NodeFlags.None, null, null, 0, 'div', null,
[
[BindingFlags.TypeElementStyle, 'width', 'px'],
[BindingFlags.TypeElementStyle, 'color', null !]
[BindingFlags.TypeElementStyle, 'color', null],
]),
],
null !, (check, view) => {
null, (check, view) => {
checkNodeInlineOrDynamic(check, view, 0, inlineDynamic, [10, 'red']);
}));
@ -200,7 +189,7 @@ export function main() {
const removeListenerSpy =
spyOn(HTMLElement.prototype, removeEventListener).and.callThrough();
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
NodeFlags.None, null !, null !, 0, 'button', null !, null !, [[null !, 'click']],
0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']],
handleEventSpy)]));
rootNodes[0].click();
@ -221,8 +210,8 @@ export function main() {
const addListenerSpy = spyOn(window, addEventListener);
const removeListenerSpy = spyOn(window, removeEventListener);
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
NodeFlags.None, null !, null !, 0, 'button', null !, null !,
[['window', 'windowClick']], handleEventSpy)]));
0, NodeFlags.None, null, null, 0, 'button', null, null, [['window', 'windowClick']],
handleEventSpy)]));
expect(addListenerSpy).toHaveBeenCalled();
expect(addListenerSpy.calls.mostRecent().args[0]).toBe('windowClick');
@ -244,7 +233,7 @@ export function main() {
const addListenerSpy = spyOn(document, addEventListener);
const removeListenerSpy = spyOn(document, removeEventListener);
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
NodeFlags.None, null !, null !, 0, 'button', null !, null !,
0, NodeFlags.None, null, null, 0, 'button', null, null,
[['document', 'documentClick']], handleEventSpy)]));
expect(addListenerSpy).toHaveBeenCalled();
@ -267,7 +256,7 @@ export function main() {
let preventDefaultSpy: jasmine.Spy = undefined !;
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
NodeFlags.None, null !, null !, 0, 'button', null !, null !, [[null !, 'click']],
0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']],
(view, eventName, event) => {
preventDefaultSpy = spyOn(event, 'preventDefault').and.callThrough();
return eventHandlerResult;
@ -294,7 +283,7 @@ export function main() {
const handleErrorSpy = spyOn(TestBed.get(ErrorHandler), 'handleError');
const addListenerSpy = spyOn(HTMLElement.prototype, addEventListener).and.callThrough();
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
NodeFlags.None, null !, null !, 0, 'button', null !, null !, [[null !, 'click']],
0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']],
() => { throw new Error('Test'); })]));
callMostRecentEventListenerHandler(addListenerSpy, 'SomeEvent');

View File

@ -6,31 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation} from '@angular/core';
import {ArgumentType, BindingFlags, NodeCheckFn, NodeDef, NodeFlags, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, moveEmbeddedView, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
import {inject} from '@angular/core/testing';
import {SecurityContext} from '@angular/core';
import {ArgumentType, BindingFlags, NodeCheckFn, NodeFlags, Services, ViewData, anchorDef, asElementData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, moveEmbeddedView, rootRenderNodes} from '@angular/core/src/view/index';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {createEmbeddedView, createRootView, isBrowser} from './helper';
import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedView} from './helper';
export function main() {
describe(`Embedded Views`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinitionFactory {
return () => viewDef(ViewFlags.None, nodes, update);
}
function createAndGetRootNodes(
viewDef: ViewDefinition, context: any = null): {rootNodes: any[], view: ViewData} {
const view = createRootView(viewDef, context);
const rootNodes = rootRenderNodes(view);
return {rootNodes, view};
}
it('should create embedded views with the right context', () => {
const parentContext = new Object();
@ -38,10 +21,10 @@ export function main() {
const {view: parentView} = createAndGetRootNodes(
compViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'div'),
elementDef(0, NodeFlags.None, null, null, 1, 'div'),
anchorDef(
NodeFlags.EmbeddedViews, null !, null !, 0, null !,
embeddedViewDef([elementDef(NodeFlags.None, null !, null !, 0, 'span')])),
NodeFlags.EmbeddedViews, null, null, 0, null,
compViewDefFactory([elementDef(0, NodeFlags.None, null, null, 0, 'span')])),
]),
parentContext);
@ -52,14 +35,13 @@ export function main() {
it('should attach and detach embedded views', () => {
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 2, 'div'),
anchorDef(NodeFlags.EmbeddedViews, null !, null !, 0, null !, embeddedViewDef([
elementDef(NodeFlags.None, null !, null !, 0, 'span', [['name', 'child0']])
elementDef(0, NodeFlags.None, null, null, 2, 'div'),
anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([
elementDef(0, NodeFlags.None, null, null, 0, 'span', [['name', 'child0']])
])),
anchorDef(
NodeFlags.None, null !, null !, 0, null !,
embeddedViewDef(
[elementDef(NodeFlags.None, null !, null !, 0, 'span', [['name', 'child1']])]))
anchorDef(NodeFlags.None, null, null, 0, null, compViewDefFactory([elementDef(
0, NodeFlags.None, null, null, 0, 'span',
[['name', 'child1']])]))
]));
const viewContainerData = asElementData(parentView, 1);
const rf = parentView.root.rendererFactory;
@ -86,14 +68,13 @@ export function main() {
it('should move embedded views', () => {
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 2, 'div'),
anchorDef(NodeFlags.EmbeddedViews, null !, null !, 0, null !, embeddedViewDef([
elementDef(NodeFlags.None, null !, null !, 0, 'span', [['name', 'child0']])
elementDef(0, NodeFlags.None, null, null, 2, 'div'),
anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([
elementDef(0, NodeFlags.None, null, null, 0, 'span', [['name', 'child0']])
])),
anchorDef(
NodeFlags.None, null !, null !, 0, null !,
embeddedViewDef(
[elementDef(NodeFlags.None, null !, null !, 0, 'span', [['name', 'child1']])]))
anchorDef(NodeFlags.None, null, null, 0, null, compViewDefFactory([elementDef(
0, NodeFlags.None, null, null, 0, 'span',
[['name', 'child1']])]))
]));
const viewContainerData = asElementData(parentView, 1);
@ -115,10 +96,10 @@ export function main() {
it('should include embedded views in root nodes', () => {
const {view: parentView} = createAndGetRootNodes(compViewDef([
anchorDef(NodeFlags.EmbeddedViews, null !, null !, 0, null !, embeddedViewDef([
elementDef(NodeFlags.None, null !, null !, 0, 'span', [['name', 'child0']])
anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([
elementDef(0, NodeFlags.None, null, null, 0, 'span', [['name', 'child0']])
])),
elementDef(NodeFlags.None, null !, null !, 0, 'span', [['name', 'after']])
elementDef(1, NodeFlags.None, null, null, 0, 'span', [['name', 'after']])
]));
const childView0 = createEmbeddedView(parentView, parentView.def.nodes[0]);
@ -138,12 +119,12 @@ export function main() {
});
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'div'),
elementDef(0, NodeFlags.None, null, null, 1, 'div'),
anchorDef(
NodeFlags.EmbeddedViews, null !, null !, 0, null !,
embeddedViewDef(
NodeFlags.EmbeddedViews, null, null, 0, null,
compViewDefFactory(
[elementDef(
NodeFlags.None, null !, null !, 0, 'span', null !,
0, NodeFlags.None, null, null, 0, 'span', null,
[[BindingFlags.TypeElementAttribute, 'name', SecurityContext.NONE]])],
update))
]));
@ -175,10 +156,10 @@ export function main() {
}
const {view: parentView} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'div'),
anchorDef(NodeFlags.EmbeddedViews, null !, null !, 0, null !, embeddedViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.OnDestroy, null !, 0, ChildProvider, [])
elementDef(0, NodeFlags.None, null, null, 1, 'div'),
anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(1, NodeFlags.OnDestroy, null, 0, ChildProvider, [])
]))
]));

View File

@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Injector, NgModuleRef, RootRenderer, Sanitizer} from '@angular/core';
import {ArgumentType, NodeCheckFn, NodeDef, RootData, Services, ViewData, ViewDefinition, initServicesIfNeeded} from '@angular/core/src/view/index';
import {Injector, NgModuleRef} from '@angular/core';
import {ArgumentType, NodeCheckFn, NodeDef, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewUpdateFn, initServicesIfNeeded, rootRenderNodes, viewDef} from '@angular/core/src/view/index';
import {TestBed} from '@angular/core/testing';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
@ -41,6 +41,39 @@ export function createEmbeddedView(parent: ViewData, anchorDef: NodeDef, context
return Services.createEmbeddedView(parent, anchorDef, anchorDef.element !.template !, context);
}
export function compViewDef(
nodes: NodeDef[], updateDirectives?: null | ViewUpdateFn, updateRenderer?: null | ViewUpdateFn,
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
const def = viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
def.nodes.forEach((node, index) => {
if (node.nodeIndex !== index) {
throw new Error('nodeIndex should be the same as the index of the node');
}
// This check should be removed when we start reordering nodes at runtime
if (node.checkIndex > -1 && node.checkIndex !== node.nodeIndex) {
throw new Error(
`nodeIndex and checkIndex should be the same, got ${node.nodeIndex} !== ${node.checkIndex}`);
}
});
return def;
}
export function compViewDefFactory(
nodes: NodeDef[], updateDirectives?: null | ViewUpdateFn, updateRenderer?: null | ViewUpdateFn,
viewFlags: ViewFlags = ViewFlags.None): ViewDefinitionFactory {
return () => compViewDef(nodes, updateDirectives, updateRenderer, viewFlags);
}
export function createAndGetRootNodes(
viewDef: ViewDefinition, ctx?: any): {rootNodes: any[], view: ViewData} {
const view = createRootView(viewDef, ctx);
const rootNodes = rootRenderNodes(view);
return {rootNodes, view};
}
let removeNodes: Node[];
beforeEach(() => { removeNodes = []; });

View File

@ -10,30 +10,21 @@ import {Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext,
import {DebugContext, NodeDef, NodeFlags, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, asProviderData, asTextData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, ngContentDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {createEmbeddedView, createRootView, isBrowser} from './helper';
import {compViewDef, compViewDefFactory, createEmbeddedView, createRootView, isBrowser} from './helper';
export function main() {
describe(`View NgContent`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinitionFactory {
return () => viewDef(ViewFlags.None, nodes, update);
}
function hostElDef(contentNodes: NodeDef[], viewNodes: NodeDef[]): NodeDef[] {
function hostElDef(
checkIndex: number, contentNodes: NodeDef[], viewNodes: NodeDef[]): NodeDef[] {
class AComp {}
const aCompViewDef = compViewDef(viewNodes);
return [
elementDef(
NodeFlags.None, null !, null !, 1 + contentNodes.length, 'acomp', null !, null !,
null !, null !, () => aCompViewDef),
directiveDef(NodeFlags.Component, null !, 0, AComp, []), ...contentNodes
checkIndex, NodeFlags.None, null, null, 1 + contentNodes.length, 'acomp', null, null,
null, null, () => aCompViewDef),
directiveDef(checkIndex + 1, NodeFlags.Component, null, 0, AComp, []), ...contentNodes
];
}
@ -46,15 +37,15 @@ export function main() {
it('should create ng-content nodes without parents', () => {
const {view, rootNodes} = createAndGetRootNodes(
compViewDef(hostElDef([textDef(0, ['a'])], [ngContentDef(null !, 0)])));
compViewDef(hostElDef(0, [textDef(2, 0, ['a'])], [ngContentDef(null, 0)])));
expect(getDOM().firstChild(rootNodes[0])).toBe(asTextData(view, 2).renderText);
});
it('should create views with multiple root ng-content nodes', () => {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(hostElDef(
[textDef(0, ['a']), textDef(1, ['b'])],
[ngContentDef(null !, 0), ngContentDef(null !, 1)])));
0, [textDef(2, 0, ['a']), textDef(3, 1, ['b'])],
[ngContentDef(null, 0), ngContentDef(null, 1)])));
expect(getDOM().childNodes(rootNodes[0])[0]).toBe(asTextData(view, 2).renderText);
expect(getDOM().childNodes(rootNodes[0])[1]).toBe(asTextData(view, 3).renderText);
@ -62,8 +53,8 @@ export function main() {
it('should create ng-content nodes with parents', () => {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(hostElDef(
[textDef(0, ['a'])],
[elementDef(NodeFlags.None, null !, null !, 1, 'div'), ngContentDef(null !, 0)])));
0, [textDef(2, 0, ['a'])],
[elementDef(0, NodeFlags.None, null, null, 1, 'div'), ngContentDef(null, 0)])));
expect(getDOM().firstChild(getDOM().firstChild(rootNodes[0])))
.toBe(asTextData(view, 2).renderText);
@ -71,8 +62,8 @@ export function main() {
it('should reproject ng-content nodes', () => {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
hostElDef([textDef(0, ['a'])], hostElDef([ngContentDef(0, 0)], [
elementDef(NodeFlags.None, null !, null !, 1, 'span'), ngContentDef(null !, 0)
hostElDef(0, [textDef(2, 0, ['a'])], hostElDef(0, [ngContentDef(0, 0)], [
elementDef(0, NodeFlags.None, null, null, 1, 'span'), ngContentDef(null, 0)
]))));
expect(getDOM().firstChild(getDOM().firstChild(getDOM().firstChild(rootNodes[0]))))
.toBe(asTextData(view, 2).renderText);
@ -88,18 +79,18 @@ export function main() {
const {view, rootNodes} =
createAndGetRootNodes(
compViewDef(
hostElDef(
hostElDef(0,
[
anchorDef(
NodeFlags.EmbeddedViews, null !, 0, 1, null !,
embeddedViewDef([textDef(null !, ['a'])])),
directiveDef(
NodeFlags.None, null !, 0, CreateViewService,
[TemplateRef, ViewContainerRef])
NodeFlags.EmbeddedViews, null, 0, 1, null,
compViewDefFactory([textDef(0, null, ['a'])])),
directiveDef(3,
NodeFlags.None, null, 0, CreateViewService,
[TemplateRef, ViewContainerRef]),
],
[
elementDef(NodeFlags.None, null !, null !, 1, 'div'),
ngContentDef(null !, 0)
elementDef(0, NodeFlags.None, null, null, 1, 'div'),
ngContentDef(null, 0),
])));
const anchor = asElementData(view, 2);
@ -111,14 +102,15 @@ export function main() {
});
it('should include projected nodes when attaching / detaching embedded views', () => {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(hostElDef([textDef(0, ['a'])], [
elementDef(NodeFlags.None, null !, null !, 1, 'div'),
anchorDef(NodeFlags.EmbeddedViews, null !, 0, 0, null !, embeddedViewDef([
ngContentDef(null !, 0),
// The anchor would be added by the compiler after the ngContent
anchorDef(NodeFlags.None, null !, null !, 0),
])),
])));
const {view, rootNodes} =
createAndGetRootNodes(compViewDef(hostElDef(0, [textDef(2, 0, ['a'])], [
elementDef(0, NodeFlags.None, null, null, 1, 'div'),
anchorDef(NodeFlags.EmbeddedViews, null, 0, 0, null, compViewDefFactory([
ngContentDef(null, 0),
// The anchor would be added by the compiler after the ngContent
anchorDef(NodeFlags.None, null, null, 0),
])),
])));
const componentView = asElementData(view, 0).componentView;
const rf = componentView.root.rendererFactory;
@ -139,7 +131,7 @@ export function main() {
it('should use root projectable nodes', () => {
const projectableNodes = [[document.createTextNode('a')], [document.createTextNode('b')]];
const view = createRootView(
compViewDef(hostElDef([], [ngContentDef(null !, 0), ngContentDef(null !, 1)])), {},
compViewDef(hostElDef(0, [], [ngContentDef(null, 0), ngContentDef(null, 1)])), {},
projectableNodes);
const rootNodes = rootRenderNodes(view);

View File

@ -6,31 +6,16 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectorRef, DoCheck, ElementRef, ErrorHandler, EventEmitter, Injector, OnChanges, OnDestroy, OnInit, RenderComponentType, Renderer, Renderer2, RootRenderer, Sanitizer, SecurityContext, SimpleChange, TemplateRef, ViewContainerRef, ViewEncapsulation, WrappedValue, getDebugNode} from '@angular/core';
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectorRef, DoCheck, ElementRef, ErrorHandler, EventEmitter, Injector, OnChanges, OnDestroy, OnInit, Renderer, Renderer2, SimpleChange, TemplateRef, ViewContainerRef,} from '@angular/core';
import {getDebugContext} from '@angular/core/src/errors';
import {ArgumentType, BindingFlags, DebugContext, DepFlags, NodeDef, NodeFlags, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, asProviderData, directiveDef, elementDef, providerDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
import {TestBed, inject, withModule} from '@angular/core/testing';
import {ArgumentType, DepFlags, NodeFlags, Services, anchorDef, asElementData, directiveDef, elementDef, providerDef, textDef} from '@angular/core/src/view/index';
import {TestBed, withModule} from '@angular/core/testing';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, isBrowser} from './helper';
import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetRootNodes, compViewDef, compViewDefFactory} from './helper';
export function main() {
describe(`View Providers`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinitionFactory {
return () => viewDef(ViewFlags.None, nodes, update);
}
function createAndGetRootNodes(viewDef: ViewDefinition): {rootNodes: any[], view: ViewData} {
const view = createRootView(viewDef, {});
const rootNodes = rootRenderNodes(view);
return {rootNodes, view};
}
describe('create', () => {
let instance: SomeService;
@ -43,8 +28,8 @@ export function main() {
it('should create providers eagerly', () => {
createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.None, null !, 0, SomeService, [])
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(1, NodeFlags.None, null, 0, SomeService, [])
]));
expect(instance instanceof SomeService).toBe(true);
@ -57,11 +42,11 @@ export function main() {
}
createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 2, 'span'),
elementDef(0, NodeFlags.None, null, null, 2, 'span'),
providerDef(
NodeFlags.TypeClassProvider | NodeFlags.LazyProvider, null !, LazyService,
LazyService, []),
directiveDef(NodeFlags.None, null !, 0, SomeService, [Injector])
NodeFlags.TypeClassProvider | NodeFlags.LazyProvider, null, LazyService, LazyService,
[]),
directiveDef(2, NodeFlags.None, null, 0, SomeService, [Injector])
]));
expect(lazy).toBeUndefined();
@ -71,9 +56,9 @@ export function main() {
it('should create value providers', () => {
createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 2, 'span'),
providerDef(NodeFlags.TypeValueProvider, null !, 'someToken', 'someValue', []),
directiveDef(NodeFlags.None, null !, 0, SomeService, ['someToken']),
elementDef(0, NodeFlags.None, null, null, 2, 'span'),
providerDef(NodeFlags.TypeValueProvider, null, 'someToken', 'someValue', []),
directiveDef(2, NodeFlags.None, null, 0, SomeService, ['someToken']),
]));
expect(instance.dep).toBe('someValue');
@ -83,9 +68,9 @@ export function main() {
function someFactory() { return 'someValue'; }
createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 2, 'span'),
providerDef(NodeFlags.TypeFactoryProvider, null !, 'someToken', someFactory, []),
directiveDef(NodeFlags.None, null !, 0, SomeService, ['someToken']),
elementDef(0, NodeFlags.None, null, null, 2, 'span'),
providerDef(NodeFlags.TypeFactoryProvider, null, 'someToken', someFactory, []),
directiveDef(2, NodeFlags.None, null, 0, SomeService, ['someToken']),
]));
expect(instance.dep).toBe('someValue');
@ -93,12 +78,11 @@ export function main() {
it('should create useExisting providers', () => {
createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 3, 'span'),
providerDef(NodeFlags.TypeValueProvider, null !, 'someExistingToken', 'someValue', []),
elementDef(0, NodeFlags.None, null, null, 3, 'span'),
providerDef(NodeFlags.TypeValueProvider, null, 'someExistingToken', 'someValue', []),
providerDef(
NodeFlags.TypeUseExistingProvider, null !, 'someToken', null !,
['someExistingToken']),
directiveDef(NodeFlags.None, null !, 0, SomeService, ['someToken']),
NodeFlags.TypeUseExistingProvider, null, 'someToken', null, ['someExistingToken']),
directiveDef(3, NodeFlags.None, null, 0, SomeService, ['someToken']),
]));
expect(instance.dep).toBe('someValue');
@ -114,9 +98,9 @@ export function main() {
createRootView(
compViewDef([
elementDef(
NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !,
() => compViewDef([textDef(null !, ['a'])])),
directiveDef(NodeFlags.Component, null !, 0, SomeService, [])
0, NodeFlags.None, null, null, 1, 'div', null, null, null, null,
() => compViewDef([textDef(0, null, ['a'])])),
directiveDef(1, NodeFlags.Component, null, 0, SomeService, [])
]),
TestBed.get(Injector), [], getDOM().createElement('div'));
} catch (e) {
@ -134,9 +118,9 @@ export function main() {
it('should inject deps from the same element', () => {
createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 2, 'span'),
directiveDef(NodeFlags.None, null !, 0, Dep, []),
directiveDef(NodeFlags.None, null !, 0, SomeService, [Dep])
elementDef(0, NodeFlags.None, null, null, 2, 'span'),
directiveDef(1, NodeFlags.None, null, 0, Dep, []),
directiveDef(2, NodeFlags.None, null, 0, SomeService, [Dep])
]));
expect(instance.dep instanceof Dep).toBeTruthy();
@ -144,34 +128,38 @@ export function main() {
it('should inject deps from a parent element', () => {
createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 3, 'span'),
directiveDef(NodeFlags.None, null !, 0, Dep, []),
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.None, null !, 0, SomeService, [Dep])
elementDef(0, NodeFlags.None, null, null, 3, 'span'),
directiveDef(1, NodeFlags.None, null, 0, Dep, []),
elementDef(2, NodeFlags.None, null, null, 1, 'span'),
directiveDef(3, NodeFlags.None, null, 0, SomeService, [Dep])
]));
expect(instance.dep instanceof Dep).toBeTruthy();
});
it('should not inject deps from sibling root elements', () => {
const nodes = [
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.None, null !, 0, Dep, []),
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.None, null !, 0, SomeService, [Dep])
const rootElNodes = [
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(1, NodeFlags.None, null, 0, Dep, []),
elementDef(2, NodeFlags.None, null, null, 1, 'span'),
directiveDef(3, NodeFlags.None, null, 0, SomeService, [Dep]),
];
// root elements
expect(() => createAndGetRootNodes(compViewDef(nodes)))
expect(() => createAndGetRootNodes(compViewDef(rootElNodes)))
.toThrowError(
'StaticInjectorError[Dep]: \n' +
' StaticInjectorError[Dep]: \n' +
' NullInjectorError: No provider for Dep!');
// non root elements
expect(
() => createAndGetRootNodes(compViewDef(
[elementDef(NodeFlags.None, null !, null !, 4, 'span')].concat(nodes))))
const nonRootElNodes = [
elementDef(0, NodeFlags.None, null, null, 4, 'span'),
elementDef(1, NodeFlags.None, null, null, 1, 'span'),
directiveDef(2, NodeFlags.None, null, 0, Dep, []),
elementDef(3, NodeFlags.None, null, null, 1, 'span'),
directiveDef(4, NodeFlags.None, null, 0, SomeService, [Dep]),
];
expect(() => createAndGetRootNodes(compViewDef(nonRootElNodes)))
.toThrowError(
'StaticInjectorError[Dep]: \n' +
' StaticInjectorError[Dep]: \n' +
@ -181,12 +169,12 @@ export function main() {
it('should inject from a parent element in a parent view', () => {
createAndGetRootNodes(compViewDef([
elementDef(
NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !,
0, NodeFlags.None, null, null, 1, 'div', null, null, null, null,
() => compViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.None, null !, 0, SomeService, [Dep])
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(1, NodeFlags.None, null, 0, SomeService, [Dep])
])),
directiveDef(NodeFlags.Component, null !, 0, Dep, []),
directiveDef(1, NodeFlags.Component, null, 0, Dep, []),
]));
expect(instance.dep instanceof Dep).toBeTruthy();
@ -194,8 +182,8 @@ export function main() {
it('should throw for missing dependencies', () => {
expect(() => createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.None, null !, 0, SomeService, ['nonExistingDep'])
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(1, NodeFlags.None, null, 0, SomeService, ['nonExistingDep'])
])))
.toThrowError(
'StaticInjectorError[nonExistingDep]: \n' +
@ -205,21 +193,22 @@ export function main() {
it('should use null for optional missing dependencies', () => {
createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(
NodeFlags.None, null !, 0, SomeService, [[DepFlags.Optional, 'nonExistingDep']])
1, NodeFlags.None, null, 0, SomeService,
[[DepFlags.Optional, 'nonExistingDep']])
]));
expect(instance.dep).toBe(null);
});
it('should skip the current element when using SkipSelf', () => {
createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 4, 'span'),
providerDef(NodeFlags.TypeValueProvider, null !, 'someToken', 'someParentValue', []),
elementDef(NodeFlags.None, null !, null !, 2, 'span'),
providerDef(NodeFlags.TypeValueProvider, null !, 'someToken', 'someValue', []),
elementDef(0, NodeFlags.None, null, null, 4, 'span'),
providerDef(NodeFlags.TypeValueProvider, null, 'someToken', 'someParentValue', []),
elementDef(2, NodeFlags.None, null, null, 2, 'span'),
providerDef(NodeFlags.TypeValueProvider, null, 'someToken', 'someValue', []),
directiveDef(
NodeFlags.None, null !, 0, SomeService, [[DepFlags.SkipSelf, 'someToken']])
4, NodeFlags.None, null, 0, SomeService, [[DepFlags.SkipSelf, 'someToken']])
]));
expect(instance.dep).toBe('someParentValue');
});
@ -227,8 +216,8 @@ export function main() {
it('should ask the root injector',
withModule({providers: [{provide: 'rootDep', useValue: 'rootValue'}]}, () => {
createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.None, null !, 0, SomeService, ['rootDep'])
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(1, NodeFlags.None, null, 0, SomeService, ['rootDep'])
]));
expect(instance.dep).toBe('rootValue');
@ -237,8 +226,8 @@ export function main() {
describe('builtin tokens', () => {
it('should inject ViewContainerRef', () => {
createAndGetRootNodes(compViewDef([
anchorDef(NodeFlags.EmbeddedViews, null !, null !, 1),
directiveDef(NodeFlags.None, null !, 0, SomeService, [ViewContainerRef])
anchorDef(NodeFlags.EmbeddedViews, null, null, 1),
directiveDef(1, NodeFlags.None, null, 0, SomeService, [ViewContainerRef]),
]));
expect(instance.dep.createEmbeddedView).toBeTruthy();
@ -246,10 +235,9 @@ export function main() {
it('should inject TemplateRef', () => {
createAndGetRootNodes(compViewDef([
anchorDef(
NodeFlags.None, null !, null !, 1, null !,
embeddedViewDef([anchorDef(NodeFlags.None, null !, null !, 0)])),
directiveDef(NodeFlags.None, null !, 0, SomeService, [TemplateRef])
anchorDef(NodeFlags.None, null, null, 1, null, compViewDefFactory([anchorDef(
NodeFlags.None, null, null, 0)])),
directiveDef(1, NodeFlags.None, null, 0, SomeService, [TemplateRef]),
]));
expect(instance.dep.createEmbeddedView).toBeTruthy();
@ -257,8 +245,8 @@ export function main() {
it('should inject ElementRef', () => {
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.None, null !, 0, SomeService, [ElementRef])
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(1, NodeFlags.None, null, 0, SomeService, [ElementRef]),
]));
expect(instance.dep.nativeElement).toBe(asElementData(view, 0).renderElement);
@ -266,8 +254,8 @@ export function main() {
it('should inject Injector', () => {
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.None, null !, 0, SomeService, [Injector])
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(1, NodeFlags.None, null, 0, SomeService, [Injector]),
]));
expect(instance.dep.get(SomeService)).toBe(instance);
@ -275,8 +263,8 @@ export function main() {
it('should inject ChangeDetectorRef for non component providers', () => {
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.None, null !, 0, SomeService, [ChangeDetectorRef])
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(1, NodeFlags.None, null, 0, SomeService, [ChangeDetectorRef])
]));
expect(instance.dep._view).toBe(view);
@ -285,11 +273,11 @@ export function main() {
it('should inject ChangeDetectorRef for component providers', () => {
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(
NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !,
0, NodeFlags.None, null, null, 1, 'div', null, null, null, null,
() => compViewDef([
elementDef(NodeFlags.None, null !, null !, 0, 'span'),
elementDef(0, NodeFlags.None, null, null, 0, 'span'),
])),
directiveDef(NodeFlags.Component, null !, 0, SomeService, [ChangeDetectorRef]),
directiveDef(1, NodeFlags.Component, null, 0, SomeService, [ChangeDetectorRef]),
]));
const compView = asElementData(view, 0).componentView;
@ -299,9 +287,9 @@ export function main() {
it('should inject RendererV1', () => {
createAndGetRootNodes(compViewDef([
elementDef(
NodeFlags.None, null !, null !, 1, 'span', null !, null !, null !, null !,
() => compViewDef([anchorDef(NodeFlags.None, null !, null !, 0)])),
directiveDef(NodeFlags.Component, null !, 0, SomeService, [Renderer])
0, NodeFlags.None, null, null, 1, 'span', null, null, null, null,
() => compViewDef([anchorDef(NodeFlags.None, null, null, 0)])),
directiveDef(1, NodeFlags.Component, null, 0, SomeService, [Renderer])
]));
expect(instance.dep.createElement).toBeTruthy();
@ -310,9 +298,9 @@ export function main() {
it('should inject Renderer2', () => {
createAndGetRootNodes(compViewDef([
elementDef(
NodeFlags.None, null !, null !, 1, 'span', null !, null !, null !, null !,
() => compViewDef([anchorDef(NodeFlags.None, null !, null !, 0)])),
directiveDef(NodeFlags.Component, null !, 0, SomeService, [Renderer2])
0, NodeFlags.None, null, null, 1, 'span', null, null, null, null,
() => compViewDef([anchorDef(NodeFlags.None, null, null, 0)])),
directiveDef(1, NodeFlags.Component, null, 0, SomeService, [Renderer2])
]));
expect(instance.dep.createElement).toBeTruthy();
@ -337,9 +325,9 @@ export function main() {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
[
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(
NodeFlags.None, null !, 0, SomeService, [], {a: [0, 'a'], b: [1, 'b']})
1, NodeFlags.None, null, 0, SomeService, [], {a: [0, 'a'], b: [1, 'b']})
],
(check, view) => {
checkNodeInlineOrDynamic(check, view, 1, inlineDynamic, ['v1', 'v2']);
@ -373,13 +361,11 @@ export function main() {
}
const handleEvent = jasmine.createSpy('handleEvent');
const subscribe = spyOn(emitter, 'subscribe').and.callThrough();
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(
NodeFlags.None, null !, null !, 1, 'span', null !, null !, null !, handleEvent),
elementDef(0, NodeFlags.None, null, null, 1, 'span', null, null, null, handleEvent),
directiveDef(
NodeFlags.None, null !, 0, SomeService, [], null !, {emitter: 'someEventName'})
1, NodeFlags.None, null, 0, SomeService, [], null, {emitter: 'someEventName'})
]));
emitter.emit('someEventInstance');
@ -399,10 +385,10 @@ export function main() {
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(
NodeFlags.None, null !, null !, 1, 'span', null !, null !, null !,
0, NodeFlags.None, null, null, 1, 'span', null, null, null,
() => { throw new Error('Test'); }),
directiveDef(
NodeFlags.None, null !, 0, SomeService, [], null !, {emitter: 'someEventName'})
1, NodeFlags.None, null, 0, SomeService, [], null, {emitter: 'someEventName'})
]));
emitter.emit('someEventInstance');
@ -440,10 +426,10 @@ export function main() {
NodeFlags.AfterViewChecked | NodeFlags.OnDestroy;
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
[
elementDef(NodeFlags.None, null !, null !, 3, 'span'),
directiveDef(allFlags, null !, 0, SomeService, [], {a: [0, 'a']}),
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(allFlags, null !, 0, SomeService, [], {a: [0, 'a']})
elementDef(0, NodeFlags.None, null, null, 3, 'span'),
directiveDef(1, allFlags, null, 0, SomeService, [], {a: [0, 'a']}),
elementDef(2, NodeFlags.None, null, null, 1, 'span'),
directiveDef(3, allFlags, null, 0, SomeService, [], {a: [0, 'a']})
],
(check, view) => {
check(view, 1, ArgumentType.Inline, 'someValue');
@ -499,9 +485,9 @@ export function main() {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
[
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(
NodeFlags.OnChanges, null !, 0, SomeService, [], {a: [0, 'nonMinifiedA']})
1, NodeFlags.OnChanges, null, 0, SomeService, [], {a: [0, 'nonMinifiedA']})
],
(check, view) => { check(view, 1, ArgumentType.Inline, currValue); }));
@ -520,8 +506,8 @@ export function main() {
}
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.AfterContentChecked, null !, 0, SomeService, [], {a: [0, 'a']}),
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(1, NodeFlags.AfterContentChecked, null, 0, SomeService, [], {a: [0, 'a']}),
]));
let err: any;
@ -543,8 +529,8 @@ export function main() {
}
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.OnDestroy, null !, 0, SomeService, [], {a: [0, 'a']}),
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(1, NodeFlags.OnDestroy, null, 0, SomeService, [], {a: [0, 'a']}),
]));
let err: any;

View File

@ -7,23 +7,12 @@
*/
import {PipeTransform} from '@angular/core';
import {NodeDef, NodeFlags, Services, ViewData, ViewDefinition, ViewFlags, ViewUpdateFn, asProviderData, directiveDef, elementDef, nodeValue, pipeDef, pureArrayDef, pureObjectDef, purePipeDef, rootRenderNodes, viewDef} from '@angular/core/src/view/index';
import {NodeFlags, Services, asProviderData, directiveDef, elementDef, nodeValue, pipeDef, pureArrayDef, pureObjectDef, purePipeDef} from '@angular/core/src/view/index';
import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView} from './helper';
import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRootNodes} from './helper';
export function main() {
describe(`View Pure Expressions`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function createAndGetRootNodes(viewDef: ViewDefinition): {rootNodes: any[], view: ViewData} {
const view = createRootView(viewDef);
const rootNodes = rootRenderNodes(view);
return {rootNodes, view};
}
class Service {
data: any;
@ -37,9 +26,9 @@ export function main() {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
[
elementDef(NodeFlags.None, null !, null !, 2, 'span'),
pureArrayDef(2),
directiveDef(NodeFlags.None, null !, 0, Service, [], {data: [0, 'data']}),
elementDef(0, NodeFlags.None, null, null, 2, 'span'),
pureArrayDef(1, 2),
directiveDef(2, NodeFlags.None, null, 0, Service, [], {data: [0, 'data']}),
],
(check, view) => {
const pureValue = checkNodeInlineOrDynamic(check, view, 1, inlineDynamic, values);
@ -75,8 +64,9 @@ export function main() {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
[
elementDef(NodeFlags.None, null !, null !, 2, 'span'), pureObjectDef({a: 0, b: 1}),
directiveDef(NodeFlags.None, null !, 0, Service, [], {data: [0, 'data']})
elementDef(0, NodeFlags.None, null, null, 2, 'span'),
pureObjectDef(1, {a: 0, b: 1}),
directiveDef(2, NodeFlags.None, null, 0, Service, [], {data: [0, 'data']})
],
(check, view) => {
const pureValue = checkNodeInlineOrDynamic(check, view, 1, inlineDynamic, values);
@ -115,10 +105,10 @@ export function main() {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
[
elementDef(NodeFlags.None, null !, null !, 3, 'span'),
elementDef(0, NodeFlags.None, null !, null !, 3, 'span'),
pipeDef(NodeFlags.None, SomePipe, []),
purePipeDef(2),
directiveDef(NodeFlags.None, null !, 0, Service, [], {data: [0, 'data']}),
purePipeDef(2, 2),
directiveDef(3, NodeFlags.None, null, 0, Service, [], {data: [0, 'data']}),
],
(check, view) => {
const pureValue = checkNodeInlineOrDynamic(

View File

@ -6,32 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ElementRef, Injector, QueryList, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, TemplateRef, ViewContainerRef, ViewEncapsulation, getDebugNode} from '@angular/core';
import {ElementRef, QueryList, TemplateRef, ViewContainerRef} from '@angular/core';
import {getDebugContext} from '@angular/core/src/errors';
import {BindingFlags, DebugContext, NodeDef, NodeFlags, QueryBindingType, QueryValueType, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, asProviderData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, queryDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
import {inject} from '@angular/core/testing';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {NodeDef, NodeFlags, QueryBindingType, QueryValueType, Services, anchorDef, asElementData, asProviderData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, queryDef} from '@angular/core/src/view/index';
import {createEmbeddedView, createRootView} from './helper';
import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedView} from './helper';
export function main() {
describe(`Query Views`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinitionFactory {
return () => viewDef(ViewFlags.None, nodes, update);
}
function createAndGetRootNodes(
viewDef: ViewDefinition, context: any = null): {rootNodes: any[], view: ViewData} {
const view = createRootView(viewDef, context);
const rootNodes = rootRenderNodes(view);
return {rootNodes, view};
}
const someQueryId = 1;
@ -41,43 +23,50 @@ export function main() {
a: QueryList<AService>;
}
function contentQueryProviders() {
function contentQueryProviders(checkIndex: number) {
return [
directiveDef(NodeFlags.None, null !, 1, QueryService, []),
directiveDef(checkIndex, NodeFlags.None, null, 1, QueryService, []),
queryDef(
NodeFlags.TypeContentQuery | NodeFlags.DynamicQuery, someQueryId,
{'a': QueryBindingType.All})
];
}
function compViewQueryProviders(extraChildCount: number, nodes: NodeDef[]) {
const cQPLength = contentQueryProviders(0).length;
// nodes first checkIndex should be 1 (to account for the `queryDef`
function compViewQueryProviders(checkIndex: number, extraChildCount: number, nodes: NodeDef[]) {
return [
elementDef(
NodeFlags.None, null !, null !, 1 + extraChildCount, 'div', null !, null !, null !,
null !, () => compViewDef([
queryDef(
NodeFlags.TypeViewQuery | NodeFlags.DynamicQuery, someQueryId,
{'a': QueryBindingType.All}),
...nodes
])),
directiveDef(NodeFlags.Component, null !, 0, QueryService, [], null !, null !, ),
checkIndex, NodeFlags.None, null, null, 1 + extraChildCount, 'div', null, null, null,
null, () => compViewDef([
queryDef(
NodeFlags.TypeViewQuery | NodeFlags.DynamicQuery, someQueryId,
{'a': QueryBindingType.All}),
...nodes
])),
directiveDef(
checkIndex + 1, NodeFlags.Component, null !, 0, QueryService, [], null !, null !, ),
];
}
function aServiceProvider() {
const cVQLength = compViewQueryProviders(0, 0, []).length;
function aServiceProvider(checkIndex: number) {
return directiveDef(
NodeFlags.None, [[someQueryId, QueryValueType.Provider]], 0, AService, []);
checkIndex, NodeFlags.None, [[someQueryId, QueryValueType.Provider]], 0, AService, []);
}
describe('content queries', () => {
it('should query providers on the same element and child elements', () => {
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 5, 'div'),
...contentQueryProviders(),
aServiceProvider(),
elementDef(NodeFlags.None, null !, null !, 1, 'div'),
aServiceProvider(),
elementDef(0, NodeFlags.None, null, null, 5, 'div'),
...contentQueryProviders(1),
aServiceProvider(1 + cQPLength),
elementDef(2 + cQPLength, NodeFlags.None, null, null, 1, 'div'),
aServiceProvider(3 + cQPLength),
]));
const qs: QueryService = asProviderData(view, 1).instance;
@ -92,13 +81,14 @@ export function main() {
});
it('should not query providers on sibling or parent elements', () => {
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 6, 'div'),
aServiceProvider(),
elementDef(NodeFlags.None, null !, null !, 2, 'div'),
...contentQueryProviders(),
elementDef(NodeFlags.None, null !, null !, 1, 'div'),
aServiceProvider(),
elementDef(0, NodeFlags.None, null, null, 6, 'div'),
aServiceProvider(1),
elementDef(2, NodeFlags.None, null, null, 2, 'div'),
...contentQueryProviders(3),
elementDef(3 + cQPLength, NodeFlags.None, null, null, 1, 'div'),
aServiceProvider(4 + cQPLength),
]));
Services.checkAndUpdateView(view);
@ -112,10 +102,10 @@ export function main() {
it('should query providers in the view', () => {
const {view} = createAndGetRootNodes(compViewDef([
...compViewQueryProviders(
0,
0, 0,
[
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
aServiceProvider(),
elementDef(1, NodeFlags.None, null, null, 1, 'span'),
aServiceProvider(2),
]),
]));
@ -129,12 +119,8 @@ export function main() {
it('should not query providers on the host element', () => {
const {view} = createAndGetRootNodes(compViewDef([
...compViewQueryProviders(
1,
[
elementDef(NodeFlags.None, null !, null !, 0, 'span'),
]),
aServiceProvider(),
...compViewQueryProviders(0, 1, [elementDef(1, NodeFlags.None, null, null, 0, 'span')]),
aServiceProvider(cVQLength),
]));
Services.checkAndUpdateView(view);
@ -146,13 +132,13 @@ export function main() {
describe('embedded views', () => {
it('should query providers in embedded views', () => {
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 5, 'div'),
...contentQueryProviders(),
anchorDef(NodeFlags.EmbeddedViews, null !, null !, 2, null !, embeddedViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'div'),
aServiceProvider(),
elementDef(0, NodeFlags.None, null, null, 5, 'div'),
...contentQueryProviders(1),
anchorDef(NodeFlags.EmbeddedViews, null, null, 2, null, compViewDefFactory([
elementDef(0, NodeFlags.None, null, null, 1, 'div'),
aServiceProvider(1),
])),
...contentQueryProviders(),
...contentQueryProviders(2 + cQPLength),
]));
const childView = createEmbeddedView(view, view.def.nodes[3]);
@ -172,15 +158,15 @@ export function main() {
it('should query providers in embedded views only at the template declaration', () => {
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 3, 'div'),
...contentQueryProviders(),
anchorDef(NodeFlags.EmbeddedViews, null !, null !, 0, null !, embeddedViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'div'),
aServiceProvider(),
elementDef(0, NodeFlags.None, null, null, 3, 'div'),
...contentQueryProviders(1),
anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([
elementDef(0, NodeFlags.None, null, null, 1, 'div'),
aServiceProvider(1),
])),
elementDef(NodeFlags.None, null !, null !, 3, 'div'),
...contentQueryProviders(),
anchorDef(NodeFlags.EmbeddedViews, null !, null !, 0),
elementDef(2 + cQPLength, NodeFlags.None, null, null, 3, 'div'),
...contentQueryProviders(3 + cQPLength),
anchorDef(NodeFlags.EmbeddedViews, null, null, 0),
]));
const childView = createEmbeddedView(view, view.def.nodes[3]);
@ -201,11 +187,11 @@ export function main() {
it('should update content queries if embedded views are added or removed', () => {
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 3, 'div'),
...contentQueryProviders(),
anchorDef(NodeFlags.EmbeddedViews, null !, null !, 0, null !, embeddedViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'div'),
aServiceProvider(),
elementDef(0, NodeFlags.None, null, null, 3, 'div'),
...contentQueryProviders(1),
anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([
elementDef(0, NodeFlags.None, null, null, 1, 'div'),
aServiceProvider(1),
])),
]));
@ -230,11 +216,11 @@ export function main() {
it('should update view queries if embedded views are added or removed', () => {
const {view} = createAndGetRootNodes(compViewDef([
...compViewQueryProviders(
0,
0, 0,
[
anchorDef(NodeFlags.EmbeddedViews, null !, null !, 0, null !, embeddedViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'div'),
aServiceProvider(),
anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([
elementDef(0, NodeFlags.None, null, null, 1, 'div'),
aServiceProvider(1),
])),
]),
]));
@ -265,13 +251,13 @@ export function main() {
}
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 4, 'div'),
directiveDef(NodeFlags.None, null !, 1, QueryService, []),
elementDef(0, NodeFlags.None, null, null, 4, 'div'),
directiveDef(1, NodeFlags.None, null, 1, QueryService, []),
queryDef(
NodeFlags.TypeContentQuery | NodeFlags.DynamicQuery, someQueryId,
{'a': QueryBindingType.All}),
aServiceProvider(),
aServiceProvider(),
aServiceProvider(3),
aServiceProvider(4),
]));
Services.checkAndUpdateView(view);
@ -290,13 +276,13 @@ export function main() {
}
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 4, 'div'),
directiveDef(NodeFlags.None, null !, 1, QueryService, []),
elementDef(0, NodeFlags.None, null, null, 4, 'div'),
directiveDef(1, NodeFlags.None, null, 1, QueryService, []),
queryDef(
NodeFlags.TypeContentQuery | NodeFlags.DynamicQuery, someQueryId,
{'a': QueryBindingType.First}),
aServiceProvider(),
aServiceProvider(),
aServiceProvider(3),
aServiceProvider(4),
]));
Services.checkAndUpdateView(view);
@ -313,8 +299,8 @@ export function main() {
}
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, [[someQueryId, QueryValueType.ElementRef]], null !, 2, 'div'),
directiveDef(NodeFlags.None, null !, 1, QueryService, []),
elementDef(0, NodeFlags.None, [[someQueryId, QueryValueType.ElementRef]], null, 2, 'div'),
directiveDef(1, NodeFlags.None, null, 1, QueryService, []),
queryDef(
NodeFlags.TypeContentQuery | NodeFlags.DynamicQuery, someQueryId,
{'a': QueryBindingType.First}),
@ -333,9 +319,9 @@ export function main() {
const {view} = createAndGetRootNodes(compViewDef([
anchorDef(
NodeFlags.None, [[someQueryId, QueryValueType.TemplateRef]], null !, 2, null !,
embeddedViewDef([anchorDef(NodeFlags.None, null !, null !, 0)])),
directiveDef(NodeFlags.None, null !, 1, QueryService, []),
NodeFlags.None, [[someQueryId, QueryValueType.TemplateRef]], null, 2, null,
compViewDefFactory([anchorDef(NodeFlags.None, null, null, 0)])),
directiveDef(1, NodeFlags.None, null, 1, QueryService, []),
queryDef(
NodeFlags.TypeContentQuery | NodeFlags.DynamicQuery, someQueryId,
{'a': QueryBindingType.First}),
@ -354,8 +340,8 @@ export function main() {
const {view} = createAndGetRootNodes(compViewDef([
anchorDef(
NodeFlags.EmbeddedViews, [[someQueryId, QueryValueType.ViewContainerRef]], null !, 2),
directiveDef(NodeFlags.None, null !, 1, QueryService, []),
NodeFlags.EmbeddedViews, [[someQueryId, QueryValueType.ViewContainerRef]], null, 2),
directiveDef(1, NodeFlags.None, null, 1, QueryService, []),
queryDef(
NodeFlags.TypeContentQuery | NodeFlags.DynamicQuery, someQueryId,
{'a': QueryBindingType.First}),
@ -375,12 +361,12 @@ export function main() {
}
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 3, 'div'),
directiveDef(NodeFlags.None, null !, 1, QueryService, []),
elementDef(0, NodeFlags.None, null, null, 3, 'div'),
directiveDef(1, NodeFlags.None, null, 1, QueryService, []),
queryDef(
NodeFlags.TypeContentQuery | NodeFlags.DynamicQuery, someQueryId,
{'a': QueryBindingType.All}),
aServiceProvider(),
aServiceProvider(3),
]));

View File

@ -6,27 +6,12 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation, getDebugNode} from '@angular/core';
import {DebugContext, NodeDef, NodeFlags, QueryValueType, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, asProviderData, asTextData, directiveDef, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
import {inject} from '@angular/core/testing';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {DebugContext, NodeFlags, QueryValueType, Services, asElementData, asTextData, directiveDef, elementDef, textDef} from '@angular/core/src/view/index';
import {createRootView, isBrowser} from './helper';
import {compViewDef, createAndGetRootNodes} from './helper';
export function main() {
describe('View Services', () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function createAndGetRootNodes(
viewDef: ViewDefinition, context: any = null): {rootNodes: any[], view: ViewData} {
const view = createRootView(viewDef, context);
const rootNodes = rootRenderNodes(view);
return {rootNodes, view};
}
describe('DebugContext', () => {
class AComp {}
@ -36,12 +21,13 @@ export function main() {
function createViewWithData() {
const {view} = createAndGetRootNodes(compViewDef([
elementDef(
NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !,
0, NodeFlags.None, null, null, 1, 'div', null, null, null, null,
() => compViewDef([
elementDef(NodeFlags.None, [['ref', QueryValueType.ElementRef]], null !, 2, 'span'),
directiveDef(NodeFlags.None, null !, 0, AService, []), textDef(null !, ['a'])
elementDef(
0, NodeFlags.None, [['ref', QueryValueType.ElementRef]], null, 2, 'span'),
directiveDef(1, NodeFlags.None, null, 0, AService, []), textDef(2, null, ['a'])
])),
directiveDef(NodeFlags.Component, null !, 0, AComp, []),
directiveDef(1, NodeFlags.Component, null, 0, AComp, []),
]));
return view;
}

View File

@ -6,46 +6,34 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation, WrappedValue, getDebugNode} from '@angular/core';
import {ArgumentType, DebugContext, NodeDef, NodeFlags, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asTextData, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
import {inject} from '@angular/core/testing';
import {getDebugNode} from '@angular/core';
import {NodeFlags, Services, asTextData, elementDef, textDef} from '@angular/core/src/view/index';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, isBrowser} from './helper';
import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRootNodes} from './helper';
export function main() {
describe(`View Text`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function createAndGetRootNodes(
viewDef: ViewDefinition, context?: any): {rootNodes: any[], view: ViewData} {
const view = createRootView(viewDef, context);
const rootNodes = rootRenderNodes(view);
return {rootNodes, view};
}
describe('create', () => {
it('should create text nodes without parents', () => {
const rootNodes = createAndGetRootNodes(compViewDef([textDef(null !, ['a'])])).rootNodes;
const rootNodes = createAndGetRootNodes(compViewDef([textDef(0, null, ['a'])])).rootNodes;
expect(rootNodes.length).toBe(1);
expect(getDOM().getText(rootNodes[0])).toBe('a');
});
it('should create views with multiple root text nodes', () => {
const rootNodes = createAndGetRootNodes(compViewDef([
textDef(null !, ['a']), textDef(null !, ['b'])
textDef(0, null, ['a']),
textDef(1, null, ['b']),
])).rootNodes;
expect(rootNodes.length).toBe(2);
});
it('should create text nodes with parents', () => {
const rootNodes = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null !, null !, 1, 'div'),
textDef(null !, ['a']),
elementDef(0, NodeFlags.None, null, null, 1, 'div'),
textDef(1, null, ['a']),
])).rootNodes;
expect(rootNodes.length).toBe(1);
const textNode = getDOM().firstChild(rootNodes[0]);
@ -55,7 +43,7 @@ export function main() {
it('should add debug information to the renderer', () => {
const someContext = new Object();
const {view, rootNodes} =
createAndGetRootNodes(compViewDef([textDef(null !, ['a'])]), someContext);
createAndGetRootNodes(compViewDef([textDef(0, null, ['a'])]), someContext);
expect(getDebugNode(rootNodes[0]) !.nativeNode).toBe(asTextData(view, 0).renderText);
});
});
@ -65,7 +53,7 @@ export function main() {
it(`should update via strategy ${inlineDynamic}`, () => {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
[
textDef(null !, ['0', '1', '2']),
textDef(0, null, ['0', '1', '2']),
],
null !, (check, view) => {
checkNodeInlineOrDynamic(check, view, 0, inlineDynamic, ['a', 'b']);
@ -73,7 +61,6 @@ export function main() {
Services.checkAndUpdateView(view);
const node = rootNodes[0];
expect(getDOM().getText(rootNodes[0])).toBe('0a1b2');
});

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {NodeFlags, QueryValueType, ViewData, ViewDefinition, ViewFlags, anchorDef, directiveDef, elementDef, textDef, viewDef} from '@angular/core/src/view/index';
import {NodeFlags, QueryValueType, ViewDefinition, ViewFlags, anchorDef, directiveDef, elementDef, textDef, viewDef} from '@angular/core/src/view/index';
import {filterQueryId} from '@angular/core/src/view/util';
export function main() {
@ -14,14 +14,14 @@ export function main() {
describe('parent', () => {
function parents(viewDef: ViewDefinition): (number | null)[] {
return viewDef.nodes.map(node => node.parent ? node.parent.index : null);
return viewDef.nodes.map(node => node.parent ? node.parent.nodeIndex : null);
}
it('should calculate parents for one level', () => {
const vd = viewDef(ViewFlags.None, [
elementDef(NodeFlags.None, null !, null !, 2, 'span'),
textDef(null !, ['a']),
textDef(null !, ['a']),
elementDef(0, NodeFlags.None, null, null, 2, 'span'),
textDef(1, null, ['a']),
textDef(2, null, ['a']),
]);
expect(parents(vd)).toEqual([null, 0, 0]);
@ -29,11 +29,11 @@ export function main() {
it('should calculate parents for one level, multiple roots', () => {
const vd = viewDef(ViewFlags.None, [
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
textDef(null !, ['a']),
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
textDef(null !, ['a']),
textDef(null !, ['a']),
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
textDef(1, null, ['a']),
elementDef(2, NodeFlags.None, null, null, 1, 'span'),
textDef(3, null, ['a']),
textDef(4, null, ['a']),
]);
expect(parents(vd)).toEqual([null, 0, null, 2, null]);
@ -41,12 +41,12 @@ export function main() {
it('should calculate parents for multiple levels', () => {
const vd = viewDef(ViewFlags.None, [
elementDef(NodeFlags.None, null !, null !, 2, 'span'),
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
textDef(null !, ['a']),
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
textDef(null !, ['a']),
textDef(null !, ['a']),
elementDef(0, NodeFlags.None, null, null, 2, 'span'),
elementDef(1, NodeFlags.None, null, null, 1, 'span'),
textDef(2, null, ['a']),
elementDef(3, NodeFlags.None, null, null, 1, 'span'),
textDef(4, null, ['a']),
textDef(5, null, ['a']),
]);
expect(parents(vd)).toEqual([null, 0, 1, null, 3, null]);
@ -65,8 +65,8 @@ export function main() {
it('should calculate childFlags for one level', () => {
const vd = viewDef(ViewFlags.None, [
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.AfterContentChecked, null !, 0, AService, [])
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(1, NodeFlags.AfterContentChecked, null, 0, AService, [])
]);
expect(childFlags(vd)).toEqual([
@ -80,9 +80,9 @@ export function main() {
it('should calculate childFlags for two levels', () => {
const vd = viewDef(ViewFlags.None, [
elementDef(NodeFlags.None, null !, null !, 2, 'span'),
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.AfterContentChecked, null !, 0, AService, [])
elementDef(0, NodeFlags.None, null, null, 2, 'span'),
elementDef(1, NodeFlags.None, null, null, 1, 'span'),
directiveDef(2, NodeFlags.AfterContentChecked, null, 0, AService, [])
]);
expect(childFlags(vd)).toEqual([
@ -98,11 +98,11 @@ export function main() {
it('should calculate childFlags for one level, multiple roots', () => {
const vd = viewDef(ViewFlags.None, [
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.AfterContentChecked, null !, 0, AService, []),
elementDef(NodeFlags.None, null !, null !, 2, 'span'),
directiveDef(NodeFlags.AfterContentInit, null !, 0, AService, []),
directiveDef(NodeFlags.AfterViewChecked, null !, 0, AService, []),
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(1, NodeFlags.AfterContentChecked, null, 0, AService, []),
elementDef(2, NodeFlags.None, null, null, 2, 'span'),
directiveDef(3, NodeFlags.AfterContentInit, null, 0, AService, []),
directiveDef(4, NodeFlags.AfterViewChecked, null, 0, AService, []),
]);
expect(childFlags(vd)).toEqual([
@ -120,12 +120,12 @@ export function main() {
it('should calculate childFlags for multiple levels', () => {
const vd = viewDef(ViewFlags.None, [
elementDef(NodeFlags.None, null !, null !, 2, 'span'),
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.AfterContentChecked, null !, 0, AService, []),
elementDef(NodeFlags.None, null !, null !, 2, 'span'),
directiveDef(NodeFlags.AfterContentInit, null !, 0, AService, []),
directiveDef(NodeFlags.AfterViewInit, null !, 0, AService, []),
elementDef(0, NodeFlags.None, null, null, 2, 'span'),
elementDef(1, NodeFlags.None, null, null, 1, 'span'),
directiveDef(2, NodeFlags.AfterContentChecked, null !, 0, AService, []),
elementDef(3, NodeFlags.None, null, null, 2, 'span'),
directiveDef(4, NodeFlags.AfterContentInit, null, 0, AService, []),
directiveDef(5, NodeFlags.AfterViewInit, null, 0, AService, []),
]);
expect(childFlags(vd)).toEqual([
@ -151,8 +151,8 @@ export function main() {
it('should calculate childMatchedQueries for one level', () => {
const vd = viewDef(ViewFlags.None, [
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.None, [[1, QueryValueType.Provider]], 0, AService, [])
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(1, NodeFlags.None, [[1, QueryValueType.Provider]], 0, AService, [])
]);
expect(childMatchedQueries(vd)).toEqual([filterQueryId(1), 0]);
@ -160,9 +160,9 @@ export function main() {
it('should calculate childMatchedQueries for two levels', () => {
const vd = viewDef(ViewFlags.None, [
elementDef(NodeFlags.None, null !, null !, 2, 'span'),
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.None, [[1, QueryValueType.Provider]], 0, AService, [])
elementDef(0, NodeFlags.None, null, null, 2, 'span'),
elementDef(1, NodeFlags.None, null, null, 1, 'span'),
directiveDef(2, NodeFlags.None, [[1, QueryValueType.Provider]], 0, AService, [])
]);
expect(childMatchedQueries(vd)).toEqual([filterQueryId(1), filterQueryId(1), 0]);
@ -170,11 +170,11 @@ export function main() {
it('should calculate childMatchedQueries for one level, multiple roots', () => {
const vd = viewDef(ViewFlags.None, [
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.None, [[1, QueryValueType.Provider]], 0, AService, []),
elementDef(NodeFlags.None, null !, null !, 2, 'span'),
directiveDef(NodeFlags.None, [[2, QueryValueType.Provider]], 0, AService, []),
directiveDef(NodeFlags.None, [[3, QueryValueType.Provider]], 0, AService, []),
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
directiveDef(1, NodeFlags.None, [[1, QueryValueType.Provider]], 0, AService, []),
elementDef(2, NodeFlags.None, null, null, 2, 'span'),
directiveDef(3, NodeFlags.None, [[2, QueryValueType.Provider]], 0, AService, []),
directiveDef(4, NodeFlags.None, [[3, QueryValueType.Provider]], 0, AService, []),
]);
expect(childMatchedQueries(vd)).toEqual([
@ -184,12 +184,12 @@ export function main() {
it('should calculate childMatchedQueries for multiple levels', () => {
const vd = viewDef(ViewFlags.None, [
elementDef(NodeFlags.None, null !, null !, 2, 'span'),
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
directiveDef(NodeFlags.None, [[1, QueryValueType.Provider]], 0, AService, []),
elementDef(NodeFlags.None, null !, null !, 2, 'span'),
directiveDef(NodeFlags.None, [[2, QueryValueType.Provider]], 0, AService, []),
directiveDef(NodeFlags.None, [[3, QueryValueType.Provider]], 0, AService, []),
elementDef(0, NodeFlags.None, null, null, 2, 'span'),
elementDef(1, NodeFlags.None, null, null, 1, 'span'),
directiveDef(2, NodeFlags.None, [[1, QueryValueType.Provider]], 0, AService, []),
elementDef(3, NodeFlags.None, null, null, 2, 'span'),
directiveDef(4, NodeFlags.None, [[2, QueryValueType.Provider]], 0, AService, []),
directiveDef(5, NodeFlags.None, [[3, QueryValueType.Provider]], 0, AService, []),
]);
expect(childMatchedQueries(vd)).toEqual([
@ -199,13 +199,13 @@ export function main() {
it('should included embedded views into childMatchedQueries', () => {
const vd = viewDef(ViewFlags.None, [
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
anchorDef(
NodeFlags.None, null !, null !, 0, null !,
NodeFlags.None, null, null, 0, null,
() => viewDef(
ViewFlags.None,
[
elementDef(NodeFlags.None, [[1, QueryValueType.Provider]], null !, 0, 'span'),
elementDef(0, NodeFlags.None, [[1, QueryValueType.Provider]], null, 0, 'span'),
]))
]);