refactor(ivy): move dir flags to tnode (#22901)

PR Close #22901
This commit is contained in:
Kara Erickson 2018-03-20 19:06:49 -07:00 committed by Matias Niemelä
parent 99711b12f9
commit e44f69c387
12 changed files with 150 additions and 155 deletions

View File

@ -16,7 +16,7 @@ import {assertComponentType, assertNotNull} from './assert';
import {queueInitHooks, queueLifecycleHooks} from './hooks'; import {queueInitHooks, queueLifecycleHooks} from './hooks';
import {CLEAN_PROMISE, _getComponentHostLElementNode, baseDirectiveCreate, createLView, createTView, enterView, getRootView, hostElement, initChangeDetectorIfExisting, locateHostElement, renderComponentOrTemplate} from './instructions'; import {CLEAN_PROMISE, _getComponentHostLElementNode, baseDirectiveCreate, createLView, createTView, enterView, getRootView, hostElement, initChangeDetectorIfExisting, locateHostElement, renderComponentOrTemplate} from './instructions';
import {ComponentDef, ComponentType} from './interfaces/definition'; import {ComponentDef, ComponentType} from './interfaces/definition';
import {LElementNode} from './interfaces/node'; import {LElementNode, TNodeFlags} from './interfaces/node';
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer'; import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
import {LView, LViewFlags, RootContext} from './interfaces/view'; import {LView, LViewFlags, RootContext} from './interfaces/view';
import {stringify} from './util'; import {stringify} from './util';
@ -174,7 +174,7 @@ export function LifecycleHooksFeature(component: any, def: ComponentDef<any>): v
// Root component is always created at dir index 1, after host element at 0 // Root component is always created at dir index 1, after host element at 0
queueInitHooks(1, def.onInit, def.doCheck, elementNode.view.tView); queueInitHooks(1, def.onInit, def.doCheck, elementNode.view.tView);
queueLifecycleHooks(elementNode.flags, elementNode.view); queueLifecycleHooks(elementNode.tNode !.flags, elementNode.view);
} }
/** /**

View File

@ -22,7 +22,7 @@ import {assertLessThan, assertNotNull} from './assert';
import {assertPreviousIsParent, getDirectiveInstance, getPreviousOrParentNode, getRenderer, renderEmbeddedTemplate} from './instructions'; import {assertPreviousIsParent, getDirectiveInstance, getPreviousOrParentNode, getRenderer, renderEmbeddedTemplate} from './instructions';
import {ComponentTemplate, DirectiveDef} from './interfaces/definition'; import {ComponentTemplate, DirectiveDef} from './interfaces/definition';
import {LInjector} from './interfaces/injector'; import {LInjector} from './interfaces/injector';
import {LContainerNode, LElementNode, LNode, LNodeFlags, LViewNode} from './interfaces/node'; import {LContainerNode, LElementNode, LNode, LNodeType, LViewNode, TNodeFlags} from './interfaces/node';
import {QueryReadType} from './interfaces/query'; import {QueryReadType} from './interfaces/query';
import {Renderer3} from './interfaces/renderer'; import {Renderer3} from './interfaces/renderer';
import {LView} from './interfaces/view'; import {LView} from './interfaces/view';
@ -274,7 +274,7 @@ export function injectChangeDetectorRef(): viewEngine_ChangeDetectorRef {
export function injectAttribute(attrName: string): string|undefined { export function injectAttribute(attrName: string): string|undefined {
ngDevMode && assertPreviousIsParent(); ngDevMode && assertPreviousIsParent();
const lElement = getPreviousOrParentNode() as LElementNode; const lElement = getPreviousOrParentNode() as LElementNode;
ngDevMode && assertNodeType(lElement, LNodeFlags.Element); ngDevMode && assertNodeType(lElement, LNodeType.Element);
const tElement = lElement.tNode !; const tElement = lElement.tNode !;
ngDevMode && assertNotNull(tElement, 'expecting tNode'); ngDevMode && assertNotNull(tElement, 'expecting tNode');
const attrs = tElement.attrs; const attrs = tElement.attrs;
@ -302,7 +302,7 @@ export function getOrCreateChangeDetectorRef(
if (currentNode.data === null) { if (currentNode.data === null) {
// if data is null, this node is a regular element node (not a component) // if data is null, this node is a regular element node (not a component)
return di.changeDetectorRef = getOrCreateHostChangeDetector(currentNode.view.node); return di.changeDetectorRef = getOrCreateHostChangeDetector(currentNode.view.node);
} else if ((currentNode.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.Element) { } else if (currentNode.type === LNodeType.Element) {
// if it's an element node with data, it's a component and context will be set later // if it's an element node with data, it's a component and context will be set later
return di.changeDetectorRef = createViewRef(currentNode.data as LView, context); return di.changeDetectorRef = createViewRef(currentNode.data as LView, context);
} }
@ -316,10 +316,10 @@ function getOrCreateHostChangeDetector(currentNode: LViewNode | LElementNode):
const hostInjector = hostNode.nodeInjector; const hostInjector = hostNode.nodeInjector;
const existingRef = hostInjector && hostInjector.changeDetectorRef; const existingRef = hostInjector && hostInjector.changeDetectorRef;
return existingRef ? return existingRef ? existingRef :
existingRef :
createViewRef( createViewRef(
hostNode.data as LView, hostNode.view.data[hostNode.flags >> LNodeFlags.INDX_SHIFT]); hostNode.data as LView,
hostNode.view.data[hostNode.tNode !.flags >> TNodeFlags.INDX_SHIFT]);
} }
/** /**
@ -328,7 +328,7 @@ function getOrCreateHostChangeDetector(currentNode: LViewNode | LElementNode):
* returns itself. * returns itself.
*/ */
function getClosestComponentAncestor(node: LViewNode | LElementNode): LElementNode { function getClosestComponentAncestor(node: LViewNode | LElementNode): LElementNode {
while ((node.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.View) { while (node.type === LNodeType.View) {
node = node.view.node; node = node.view.node;
} }
return node as LElementNode; return node as LElementNode;
@ -386,13 +386,13 @@ export function getOrCreateInjectable<T>(
// The size of the node's directive's list is stored in certain bits of the node's flags, // The size of the node's directive's list is stored in certain bits of the node's flags,
// so exact it with a mask and shift it back such that the bits reflect the real value. // so exact it with a mask and shift it back such that the bits reflect the real value.
const flags = node.flags; const flags = node.tNode !.flags;
const size = (flags & LNodeFlags.SIZE_MASK) >> LNodeFlags.SIZE_SHIFT; const size = flags & TNodeFlags.SIZE_MASK;
if (size !== 0) { if (size !== 0) {
// The start index of the directives list is also part of the node's flags, but there is // The start index of the directives list is also part of the node's flags, but there is
// nothing to the "left" of it so it doesn't need a mask. // nothing to the "left" of it so it doesn't need a mask.
const start = flags >> LNodeFlags.INDX_SHIFT; const start = flags >> TNodeFlags.INDX_SHIFT;
const tData = node.view.tView.data; const tData = node.view.tView.data;
for (let i = start, ii = start + size; i < ii; i++) { for (let i = start, ii = start + size; i < ii; i++) {
@ -510,10 +510,8 @@ export class ReadFromInjectorFn<T> {
* @returns The ElementRef instance to use * @returns The ElementRef instance to use
*/ */
export function getOrCreateElementRef(di: LInjector): viewEngine_ElementRef { export function getOrCreateElementRef(di: LInjector): viewEngine_ElementRef {
return di.elementRef || return di.elementRef || (di.elementRef = new ElementRef(
(di.elementRef = new ElementRef( di.node.type === LNodeType.Container ? null : di.node.native));
((di.node.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.Container) ? null :
di.node.native));
} }
export const QUERY_READ_TEMPLATE_REF = <QueryReadType<viewEngine_TemplateRef<any>>>( export const QUERY_READ_TEMPLATE_REF = <QueryReadType<viewEngine_TemplateRef<any>>>(
@ -530,12 +528,12 @@ export const QUERY_READ_ELEMENT_REF =
export const QUERY_READ_FROM_NODE = export const QUERY_READ_FROM_NODE =
(new ReadFromInjectorFn<any>((injector: LInjector, node: LNode, directiveIdx: number) => { (new ReadFromInjectorFn<any>((injector: LInjector, node: LNode, directiveIdx: number) => {
ngDevMode && assertNodeOfPossibleTypes(node, LNodeFlags.Container, LNodeFlags.Element); ngDevMode && assertNodeOfPossibleTypes(node, LNodeType.Container, LNodeType.Element);
if (directiveIdx > -1) { if (directiveIdx > -1) {
return node.view.data[directiveIdx]; return node.view.data[directiveIdx];
} else if ((node.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.Element) { } else if (node.type === LNodeType.Element) {
return getOrCreateElementRef(injector); return getOrCreateElementRef(injector);
} else if ((node.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.Container) { } else if (node.type === LNodeType.Container) {
return getOrCreateTemplateRef(injector); return getOrCreateTemplateRef(injector);
} }
throw new Error('fail'); throw new Error('fail');
@ -613,7 +611,7 @@ class ViewContainerRef implements viewEngine_ViewContainerRef {
// Look for the parent node and increment its dynamic view count. // Look for the parent node and increment its dynamic view count.
if (this._node.parent !== null && this._node.parent.data !== null) { if (this._node.parent !== null && this._node.parent.data !== null) {
ngDevMode && ngDevMode &&
assertNodeOfPossibleTypes(this._node.parent, LNodeFlags.View, LNodeFlags.Element); assertNodeOfPossibleTypes(this._node.parent, LNodeType.View, LNodeType.Element);
this._node.parent.data.dynamicViewCount++; this._node.parent.data.dynamicViewCount++;
} }
} }
@ -635,7 +633,7 @@ class ViewContainerRef implements viewEngine_ViewContainerRef {
* @returns The TemplateRef instance to use * @returns The TemplateRef instance to use
*/ */
export function getOrCreateTemplateRef<T>(di: LInjector): viewEngine_TemplateRef<T> { export function getOrCreateTemplateRef<T>(di: LInjector): viewEngine_TemplateRef<T> {
ngDevMode && assertNodeType(di.node, LNodeFlags.Container); ngDevMode && assertNodeType(di.node, LNodeType.Container);
const data = (di.node as LContainerNode).data; const data = (di.node as LContainerNode).data;
return di.templateRef || (di.templateRef = new TemplateRef<any>( return di.templateRef || (di.templateRef = new TemplateRef<any>(
getOrCreateElementRef(di), data.template !, getRenderer())); getOrCreateElementRef(di), data.template !, getRenderer()));

View File

@ -7,7 +7,7 @@
*/ */
import {DirectiveDef} from './interfaces/definition'; import {DirectiveDef} from './interfaces/definition';
import {LNodeFlags} from './interfaces/node'; import {TNodeFlags} from './interfaces/node';
import {HookData, LView, LifecycleStage, TView} from './interfaces/view'; import {HookData, LView, LifecycleStage, TView} from './interfaces/view';
/** /**
@ -43,13 +43,13 @@ export function queueInitHooks(
export function queueLifecycleHooks(flags: number, currentView: LView): void { export function queueLifecycleHooks(flags: number, currentView: LView): void {
const tView = currentView.tView; const tView = currentView.tView;
if (tView.firstTemplatePass === true) { if (tView.firstTemplatePass === true) {
const size = (flags & LNodeFlags.SIZE_MASK) >> LNodeFlags.SIZE_SHIFT; const start = flags >> TNodeFlags.INDX_SHIFT;
const start = flags >> LNodeFlags.INDX_SHIFT; const end = start + (flags & TNodeFlags.SIZE_MASK);
// It's necessary to loop through the directives at elementEnd() (rather than processing in // It's necessary to loop through the directives at elementEnd() (rather than processing in
// directiveCreate) so we can preserve the current hook order. Content, view, and destroy // directiveCreate) so we can preserve the current hook order. Content, view, and destroy
// hooks for projected components and directives must be called *before* their hosts. // hooks for projected components and directives must be called *before* their hosts.
for (let i = start, end = start + size; i < end; i++) { for (let i = start; i < end; i++) {
const def = (tView.data[i] as DirectiveDef<any>); const def = (tView.data[i] as DirectiveDef<any>);
queueContentHooks(def, tView, i); queueContentHooks(def, tView, i);
queueViewHooks(def, tView, i); queueViewHooks(def, tView, i);

View File

@ -15,7 +15,7 @@ import {CssSelector, LProjection, NG_PROJECT_AS_ATTR_NAME} from './interfaces/pr
import {LQueries} from './interfaces/query'; import {LQueries} from './interfaces/query';
import {LView, LViewFlags, LifecycleStage, RootContext, TData, TView} from './interfaces/view'; import {LView, LViewFlags, LifecycleStage, RootContext, TData, TView} from './interfaces/view';
import {LContainerNode, LElementNode, LNode, LNodeFlags, LProjectionNode, LTextNode, LViewNode, TNode, TContainerNode, InitialInputData, InitialInputs, PropertyAliases, PropertyAliasValue,} from './interfaces/node'; import {LContainerNode, LElementNode, LNode, LNodeType, TNodeFlags, LProjectionNode, LTextNode, LViewNode, TNode, TContainerNode, InitialInputData, InitialInputs, PropertyAliases, PropertyAliasValue,} from './interfaces/node';
import {assertNodeType} from './node_assert'; import {assertNodeType} from './node_assert';
import {appendChild, insertChild, insertView, appendProjectedNode, removeView, canInsertNativeNode} from './node_manipulation'; import {appendChild, insertChild, insertView, appendProjectedNode, removeView, canInsertNativeNode} from './node_manipulation';
import {matchingSelectorIndex} from './node_selector_matcher'; import {matchingSelectorIndex} from './node_selector_matcher';
@ -296,18 +296,18 @@ export function createLView(
* keep the execution code monomorphic and fast. * keep the execution code monomorphic and fast.
*/ */
export function createLNode( export function createLNode(
index: number | null, type: LNodeFlags.Element, native: RElement | RText | null, index: number | null, type: LNodeType.Element, native: RElement | RText | null,
lView?: LView | null): LElementNode; lView?: LView | null): LElementNode;
export function createLNode( export function createLNode(
index: null, type: LNodeFlags.View, native: null, lView: LView): LViewNode; index: null, type: LNodeType.View, native: null, lView: LView): LViewNode;
export function createLNode( export function createLNode(
index: number, type: LNodeFlags.Container, native: undefined, index: number, type: LNodeType.Container, native: undefined,
lContainer: LContainer): LContainerNode; lContainer: LContainer): LContainerNode;
export function createLNode( export function createLNode(
index: number, type: LNodeFlags.Projection, native: null, index: number, type: LNodeType.Projection, native: null,
lProjection: LProjection): LProjectionNode; lProjection: LProjection): LProjectionNode;
export function createLNode( export function createLNode(
index: number | null, type: LNodeFlags, native: RText | RElement | null | undefined, index: number | null, type: LNodeType, native: RText | RElement | null | undefined,
state?: null | LView | LContainer | LProjection): LElementNode&LTextNode&LViewNode& state?: null | LView | LContainer | LProjection): LElementNode&LTextNode&LViewNode&
LContainerNode&LProjectionNode { LContainerNode&LProjectionNode {
const parent = isParent ? previousOrParentNode : const parent = isParent ? previousOrParentNode :
@ -317,7 +317,7 @@ export function createLNode(
parent && parent.queries && parent.queries.child(); parent && parent.queries && parent.queries.child();
const isState = state != null; const isState = state != null;
const node: LElementNode&LTextNode&LViewNode&LContainerNode&LProjectionNode = { const node: LElementNode&LTextNode&LViewNode&LContainerNode&LProjectionNode = {
flags: type, type: type,
native: native as any, native: native as any,
view: currentView, view: currentView,
parent: parent as any, parent: parent as any,
@ -330,7 +330,7 @@ export function createLNode(
pNextOrParent: null pNextOrParent: null
}; };
if ((type & LNodeFlags.ViewOrElement) === LNodeFlags.ViewOrElement && isState) { if ((type & LNodeType.ViewOrElement) === LNodeType.ViewOrElement && isState) {
// Bit of a hack to bust through the readonly because there is a circular dep between // Bit of a hack to bust through the readonly because there is a circular dep between
// LView and LNode. // LView and LNode.
ngDevMode && assertNull((state as LView).node, 'LView.node should not have been initialized'); ngDevMode && assertNull((state as LView).node, 'LView.node should not have been initialized');
@ -352,7 +352,7 @@ export function createLNode(
if (isParent) { if (isParent) {
currentQueries = null; currentQueries = null;
if (previousOrParentNode.view === currentView || if (previousOrParentNode.view === currentView ||
(previousOrParentNode.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.View) { previousOrParentNode.type === LNodeType.View) {
// We are in the same view, which means we are adding content node to the parent View. // We are in the same view, which means we are adding content node to the parent View.
ngDevMode && assertNull( ngDevMode && assertNull(
previousOrParentNode.child, previousOrParentNode.child,
@ -399,7 +399,7 @@ export function renderTemplate<T>(
resetApplicationState(); resetApplicationState();
rendererFactory = providedRendererFactory; rendererFactory = providedRendererFactory;
host = createLNode( host = createLNode(
null, LNodeFlags.Element, hostNode, null, LNodeType.Element, hostNode,
createLView( createLView(
-1, providedRendererFactory.createRenderer(null, null), getOrCreateTView(template), -1, providedRendererFactory.createRenderer(null, null), getOrCreateTView(template),
null, {}, LViewFlags.CheckAlways)); null, {}, LViewFlags.CheckAlways));
@ -422,7 +422,7 @@ export function renderEmbeddedTemplate<T>(
if (viewNode == null) { if (viewNode == null) {
const view = const view =
createLView(-1, renderer, createTView(), template, context, LViewFlags.CheckAlways); createLView(-1, renderer, createTView(), template, context, LViewFlags.CheckAlways);
viewNode = createLNode(null, LNodeFlags.View, null, view); viewNode = createLNode(null, LNodeType.View, null, view);
cm = true; cm = true;
} }
enterView(viewNode.data, viewNode); enterView(viewNode.data, viewNode);
@ -521,7 +521,7 @@ export function elementStart(
// Only component views should be added to the view tree directly. Embedded views are // 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. // accessed through their containers because they may be removed / re-added later.
node = createLNode(index, LNodeFlags.Element, native, componentView); node = createLNode(index, LNodeType.Element, native, componentView);
if (node.tNode == null) { if (node.tNode == null) {
const localNames: (string | number)[]|null = const localNames: (string | number)[]|null =
@ -700,10 +700,12 @@ export function locateHostElement(
*/ */
export function hostElement(rNode: RElement | null, def: ComponentDef<any>): LElementNode { export function hostElement(rNode: RElement | null, def: ComponentDef<any>): LElementNode {
resetApplicationState(); resetApplicationState();
return createLNode( const node = createLNode(
0, LNodeFlags.Element, rNode, createLView( 0, LNodeType.Element, rNode, createLView(
-1, renderer, getOrCreateTView(def.template), null, null, -1, renderer, getOrCreateTView(def.template), null, null,
def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways)); def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways));
if (firstTemplatePass) node.tNode = createTNode(def.tag, null, null, null);
return node;
} }
@ -740,7 +742,7 @@ export function listener(
if (tNode.outputs === undefined) { if (tNode.outputs === undefined) {
// if we create TNode here, inputs must be undefined so we know they still need to be // if we create TNode here, inputs must be undefined so we know they still need to be
// checked // checked
tNode.outputs = generatePropertyAliases(node.flags, BindingDirection.Output); tNode.outputs = generatePropertyAliases(node.tNode !.flags, BindingDirection.Output);
} }
const outputs = tNode.outputs; const outputs = tNode.outputs;
@ -770,10 +772,10 @@ export function elementEnd() {
ngDevMode && assertHasParent(); ngDevMode && assertHasParent();
previousOrParentNode = previousOrParentNode.parent !; previousOrParentNode = previousOrParentNode.parent !;
} }
ngDevMode && assertNodeType(previousOrParentNode, LNodeFlags.Element); ngDevMode && assertNodeType(previousOrParentNode, LNodeType.Element);
const queries = previousOrParentNode.queries; const queries = previousOrParentNode.queries;
queries && queries.addNode(previousOrParentNode); queries && queries.addNode(previousOrParentNode);
queueLifecycleHooks(previousOrParentNode.flags, currentView); queueLifecycleHooks(previousOrParentNode.tNode !.flags, currentView);
} }
/** /**
@ -823,7 +825,7 @@ export function elementProperty<T>(
// yet been checked // yet been checked
if (tNode && tNode.inputs === undefined) { if (tNode && tNode.inputs === undefined) {
// mark inputs as checked // mark inputs as checked
tNode.inputs = generatePropertyAliases(node.flags, BindingDirection.Input); tNode.inputs = generatePropertyAliases(node.tNode !.flags, BindingDirection.Input);
} }
const inputData = tNode && tNode.inputs; const inputData = tNode && tNode.inputs;
@ -855,6 +857,7 @@ function createTNode(
tagName: string | null, attrs: string[] | null, data: TContainer | null, tagName: string | null, attrs: string[] | null, data: TContainer | null,
localNames: (string | number)[] | null): TNode { localNames: (string | number)[] | null): TNode {
return { return {
flags: 0,
tagName: tagName, tagName: tagName,
attrs: attrs, attrs: attrs,
localNames: localNames, localNames: localNames,
@ -883,13 +886,13 @@ function setInputsForProperty(inputs: PropertyAliasValue, value: any): void {
* @param Direction direction whether to consider inputs or outputs * @param Direction direction whether to consider inputs or outputs
* @returns PropertyAliases|null aggregate of all properties if any, `null` otherwise * @returns PropertyAliases|null aggregate of all properties if any, `null` otherwise
*/ */
function generatePropertyAliases(lNodeFlags: number, direction: BindingDirection): PropertyAliases| function generatePropertyAliases(
null { tNodeFlags: TNodeFlags, direction: BindingDirection): PropertyAliases|null {
const size = (lNodeFlags & LNodeFlags.SIZE_MASK) >> LNodeFlags.SIZE_SHIFT; const size = tNodeFlags & TNodeFlags.SIZE_MASK;
let propStore: PropertyAliases|null = null; let propStore: PropertyAliases|null = null;
if (size > 0) { if (size > 0) {
const start = lNodeFlags >> LNodeFlags.INDX_SHIFT; const start = tNodeFlags >> TNodeFlags.INDX_SHIFT;
const isInput = direction === BindingDirection.Input; const isInput = direction === BindingDirection.Input;
for (let i = start, ii = start + size; i < ii; i++) { for (let i = start, ii = start + size; i < ii; i++) {
@ -1045,7 +1048,7 @@ export function text(index: number, value?: any): void {
(isProceduralRenderer(renderer) ? renderer.createText(stringify(value)) : (isProceduralRenderer(renderer) ? renderer.createText(stringify(value)) :
renderer.createTextNode(stringify(value))) : renderer.createTextNode(stringify(value))) :
null; null;
const node = createLNode(index, LNodeFlags.Element, textNode); const node = createLNode(index, LNodeType.Element, textNode);
// Text nodes are self closing. // Text nodes are self closing.
isParent = false; isParent = false;
appendChild(node.parent !, textNode, currentView); appendChild(node.parent !, textNode, currentView);
@ -1101,7 +1104,7 @@ export function directiveCreate<T>(
ngDevMode && assertNotNull(previousOrParentNode.tNode, 'previousOrParentNode.tNode'); ngDevMode && assertNotNull(previousOrParentNode.tNode, 'previousOrParentNode.tNode');
const tNode: TNode|null = previousOrParentNode.tNode !; const tNode: TNode|null = previousOrParentNode.tNode !;
if (currentView.tView.firstTemplatePass && localNames) { if (firstTemplatePass && localNames) {
tNode.localNames = tNode.localNames ? tNode.localNames.concat(localNames) : localNames; tNode.localNames = tNode.localNames ? tNode.localNames.concat(localNames) : localNames;
} }
@ -1128,14 +1131,12 @@ export function baseDirectiveCreate<T>(
ngDevMode && ngDevMode &&
assertNull(currentView.bindingStartIndex, 'directives should be created before any bindings'); assertNull(currentView.bindingStartIndex, 'directives should be created before any bindings');
ngDevMode && assertPreviousIsParent(); ngDevMode && assertPreviousIsParent();
let flags = previousOrParentNode !.flags;
let size = flags & LNodeFlags.SIZE_MASK; if (firstTemplatePass) {
if (size === 0) { const flags = previousOrParentNode.tNode !.flags;
flags = (index << LNodeFlags.INDX_SHIFT) | LNodeFlags.SIZE_SKIP | flags & LNodeFlags.TYPE_MASK; previousOrParentNode.tNode !.flags =
} else { (flags & TNodeFlags.SIZE_MASK) === 0 ? (index << TNodeFlags.INDX_SHIFT) | 1 : flags + 1;
flags += LNodeFlags.SIZE_SKIP;
} }
previousOrParentNode !.flags = flags;
ngDevMode && assertDataInRange(index - 1); ngDevMode && assertDataInRange(index - 1);
Object.defineProperty( Object.defineProperty(
@ -1152,8 +1153,7 @@ export function baseDirectiveCreate<T>(
diPublic(directiveDef !); diPublic(directiveDef !);
} }
if (directiveDef !.attributes != null && if (directiveDef !.attributes != null && previousOrParentNode.type == LNodeType.Element) {
(previousOrParentNode.flags & LNodeFlags.TYPE_MASK) == LNodeFlags.Element) {
setUpAttributes( setUpAttributes(
(previousOrParentNode as LElementNode).native, directiveDef !.attributes as string[]); (previousOrParentNode as LElementNode).native, directiveDef !.attributes as string[]);
} }
@ -1169,8 +1169,7 @@ export function baseDirectiveCreate<T>(
* @param tNode The static data for this node * @param tNode The static data for this node
*/ */
function setInputsFromAttrs<T>(instance: T, inputs: {[key: string]: string}, tNode: TNode): void { function setInputsFromAttrs<T>(instance: T, inputs: {[key: string]: string}, tNode: TNode): void {
const directiveIndex = const directiveIndex = (previousOrParentNode.tNode !.flags & TNodeFlags.SIZE_MASK) - 1;
((previousOrParentNode.flags & LNodeFlags.SIZE_MASK) >> LNodeFlags.SIZE_SHIFT) - 1;
let initialInputData = tNode.initialInputs as InitialInputData | undefined; let initialInputData = tNode.initialInputs as InitialInputData | undefined;
if (initialInputData === undefined || directiveIndex >= initialInputData.length) { if (initialInputData === undefined || directiveIndex >= initialInputData.length) {
@ -1257,7 +1256,7 @@ export function container(
queries: null queries: null
}; };
const node = createLNode(index, LNodeFlags.Container, undefined, lContainer); const node = createLNode(index, LNodeType.Container, undefined, lContainer);
if (node.tNode == null) { if (node.tNode == null) {
const localNames: (string | number)[]|null = findMatchingLocalNames(null, localRefs, -1, ''); const localNames: (string | number)[]|null = findMatchingLocalNames(null, localRefs, -1, '');
@ -1270,7 +1269,7 @@ export function container(
hack_declareDirectives(index, index, directiveTypes, localRefs); hack_declareDirectives(index, index, directiveTypes, localRefs);
isParent = false; isParent = false;
ngDevMode && assertNodeType(previousOrParentNode, LNodeFlags.Container); ngDevMode && assertNodeType(previousOrParentNode, LNodeType.Container);
const queries = node.queries; const queries = node.queries;
if (queries) { if (queries) {
// check if a given container node matches // check if a given container node matches
@ -1288,7 +1287,7 @@ export function container(
export function containerRefreshStart(index: number): void { export function containerRefreshStart(index: number): void {
ngDevMode && assertDataInRange(index); ngDevMode && assertDataInRange(index);
previousOrParentNode = data[index] as LNode; previousOrParentNode = data[index] as LNode;
ngDevMode && assertNodeType(previousOrParentNode, LNodeFlags.Container); ngDevMode && assertNodeType(previousOrParentNode, LNodeType.Container);
isParent = true; isParent = true;
(previousOrParentNode as LContainerNode).data.nextIndex = 0; (previousOrParentNode as LContainerNode).data.nextIndex = 0;
ngDevMode && assertSame( ngDevMode && assertSame(
@ -1311,14 +1310,14 @@ export function containerRefreshEnd(): void {
if (isParent) { if (isParent) {
isParent = false; isParent = false;
} else { } else {
ngDevMode && assertNodeType(previousOrParentNode, LNodeFlags.View); ngDevMode && assertNodeType(previousOrParentNode, LNodeType.View);
ngDevMode && assertHasParent(); ngDevMode && assertHasParent();
previousOrParentNode = previousOrParentNode.parent !; previousOrParentNode = previousOrParentNode.parent !;
} }
ngDevMode && assertNodeType(previousOrParentNode, LNodeFlags.Container); ngDevMode && assertNodeType(previousOrParentNode, LNodeType.Container);
const container = previousOrParentNode as LContainerNode; const container = previousOrParentNode as LContainerNode;
container.native = undefined; container.native = undefined;
ngDevMode && assertNodeType(container, LNodeFlags.Container); ngDevMode && assertNodeType(container, LNodeType.Container);
const nextIndex = container.data.nextIndex; const nextIndex = container.data.nextIndex;
// remove extra views at the end of the container // remove extra views at the end of the container
@ -1377,13 +1376,13 @@ function scanForView(
export function embeddedViewStart(viewBlockId: number): boolean { export function embeddedViewStart(viewBlockId: number): boolean {
const container = const container =
(isParent ? previousOrParentNode : previousOrParentNode.parent !) as LContainerNode; (isParent ? previousOrParentNode : previousOrParentNode.parent !) as LContainerNode;
ngDevMode && assertNodeType(container, LNodeFlags.Container); ngDevMode && assertNodeType(container, LNodeType.Container);
const lContainer = container.data; const lContainer = container.data;
const existingViewNode = scanForView(container, lContainer.nextIndex, viewBlockId); const existingViewNode = scanForView(container, lContainer.nextIndex, viewBlockId);
if (existingViewNode) { if (existingViewNode) {
previousOrParentNode = existingViewNode; previousOrParentNode = existingViewNode;
ngDevMode && assertNodeType(previousOrParentNode, LNodeFlags.View); ngDevMode && assertNodeType(previousOrParentNode, LNodeType.View);
isParent = true; isParent = true;
enterView((existingViewNode as LViewNode).data, existingViewNode as LViewNode); enterView((existingViewNode as LViewNode).data, existingViewNode as LViewNode);
} else { } else {
@ -1395,7 +1394,7 @@ export function embeddedViewStart(viewBlockId: number): boolean {
newView.queries = lContainer.queries.enterView(lContainer.nextIndex); newView.queries = lContainer.queries.enterView(lContainer.nextIndex);
} }
enterView(newView, createLNode(null, LNodeFlags.View, null, newView)); enterView(newView, createLNode(null, LNodeType.View, null, newView));
} }
return !existingViewNode; return !existingViewNode;
@ -1414,7 +1413,7 @@ export function embeddedViewStart(viewBlockId: number): boolean {
* @returns TView * @returns TView
*/ */
function getOrCreateEmbeddedTView(viewIndex: number, parent: LContainerNode): TView { function getOrCreateEmbeddedTView(viewIndex: number, parent: LContainerNode): TView {
ngDevMode && assertNodeType(parent, LNodeFlags.Container); ngDevMode && assertNodeType(parent, LNodeType.Container);
const tContainer = (parent !.tNode as TContainerNode).data; const tContainer = (parent !.tNode as TContainerNode).data;
if (viewIndex >= tContainer.length || tContainer[viewIndex] == null) { if (viewIndex >= tContainer.length || tContainer[viewIndex] == null) {
tContainer[viewIndex] = createTView(); tContainer[viewIndex] = createTView();
@ -1429,8 +1428,8 @@ export function embeddedViewEnd(): void {
const viewNode = previousOrParentNode = currentView.node as LViewNode; const viewNode = previousOrParentNode = currentView.node as LViewNode;
const containerNode = previousOrParentNode.parent as LContainerNode; const containerNode = previousOrParentNode.parent as LContainerNode;
if (containerNode) { if (containerNode) {
ngDevMode && assertNodeType(viewNode, LNodeFlags.View); ngDevMode && assertNodeType(viewNode, LNodeType.View);
ngDevMode && assertNodeType(containerNode, LNodeFlags.Container); ngDevMode && assertNodeType(containerNode, LNodeType.Container);
const lContainer = containerNode.data; const lContainer = containerNode.data;
if (creationMode) { if (creationMode) {
@ -1442,7 +1441,7 @@ export function embeddedViewEnd(): void {
} }
leaveView(currentView !.parent !); leaveView(currentView !.parent !);
ngDevMode && assertEqual(isParent, false, 'isParent'); ngDevMode && assertEqual(isParent, false, 'isParent');
ngDevMode && assertNodeType(previousOrParentNode, LNodeFlags.View); ngDevMode && assertNodeType(previousOrParentNode, LNodeType.View);
} }
///////////// /////////////
@ -1456,14 +1455,16 @@ export function embeddedViewEnd(): void {
export function componentRefresh<T>(directiveIndex: number, elementIndex: number): void { export function componentRefresh<T>(directiveIndex: number, elementIndex: number): void {
ngDevMode && assertDataInRange(elementIndex); ngDevMode && assertDataInRange(elementIndex);
const element = data ![elementIndex] as LElementNode; const element = data ![elementIndex] as LElementNode;
ngDevMode && assertNodeType(element, LNodeFlags.Element); ngDevMode && assertNodeType(element, LNodeType.Element);
ngDevMode && assertNotNull(element.data, `Component's host node should have an LView attached.`); ngDevMode && assertNotNull(element.data, `Component's host node should have an LView attached.`);
const hostView = element.data !; const hostView = element.data !;
// Only attached CheckAlways components or attached, dirty OnPush components should be checked // Only attached CheckAlways components or attached, dirty OnPush components should be checked
if (viewAttached(hostView) && hostView.flags & (LViewFlags.CheckAlways | LViewFlags.Dirty)) { if (viewAttached(hostView) && hostView.flags & (LViewFlags.CheckAlways | LViewFlags.Dirty)) {
ngDevMode && assertDataInRange(directiveIndex); ngDevMode && assertDataInRange(directiveIndex);
detectChangesInternal(hostView, element, getDirectiveInstance<T>(data[directiveIndex])); const template = (tData[directiveIndex] as ComponentDef<any>).template;
detectChangesInternal(
hostView, element, template, getDirectiveInstance<T>(data[directiveIndex]));
} }
} }
@ -1561,7 +1562,7 @@ function appendToProjectionNode(
*/ */
export function projection( export function projection(
nodeIndex: number, localIndex: number, selectorIndex: number = 0, attrs?: string[]): void { nodeIndex: number, localIndex: number, selectorIndex: number = 0, attrs?: string[]): void {
const node = createLNode(nodeIndex, LNodeFlags.Projection, null, {head: null, tail: null}); const node = createLNode(nodeIndex, LNodeType.Projection, null, {head: null, tail: null});
if (node.tNode == null) { if (node.tNode == null) {
node.tNode = createTNode(null, attrs || null, null, null); node.tNode = createTNode(null, attrs || null, null, null);
@ -1579,7 +1580,7 @@ export function projection(
// build the linked list of projected nodes: // build the linked list of projected nodes:
for (let i = 0; i < nodesForSelector.length; i++) { for (let i = 0; i < nodesForSelector.length; i++) {
const nodeToProject = nodesForSelector[i]; const nodeToProject = nodesForSelector[i];
if ((nodeToProject.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.Projection) { if (nodeToProject.type === LNodeType.Projection) {
const previouslyProjected = (nodeToProject as LProjectionNode).data; const previouslyProjected = (nodeToProject as LProjectionNode).data;
appendToProjectionNode(node, previouslyProjected.head, previouslyProjected.tail); appendToProjectionNode(node, previouslyProjected.head, previouslyProjected.tail);
} else { } else {
@ -1609,13 +1610,13 @@ export function projection(
*/ */
function findComponentHost(lView: LView): LElementNode { function findComponentHost(lView: LView): LElementNode {
let viewRootLNode = lView.node; let viewRootLNode = lView.node;
while ((viewRootLNode.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.View) { while (viewRootLNode.type === LNodeType.View) {
ngDevMode && assertNotNull(lView.parent, 'lView.parent'); ngDevMode && assertNotNull(lView.parent, 'lView.parent');
lView = lView.parent !; lView = lView.parent !;
viewRootLNode = lView.node; viewRootLNode = lView.node;
} }
ngDevMode && assertNodeType(viewRootLNode, LNodeFlags.Element); ngDevMode && assertNodeType(viewRootLNode, LNodeType.Element);
ngDevMode && assertNotNull(viewRootLNode.data, 'node.data'); ngDevMode && assertNotNull(viewRootLNode.data, 'node.data');
return viewRootLNode as LElementNode; return viewRootLNode as LElementNode;
@ -1768,7 +1769,9 @@ export function getRootView(component: any): LView {
export function detectChanges<T>(component: T): void { export function detectChanges<T>(component: T): void {
const hostNode = _getComponentHostLElementNode(component); const hostNode = _getComponentHostLElementNode(component);
ngDevMode && assertNotNull(hostNode.data, 'Component host node should be attached to an LView'); ngDevMode && assertNotNull(hostNode.data, 'Component host node should be attached to an LView');
detectChangesInternal(hostNode.data as LView, hostNode, component); const componentIndex = hostNode.tNode !.flags >> TNodeFlags.INDX_SHIFT;
const template = (hostNode.view.tView.data[componentIndex] as ComponentDef<T>).template;
detectChangesInternal(hostNode.data as LView, hostNode, template, component);
} }
@ -1804,10 +1807,8 @@ function throwErrorIfNoChangesMode(oldValue: any, currValue: any): never|void {
/** Checks the view of the component provided. Does not gate on dirty checks or execute doCheck. */ /** Checks the view of the component provided. Does not gate on dirty checks or execute doCheck. */
function detectChangesInternal<T>(hostView: LView, hostNode: LElementNode, component: T) { export function detectChangesInternal<T>(
const componentIndex = hostNode.flags >> LNodeFlags.INDX_SHIFT; hostView: LView, hostNode: LElementNode, template: ComponentTemplate<any>, component: T) {
const template = (hostNode.view.tView.data[componentIndex] as ComponentDef<T>).template;
const oldView = enterView(hostView, hostNode); const oldView = enterView(hostView, hostNode);
try { try {
template(component, creationMode); template(component, creationMode);

View File

@ -16,31 +16,24 @@ import {LView, TData, TView} from './view';
/** /**
* LNodeFlags corresponds to the LNode.flags property. It contains information * LNodeType corresponds to the LNode.type property. It contains information
* on how to map a particular set of bits in LNode.flags to the node type, directive * on how to map a particular set of bits in LNode.flags to the node type.
* count, or directive starting index.
*
* For example, if you wanted to check the type of a certain node, you would mask
* node.flags with TYPE_MASK and compare it to the value for a certain node type. e.g:
*
*```ts
* if ((node.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.Element) {...}
*```
*/ */
export const enum LNodeFlags { export const enum LNodeType {
Container = 0b00, Container = 0b00,
Projection = 0b01, Projection = 0b01,
View = 0b10, View = 0b10,
Element = 0b11, Element = 0b11,
ViewOrElement = 0b10, ViewOrElement = 0b10,
SIZE_SKIP = 0b100,
SIZE_SHIFT = 2,
INDX_SHIFT = 12,
TYPE_MASK = 0b00000000000000000000000000000011,
SIZE_MASK = 0b00000000000000000000111111111100,
INDX_MASK = 0b11111111111111111111000000000000
} }
/**
* TNodeFlags corresponds to the TNode.flags property. It contains information
* on how to map a particular set of bits to the node's first directive index
* (with INDX_SHIFT) or the node's directive count (with SIZE_MASK)
*/
export const enum TNodeFlags {INDX_SHIFT = 12, SIZE_MASK = 0b00000000000000000000111111111111}
/** /**
* LNode is an internal data structure which is used for the incremental DOM algorithm. * LNode is an internal data structure which is used for the incremental DOM algorithm.
* The "L" stands for "Logical" to differentiate between `RNodes` (actual rendered DOM * The "L" stands for "Logical" to differentiate between `RNodes` (actual rendered DOM
@ -58,17 +51,8 @@ export const enum LNodeFlags {
* instructions. * instructions.
*/ */
export interface LNode { export interface LNode {
/** /** The type of the node (see LNodeFlags) */
* This number stores three values using its bits: type: LNodeType;
*
* - the type of the node (first 2 bits)
* - the number of directives on that node (next 10 bits)
* - the starting index of the node's directives in the directives array (last 20 bits).
*
* The latter two values are necessary so DI can effectively search the directives associated
* with a node without searching the whole directives array.
*/
flags: LNodeFlags;
/** /**
* The associated DOM node. Storing this allows us to: * The associated DOM node. Storing this allows us to:
@ -217,6 +201,17 @@ export interface LProjectionNode extends LNode {
* see: https://en.wikipedia.org/wiki/Flyweight_pattern for more on the Flyweight pattern * see: https://en.wikipedia.org/wiki/Flyweight_pattern for more on the Flyweight pattern
*/ */
export interface TNode { export interface TNode {
/**
* This number stores two values using its bits:
*
* - the number of directives on that node (first 12 bits)
* - the starting index of the node's directives in the directives array (last 20 bits).
*
* These two values are necessary so DI can effectively search the directives associated
* with a node without searching the whole directives array.
*/
flags: TNodeFlags;
/** The tag name associated with this node. */ /** The tag name associated with this node. */
tagName: string|null; tagName: string|null;

View File

@ -7,24 +7,23 @@
*/ */
import {assertEqual, assertNotNull} from './assert'; import {assertEqual, assertNotNull} from './assert';
import {LNode, LNodeFlags} from './interfaces/node'; import {LNode, LNodeType} from './interfaces/node';
export function assertNodeType(node: LNode, type: LNodeFlags) { export function assertNodeType(node: LNode, type: LNodeType) {
assertNotNull(node, 'should be called with a node'); assertNotNull(node, 'should be called with a node');
assertEqual(node.flags & LNodeFlags.TYPE_MASK, type, `should be a ${typeName(type)}`); assertEqual(node.type, type, `should be a ${typeName(type)}`);
} }
export function assertNodeOfPossibleTypes(node: LNode, ...types: LNodeFlags[]) { export function assertNodeOfPossibleTypes(node: LNode, ...types: LNodeType[]) {
assertNotNull(node, 'should be called with a node'); assertNotNull(node, 'should be called with a node');
const nodeType = node.flags & LNodeFlags.TYPE_MASK; const found = types.some(type => node.type === type);
const found = types.some(type => nodeType === type);
assertEqual(found, true, `Should be one of ${types.map(typeName).join(', ')}`); assertEqual(found, true, `Should be one of ${types.map(typeName).join(', ')}`);
} }
function typeName(type: LNodeFlags): string { function typeName(type: LNodeType): string {
if (type == LNodeFlags.Projection) return 'Projection'; if (type == LNodeType.Projection) return 'Projection';
if (type == LNodeFlags.Container) return 'Container'; if (type == LNodeType.Container) return 'Container';
if (type == LNodeFlags.View) return 'View'; if (type == LNodeType.View) return 'View';
if (type == LNodeFlags.Element) return 'Element'; if (type == LNodeType.Element) return 'Element';
return '<unknown>'; return '<unknown>';
} }

View File

@ -9,7 +9,7 @@
import {assertNotNull} from './assert'; import {assertNotNull} from './assert';
import {callHooks} from './hooks'; import {callHooks} from './hooks';
import {LContainer, unusedValueExportToPlacateAjd as unused1} from './interfaces/container'; import {LContainer, unusedValueExportToPlacateAjd as unused1} from './interfaces/container';
import {LContainerNode, LElementNode, LNode, LNodeFlags, LProjectionNode, LTextNode, LViewNode, unusedValueExportToPlacateAjd as unused2} from './interfaces/node'; import {LContainerNode, LElementNode, LNode, LNodeType, LProjectionNode, LTextNode, LViewNode, unusedValueExportToPlacateAjd as unused2} from './interfaces/node';
import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection'; import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection';
import {ProceduralRenderer3, RElement, RNode, RText, isProceduralRenderer, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer'; import {ProceduralRenderer3, RElement, RNode, RText, isProceduralRenderer, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer';
import {HookData, LView, LViewOrLContainer, TView, unusedValueExportToPlacateAjd as unused5} from './interfaces/view'; import {HookData, LView, LViewOrLContainer, TView, unusedValueExportToPlacateAjd as unused5} from './interfaces/view';
@ -34,8 +34,7 @@ function findNextRNodeSibling(node: LNode | null, stopNode: LNode | null): RElem
while (currentNode && currentNode !== stopNode) { while (currentNode && currentNode !== stopNode) {
let pNextOrParent = currentNode.pNextOrParent; let pNextOrParent = currentNode.pNextOrParent;
if (pNextOrParent) { if (pNextOrParent) {
let pNextOrParentType = pNextOrParent.flags & LNodeFlags.TYPE_MASK; while (pNextOrParent.type !== LNodeType.Projection) {
while (pNextOrParentType !== LNodeFlags.Projection) {
const nativeNode = findFirstRNode(pNextOrParent); const nativeNode = findFirstRNode(pNextOrParent);
if (nativeNode) { if (nativeNode) {
return nativeNode; return nativeNode;
@ -55,8 +54,8 @@ function findNextRNodeSibling(node: LNode | null, stopNode: LNode | null): RElem
const parentNode = currentNode.parent; const parentNode = currentNode.parent;
currentNode = null; currentNode = null;
if (parentNode) { if (parentNode) {
const parentType = parentNode.flags & LNodeFlags.TYPE_MASK; const parentType = parentNode.type;
if (parentType === LNodeFlags.Container || parentType === LNodeFlags.View) { if (parentType === LNodeType.Container || parentType === LNodeType.View) {
currentNode = parentNode; currentNode = parentNode;
} }
} }
@ -77,8 +76,7 @@ function getNextLNodeWithProjection(node: LNode): LNode|null {
if (pNextOrParent) { if (pNextOrParent) {
// The node is projected // The node is projected
const isLastProjectedNode = const isLastProjectedNode = pNextOrParent.type === LNodeType.Projection;
(pNextOrParent.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.Projection;
// returns pNextOrParent if we are not at the end of the list, null otherwise // returns pNextOrParent if we are not at the end of the list, null otherwise
return isLastProjectedNode ? null : pNextOrParent; return isLastProjectedNode ? null : pNextOrParent;
} }
@ -122,16 +120,15 @@ function getNextOrParentSiblingNode(initialNode: LNode, rootNode: LNode): LNode|
function findFirstRNode(rootNode: LNode): RElement|RText|null { function findFirstRNode(rootNode: LNode): RElement|RText|null {
let node: LNode|null = rootNode; let node: LNode|null = rootNode;
while (node) { while (node) {
const type = node.flags & LNodeFlags.TYPE_MASK;
let nextNode: LNode|null = null; let nextNode: LNode|null = null;
if (type === LNodeFlags.Element) { if (node.type === LNodeType.Element) {
// A LElementNode has a matching RNode in LElementNode.native // A LElementNode has a matching RNode in LElementNode.native
return (node as LElementNode).native; return (node as LElementNode).native;
} else if (type === LNodeFlags.Container) { } else if (node.type === LNodeType.Container) {
// For container look at the first node of the view next // For container look at the first node of the view next
const childContainerData: LContainer = (node as LContainerNode).data; const childContainerData: LContainer = (node as LContainerNode).data;
nextNode = childContainerData.views.length ? childContainerData.views[0].child : null; nextNode = childContainerData.views.length ? childContainerData.views[0].child : null;
} else if (type === LNodeFlags.Projection) { } else if (node.type === LNodeType.Projection) {
// For Projection look at the first projected node // For Projection look at the first projected node
nextNode = (node as LProjectionNode).data.head; nextNode = (node as LProjectionNode).data.head;
} else { } else {
@ -164,17 +161,16 @@ export function addRemoveViewFromContainer(
export function addRemoveViewFromContainer( export function addRemoveViewFromContainer(
container: LContainerNode, rootNode: LViewNode, insertMode: boolean, container: LContainerNode, rootNode: LViewNode, insertMode: boolean,
beforeNode?: RNode | null): void { beforeNode?: RNode | null): void {
ngDevMode && assertNodeType(container, LNodeFlags.Container); ngDevMode && assertNodeType(container, LNodeType.Container);
ngDevMode && assertNodeType(rootNode, LNodeFlags.View); ngDevMode && assertNodeType(rootNode, LNodeType.View);
const parentNode = container.data.renderParent; const parentNode = container.data.renderParent;
const parent = parentNode ? parentNode.native : null; const parent = parentNode ? parentNode.native : null;
let node: LNode|null = rootNode.child; let node: LNode|null = rootNode.child;
if (parent) { if (parent) {
while (node) { while (node) {
const type = node.flags & LNodeFlags.TYPE_MASK;
let nextNode: LNode|null = null; let nextNode: LNode|null = null;
const renderer = container.view.renderer; const renderer = container.view.renderer;
if (type === LNodeFlags.Element) { if (node.type === LNodeType.Element) {
if (insertMode) { if (insertMode) {
isProceduralRenderer(renderer) ? isProceduralRenderer(renderer) ?
renderer.insertBefore(parent, node.native !, beforeNode as RNode | null) : renderer.insertBefore(parent, node.native !, beforeNode as RNode | null) :
@ -184,13 +180,13 @@ export function addRemoveViewFromContainer(
parent.removeChild(node.native !); parent.removeChild(node.native !);
} }
nextNode = node.next; nextNode = node.next;
} else if (type === LNodeFlags.Container) { } else if (node.type === LNodeType.Container) {
// if we get to a container, it must be a root node of a view because we are only // if we get to a container, it must be a root node of a view because we are only
// propagating down into child views / containers and not child elements // propagating down into child views / containers and not child elements
const childContainerData: LContainer = (node as LContainerNode).data; const childContainerData: LContainer = (node as LContainerNode).data;
childContainerData.renderParent = parentNode; childContainerData.renderParent = parentNode;
nextNode = childContainerData.views.length ? childContainerData.views[0].child : null; nextNode = childContainerData.views.length ? childContainerData.views[0].child : null;
} else if (type === LNodeFlags.Projection) { } else if (node.type === LNodeType.Projection) {
nextNode = (node as LProjectionNode).data.head; nextNode = (node as LProjectionNode).data.head;
} else { } else {
nextNode = (node as LViewNode).child; nextNode = (node as LViewNode).child;
@ -347,7 +343,7 @@ export function setViewNext(view: LViewNode, next: LViewNode | null): void {
*/ */
export function getParentState(state: LViewOrLContainer, rootView: LView): LViewOrLContainer|null { export function getParentState(state: LViewOrLContainer, rootView: LView): LViewOrLContainer|null {
let node; let node;
if ((node = (state as LView) !.node) && (node.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.View) { if ((node = (state as LView) !.node) && node.type === LNodeType.View) {
// if it's an embedded view, the state needs to go up to the container, in case the // if it's an embedded view, the state needs to go up to the container, in case the
// container has a next // container has a next
return node.parent !.data as any; return node.parent !.data as any;
@ -410,7 +406,7 @@ function executeOnDestroys(view: LView): void {
* @return boolean Whether the child element should be inserted. * @return boolean Whether the child element should be inserted.
*/ */
export function canInsertNativeNode(parent: LNode, currentView: LView): boolean { export function canInsertNativeNode(parent: LNode, currentView: LView): boolean {
const parentIsElement = (parent.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.Element; const parentIsElement = parent.type === LNodeType.Element;
return parentIsElement && return parentIsElement &&
(parent.view !== currentView || parent.data === null /* Regular Element. */); (parent.view !== currentView || parent.data === null /* Regular Element. */);
@ -467,7 +463,7 @@ export function insertChild(node: LNode, currentView: LView): void {
export function appendProjectedNode( export function appendProjectedNode(
node: LElementNode | LTextNode | LContainerNode, currentParent: LViewNode | LElementNode, node: LElementNode | LTextNode | LContainerNode, currentParent: LViewNode | LElementNode,
currentView: LView): void { currentView: LView): void {
if ((node.flags & LNodeFlags.TYPE_MASK) !== LNodeFlags.Container) { if (node.type !== LNodeType.Container) {
appendChild(currentParent, (node as LElementNode | LTextNode).native, currentView); appendChild(currentParent, (node as LElementNode | LTextNode).native, currentView);
} else if (canInsertNativeNode(currentParent, currentView)) { } else if (canInsertNativeNode(currentParent, currentView)) {
// The node we are adding is a Container and we are adding it to Element which // The node we are adding is a Container and we are adding it to Element which

View File

@ -20,7 +20,7 @@ import {ReadFromInjectorFn, getOrCreateNodeInjectorForNode} from './di';
import {assertPreviousIsParent, getCurrentQueries, store} from './instructions'; import {assertPreviousIsParent, getCurrentQueries, store} from './instructions';
import {DirectiveDef, unusedValueExportToPlacateAjd as unused1} from './interfaces/definition'; import {DirectiveDef, unusedValueExportToPlacateAjd as unused1} from './interfaces/definition';
import {LInjector, unusedValueExportToPlacateAjd as unused2} from './interfaces/injector'; import {LInjector, unusedValueExportToPlacateAjd as unused2} from './interfaces/injector';
import {LContainerNode, LElementNode, LNode, LNodeFlags, TNode, unusedValueExportToPlacateAjd as unused3} from './interfaces/node'; import {LContainerNode, LElementNode, LNode, TNode, TNodeFlags, unusedValueExportToPlacateAjd as unused3} from './interfaces/node';
import {LQueries, QueryReadType, unusedValueExportToPlacateAjd as unused4} from './interfaces/query'; import {LQueries, QueryReadType, unusedValueExportToPlacateAjd as unused4} from './interfaces/query';
import {flatten} from './util'; import {flatten} from './util';
@ -195,10 +195,9 @@ function getIdxOfMatchingSelector(tNode: TNode, selector: string): number|null {
*/ */
function geIdxOfMatchingDirective(node: LNode, type: Type<any>): number|null { function geIdxOfMatchingDirective(node: LNode, type: Type<any>): number|null {
const tData = node.view.tView.data; const tData = node.view.tView.data;
const flags = node.flags; const flags = node.tNode !.flags;
for (let i = flags >> LNodeFlags.INDX_SHIFT, for (let i = flags >> TNodeFlags.INDX_SHIFT, ii = i + (flags & TNodeFlags.SIZE_MASK); i < ii;
ii = i + ((flags & LNodeFlags.SIZE_MASK) >> LNodeFlags.SIZE_SHIFT); i++) {
i < ii; i++) {
const def = tData[i] as DirectiveDef<any>; const def = tData[i] as DirectiveDef<any>;
if (def.diPublic && def.type === type) { if (def.diPublic && def.type === type) {
return i; return i;

View File

@ -128,6 +128,9 @@
{ {
"name": "createLView" "name": "createLView"
}, },
{
"name": "createTNode"
},
{ {
"name": "createTView" "name": "createTView"
}, },
@ -164,6 +167,9 @@
{ {
"name": "executeInitHooks" "name": "executeInitHooks"
}, },
{
"name": "firstTemplatePass"
},
{ {
"name": "flattenUnsubscriptionErrors" "name": "flattenUnsubscriptionErrors"
}, },

View File

@ -13,7 +13,7 @@ import {InjectFlags, bloomAdd, bloomFindPossibleInjector, getOrCreateNodeInjecto
import {NgOnChangesFeature, PublicFeature, defineDirective, directiveInject, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index'; import {NgOnChangesFeature, PublicFeature, defineDirective, directiveInject, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, createLNode, createLView, createTView, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, load, projection, projectionDef, text, textBinding} from '../../src/render3/instructions'; import {bind, container, containerRefreshEnd, containerRefreshStart, createLNode, createLView, createTView, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, load, projection, projectionDef, text, textBinding} from '../../src/render3/instructions';
import {LInjector} from '../../src/render3/interfaces/injector'; import {LInjector} from '../../src/render3/interfaces/injector';
import {LNodeFlags} from '../../src/render3/interfaces/node'; import {LNodeType} from '../../src/render3/interfaces/node';
import {LViewFlags} from '../../src/render3/interfaces/view'; import {LViewFlags} from '../../src/render3/interfaces/view';
import {ViewRef} from '../../src/render3/view_ref'; import {ViewRef} from '../../src/render3/view_ref';
@ -623,7 +623,7 @@ describe('di', () => {
createLView(-1, null !, createTView(), null, null, LViewFlags.CheckAlways); createLView(-1, null !, createTView(), null, null, LViewFlags.CheckAlways);
const oldView = enterView(contentView, null !); const oldView = enterView(contentView, null !);
try { try {
const parent = createLNode(0, LNodeFlags.Element, null, null); const parent = createLNode(0, LNodeType.Element, null, null);
// Simulate the situation where the previous parent is not initialized. // Simulate the situation where the previous parent is not initialized.
// This happens on first bootstrap because we don't init existing values // This happens on first bootstrap because we don't init existing values

View File

@ -12,6 +12,7 @@ import {getProjectAsAttrValue, isNodeMatchingSelector, isNodeMatchingSelectorWit
function testLStaticData(tagName: string, attrs: string[] | null): TNode { function testLStaticData(tagName: string, attrs: string[] | null): TNode {
return { return {
flags: 0,
tagName, tagName,
attrs, attrs,
localNames: null, localNames: null,

View File

@ -10,8 +10,8 @@ import {stringifyElement} from '@angular/platform-browser/testing/src/browser_ut
import {CreateComponentOptions} from '../../src/render3/component'; import {CreateComponentOptions} from '../../src/render3/component';
import {ComponentTemplate, ComponentType, DirectiveType, PublicFeature, defineComponent, defineDirective, renderComponent as _renderComponent, tick} from '../../src/render3/index'; import {ComponentTemplate, ComponentType, DirectiveType, PublicFeature, defineComponent, defineDirective, renderComponent as _renderComponent, tick} from '../../src/render3/index';
import {NG_HOST_SYMBOL, createLNode, createLView, renderTemplate} from '../../src/render3/instructions'; import {NG_HOST_SYMBOL, renderTemplate} from '../../src/render3/instructions';
import {LElementNode, LNodeFlags} from '../../src/render3/interfaces/node'; import {LElementNode} from '../../src/render3/interfaces/node';
import {RElement, RText, Renderer3, RendererFactory3, domRendererFactory3} from '../../src/render3/interfaces/renderer'; import {RElement, RText, Renderer3, RendererFactory3, domRendererFactory3} from '../../src/render3/interfaces/renderer';
import {getRendererFactory2} from './imported_renderer2'; import {getRendererFactory2} from './imported_renderer2';