refactor(ivy): clean up TNode not depending on LView (#28354)

PR Close #28354
This commit is contained in:
Miško Hevery 2019-01-24 23:50:12 +00:00 committed by Jason Aden
parent ef6728207b
commit 3d5a919ac5
4 changed files with 37 additions and 32 deletions

View File

@ -25,11 +25,11 @@ import {assertComponentType} from './assert';
import {LifecycleHooksFeature, createRootComponent, createRootComponentView, createRootContext} from './component';
import {getComponentDef} from './definition';
import {NodeInjector} from './di';
import {addToViewTree, createLView, createTView, createViewNode, elementCreate, locateHostElement, refreshDescendantViews} from './instructions';
import {addToViewTree, assignTViewNodeToLView, createLView, createTView, elementCreate, locateHostElement, refreshDescendantViews} from './instructions';
import {ComponentDef} from './interfaces/definition';
import {TContainerNode, TElementContainerNode, TElementNode} from './interfaces/node';
import {RNode, RendererFactory3, domRendererFactory3, isProceduralRenderer} from './interfaces/renderer';
import {HEADER_OFFSET, LView, LViewFlags, RootContext} from './interfaces/view';
import {HEADER_OFFSET, LView, LViewFlags, RootContext, TVIEW} from './interfaces/view';
import {enterView, leaveView} from './state';
import {defaultScheduler, getTNode} from './util';
import {createElementRef} from './view_engine_compatibility';
@ -242,7 +242,7 @@ export class ComponentRef<T> extends viewEngine_ComponentRef<T> {
super();
this.instance = instance;
this.hostView = this.changeDetectorRef = new RootViewRef<T>(_rootLView);
this.hostView._tViewNode = createViewNode(-1, _rootLView);
this.hostView._tViewNode = assignTViewNodeToLView(_rootLView[TVIEW], null, -1, _rootLView);
this.componentType = componentType;
}

View File

@ -205,17 +205,24 @@ export function createNodeAtIndex(
assertLessThan(adjustedIndex, lView.length, `Slot should have been initialized with null`);
lView[adjustedIndex] = native;
const previousOrParentTNode = getPreviousOrParentTNode();
const isParent = getIsParent();
let tNode = tView.data[adjustedIndex] as TNode;
if (tNode == null) {
// TODO(misko): Refactor createTNode so that it does not depend on LView.
tNode = tView.data[adjustedIndex] = createTNode(lView, type, adjustedIndex, name, attrs, null);
const parent =
isParent ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent;
// Parents cannot cross component boundaries because components will be used in multiple places,
// so it's only set if the view is the same.
const parentInSameView = parent && parent !== lView[HOST_NODE];
const tParentNode = parentInSameView ? parent as TElementNode | TContainerNode : null;
tNode = tView.data[adjustedIndex] = createTNode(tParentNode, type, adjustedIndex, name, attrs);
}
// Now link ourselves into the tree.
// We need this even if tNode exists, otherwise we might end up pointing to unexisting tNodes when
// we use i18n (especially with ICU expressions that update the DOM during the update phase).
const previousOrParentTNode = getPreviousOrParentTNode();
const isParent = getIsParent();
if (previousOrParentTNode) {
if (isParent && previousOrParentTNode.child == null &&
(tNode.parent !== null || previousOrParentTNode.type === TNodeType.View)) {
@ -236,14 +243,20 @@ export function createNodeAtIndex(
TProjectionNode & TIcuContainerNode;
}
export function createViewNode(index: number, view: LView) {
export function assignTViewNodeToLView(
tView: TView, tParentNode: TNode | null, index: number, lView: LView): TViewNode {
// View nodes are not stored in data because they can be added / removed at runtime (which
// would cause indices to change). Their TNodes are instead stored in tView.node.
if (view[TVIEW].node == null) {
view[TVIEW].node = createTNode(view, TNodeType.View, index, null, null, null) as TViewNode;
let tNode = tView.node;
if (tNode == null) {
ngDevMode && tParentNode &&
assertNodeOfPossibleTypes(tParentNode, TNodeType.Element, TNodeType.Container);
tView.node = tNode = createTNode(
tParentNode as TElementNode | TContainerNode | null, //
TNodeType.View, index, null, null) as TViewNode;
}
return view[HOST_NODE] = view[TVIEW].node as TViewNode;
return lView[HOST_NODE] = tNode as TViewNode;
}
@ -323,7 +336,7 @@ export function createEmbeddedViewAndNode<T>(
if (queries) {
lView[QUERIES] = queries.createView();
}
createViewNode(-1, lView);
assignTViewNodeToLView(tView, null, -1, lView);
if (tView.firstTemplatePass) {
tView.node !.injectorIndex = injectorIndex;
@ -1221,18 +1234,9 @@ function savePropertyDebugData(
* @returns the TNode object
*/
export function createTNode(
lView: LView, type: TNodeType, adjustedIndex: number, tagName: string | null,
attrs: TAttributes | null, tViews: TView[] | null): TNode {
const previousOrParentTNode = getPreviousOrParentTNode();
tParent: TElementNode | TContainerNode | null, type: TNodeType, adjustedIndex: number,
tagName: string | null, attrs: TAttributes | null): TNode {
ngDevMode && ngDevMode.tNode++;
const parent =
getIsParent() ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent;
// Parents cannot cross component boundaries because components will be used in multiple places,
// so it's only set if the view is the same.
const parentInSameView = parent && lView && parent !== lView[HOST_NODE];
const tParent = parentInSameView ? parent as TElementNode | TContainerNode : null;
return {
type: type,
index: adjustedIndex,
@ -1249,7 +1253,7 @@ export function createTNode(
initialInputs: undefined,
inputs: undefined,
outputs: undefined,
tViews: tViews,
tViews: null,
next: null,
child: null,
parent: tParent,
@ -2286,7 +2290,9 @@ export function embeddedViewStart(viewBlockId: number, consts: number, vars: num
viewToRender[QUERIES] = lContainer[QUERIES] !.createView();
}
createViewNode(viewBlockId, viewToRender);
const tParentNode = getIsParent() ? previousOrParentTNode :
previousOrParentTNode && previousOrParentTNode.parent;
assignTViewNodeToLView(viewToRender[TVIEW], tParentNode, viewBlockId, viewToRender);
enterView(viewToRender, viewToRender[TVIEW].node);
}
if (lContainer) {

View File

@ -380,6 +380,9 @@
{
"name": "assertTemplate"
},
{
"name": "assignTViewNodeToLView"
},
{
"name": "attachPatchData"
},
@ -482,9 +485,6 @@
{
"name": "createViewBlueprint"
},
{
"name": "createViewNode"
},
{
"name": "decreaseElementDepthCount"
},

View File

@ -12,17 +12,16 @@ import {CssSelector, CssSelectorList, NG_PROJECT_AS_ATTR_NAME, SelectorFlags,} f
import {getProjectAsAttrValue, isNodeMatchingSelectorList, isNodeMatchingSelector} from '../../src/render3/node_selector_matcher';
import {initializeStaticContext} from '../../src/render3/styling/class_and_style_bindings';
import {createTNode} from '@angular/core/src/render3/instructions';
import {getLView} from '@angular/core/src/render3/state';
function testLStaticData(tagName: string, attrs: TAttributes | null): TNode {
return createTNode(getLView(), TNodeType.Element, 0, tagName, attrs, null);
return createTNode(null, TNodeType.Element, 0, tagName, attrs);
}
describe('css selector matching', () => {
function isMatching(
tagName: string, attrsOrTNode: TAttributes | TNode | null, selector: CssSelector): boolean {
const tNode = (!attrsOrTNode || Array.isArray(attrsOrTNode)) ?
createTNode(getLView(), TNodeType.Element, 0, tagName, attrsOrTNode as TAttributes, null) :
createTNode(null, TNodeType.Element, 0, tagName, attrsOrTNode as TAttributes) :
(attrsOrTNode as TNode);
return isNodeMatchingSelector(tNode, selector, false);
}
@ -307,7 +306,7 @@ describe('css selector matching', () => {
() => {
// selector: 'div.abc'
const selector = ['div', SelectorFlags.CLASS, 'abc'];
const tNode = createTNode(getLView(), TNodeType.Element, 0, 'div', [], null);
const tNode = createTNode(null, TNodeType.Element, 0, 'div', []);
// <div> (without attrs or styling context)
expect(isMatching('div', tNode, selector)).toBeFalsy();