refactor(ivy): add TView and TContainer (#21463)

PR Close #21463
This commit is contained in:
Kara Erickson 2018-01-10 18:19:16 -08:00 committed by Alex Eagle
parent 3bcc0e6f76
commit efe545a878
11 changed files with 128 additions and 108 deletions

View File

@ -171,7 +171,8 @@ export function renderComponent<T>(
let component: T; let component: T;
const hostNode = locateHostElement(rendererFactory, opts.host || componentDef.tag); const hostNode = locateHostElement(rendererFactory, opts.host || componentDef.tag);
const oldView = enterView( const oldView = enterView(
createLView(-1, rendererFactory.createRenderer(hostNode, componentDef.rendererType), []), createLView(
-1, rendererFactory.createRenderer(hostNode, componentDef.rendererType), {data: []}),
null !); null !);
try { try {
// Create element node at index 0 in data array // Create element node at index 0 in data array

View File

@ -207,11 +207,11 @@ export function getOrCreateInjectable<T>(di: LInjector, token: Type<T>, flags?:
// 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 >> LNodeFlags.INDX_SHIFT;
const ngStaticData = node.view.ngStaticData; 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++) {
// Get the definition for the directive at this index and, if it is injectable (diPublic), // Get the definition for the directive at this index and, if it is injectable (diPublic),
// and matches the given token, return the directive instance. // and matches the given token, return the directive instance.
const directiveDef = ngStaticData[i] as TypedDirectiveDef<any>; const directiveDef = tData[i] as TypedDirectiveDef<any>;
if (directiveDef.diPublic && directiveDef.type == token) { if (directiveDef.diPublic && directiveDef.type == token) {
return node.view.data[i]; return node.view.data[i];
} }

View File

@ -14,13 +14,13 @@ import {ViewContainerRef} from '../linker/view_container_ref';
import {Type} from '../type'; import {Type} from '../type';
import {assertEqual, assertLessThan, assertNotEqual, assertNotNull} from './assert'; import {assertEqual, assertLessThan, assertNotEqual, assertNotNull} from './assert';
import {LContainer} from './interfaces/container'; import {LContainer, TContainer} from './interfaces/container';
import {LInjector} from './interfaces/injector'; import {LInjector} from './interfaces/injector';
import {CssSelector, LProjection} from './interfaces/projection'; import {CssSelector, LProjection} from './interfaces/projection';
import {LQuery, QueryReadType} from './interfaces/query'; import {LQuery, QueryReadType} from './interfaces/query';
import {LView} from './interfaces/view'; import {LView, TData, TView} from './interfaces/view';
import {LContainerNode, LElementNode, LNode, LNodeFlags, LProjectionNode, LTextNode, LViewNode, NgStaticData, TNode, TContainerNode, InitialInputData, InitialInputs, PropertyAliases, PropertyAliasValue,} from './interfaces/node'; import {LContainerNode, LElementNode, LNode, LNodeFlags, 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, processProjectedNode, removeView} from './node_manipulation'; import {appendChild, insertChild, insertView, processProjectedNode, removeView} from './node_manipulation';
import {isNodeMatchingSelector} from './node_selector_matcher'; import {isNodeMatchingSelector} from './node_selector_matcher';
@ -82,19 +82,19 @@ let previousOrParentNode: LNode;
let isParent: boolean; let isParent: boolean;
/** /**
* The current template's static data (shared between all templates of a * Static data that corresponds to the instance-specific data array on an LView.
* given type).
* *
* Each node's static data is stored at the same index that it's stored * Each node's static data is stored in tData at the same index that it's stored
* in the data array. Any nodes that do not have static data store a null * in the data array. Each directive's definition is stored here at the same index
* value to avoid a sparse array. * as its directive instance in the data array. Any nodes that do not have static
* data store a null value in tData to avoid a sparse array.
*/ */
let ngStaticData: NgStaticData; let tData: TData;
/** State of the current view being processed. */ /** State of the current view being processed. */
let currentView: LView; let currentView: LView;
// The initialization has to be after the `let`, otherwise `createLView` can't see `let`. // The initialization has to be after the `let`, otherwise `createLView` can't see `let`.
currentView = createLView(null !, null !, []); currentView = createLView(null !, null !, {data: []});
let currentQuery: LQuery|null; let currentQuery: LQuery|null;
@ -151,7 +151,7 @@ export function enterView(newView: LView, host: LElementNode | LViewNode | null)
const oldView = currentView; const oldView = currentView;
data = newView.data; data = newView.data;
bindingIndex = newView.bindingStartIndex || 0; bindingIndex = newView.bindingStartIndex || 0;
ngStaticData = newView.ngStaticData; tData = newView.tView.data;
creationMode = newView.creationMode; creationMode = newView.creationMode;
viewHookStartIndex = newView.viewHookStartIndex; viewHookStartIndex = newView.viewHookStartIndex;
@ -176,14 +176,13 @@ export function leaveView(newView: LView): void {
enterView(newView, null); enterView(newView, null);
} }
export function createLView( export function createLView(viewId: number, renderer: Renderer3, tView: TView): LView {
viewId: number, renderer: Renderer3, ngStaticData: NgStaticData): LView {
const newView = { const newView = {
parent: currentView, parent: currentView,
id: viewId, // -1 for component views id: viewId, // -1 for component views
node: null !, // until we initialize it in createNode. node: null !, // until we initialize it in createNode.
data: [], data: [],
ngStaticData: ngStaticData, tView: tView,
cleanup: null, cleanup: null,
renderer: renderer, renderer: renderer,
child: null, child: null,
@ -246,10 +245,10 @@ export function createLNode(
data[index] = node; data[index] = node;
// Every node adds a value to the static data array to avoid a sparse array // Every node adds a value to the static data array to avoid a sparse array
if (index >= ngStaticData.length) { if (index >= tData.length) {
ngStaticData[index] = null; tData[index] = null;
} else { } else {
node.tNode = ngStaticData[index] as TNode; node.tNode = tData[index] as TNode;
} }
// Now link ourselves into the tree. // Now link ourselves into the tree.
@ -300,24 +299,23 @@ export function renderTemplate<T>(
rendererFactory = providedRendererFactory; rendererFactory = providedRendererFactory;
host = createLNode( host = createLNode(
null, LNodeFlags.Element, hostNode, null, LNodeFlags.Element, hostNode,
createLView(-1, providedRendererFactory.createRenderer(null, null), [])); createLView(
-1, providedRendererFactory.createRenderer(null, null), getOrCreateTView(template)));
} }
const hostView = host.data !; const hostView = host.data !;
ngDevMode && assertNotEqual(hostView, null, 'hostView'); ngDevMode && assertNotEqual(hostView, null, 'hostView');
hostView.ngStaticData = getTemplateStatic(template);
renderComponentOrTemplate(host, hostView, context, template); renderComponentOrTemplate(host, hostView, context, template);
return host; return host;
} }
export function renderComponentOrTemplate<T>( export function renderComponentOrTemplate<T>(
node: LElementNode, lView: LView, componentOrContext: T, template?: ComponentTemplate<T>) { node: LElementNode, hostView: LView, componentOrContext: T, template?: ComponentTemplate<T>) {
const oldView = enterView(lView, node); const oldView = enterView(hostView, node);
try { try {
if (rendererFactory.begin) { if (rendererFactory.begin) {
rendererFactory.begin(); rendererFactory.begin();
} }
if (template) { if (template) {
ngStaticData = template.ngStaticData || (template.ngStaticData = [] as never);
template(componentOrContext !, creationMode); template(componentOrContext !, creationMode);
} else { } else {
// Element was stored at 0 and directive was stored at 1 in renderComponent // Element was stored at 0 and directive was stored at 1 in renderComponent
@ -328,7 +326,7 @@ export function renderComponentOrTemplate<T>(
if (rendererFactory.end) { if (rendererFactory.end) {
rendererFactory.end(); rendererFactory.end();
} }
lView.creationMode = false; hostView.creationMode = false;
leaveView(oldView); leaveView(oldView);
} }
} }
@ -450,10 +448,9 @@ export function elementStart(
let componentView: LView|null = null; let componentView: LView|null = null;
if (isHostElement) { if (isHostElement) {
const ngStaticData = getTemplateStatic(hostComponentDef !.template); const tView = getOrCreateTView(hostComponentDef !.template);
componentView = addToViewTree(createLView( componentView = addToViewTree(createLView(
-1, rendererFactory.createRenderer(native, hostComponentDef !.rendererType), -1, rendererFactory.createRenderer(native, hostComponentDef !.rendererType), tView));
ngStaticData));
} }
// 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
@ -465,7 +462,7 @@ export function elementStart(
if (node.tNode == null) { if (node.tNode == null) {
ngDevMode && assertDataInRange(index - 1); ngDevMode && assertDataInRange(index - 1);
node.tNode = ngStaticData[index] = node.tNode = tData[index] =
createTNode(name, attrs || null, null, hostComponentDef ? null : queryName); createTNode(name, attrs || null, null, hostComponentDef ? null : queryName);
} }
@ -532,14 +529,14 @@ function hack_findQueryName(
} }
/** /**
* Gets static data from a template function or creates a new static * Gets TView from a template function or creates a new TView
* data array if it doesn't already exist. * if it doesn't already exist.
* *
* @param template The template from which to get static data * @param template The template from which to get static data
* @returns NgStaticData * @returns TView
*/ */
function getTemplateStatic(template: ComponentTemplate<any>): NgStaticData { function getOrCreateTView(template: ComponentTemplate<any>): TView {
return template.ngStaticData || (template.ngStaticData = [] as never); return template.ngPrivateData || (template.ngPrivateData = { data: [] } as never);
} }
function setUpAttributes(native: RElement, attrs: string[]): void { function setUpAttributes(native: RElement, attrs: string[]): void {
@ -583,14 +580,15 @@ export function locateHostElement(
} }
/** /**
* Creates the host LNode.. * Creates the host LNode.
* *
* @param rNode Render host element. * @param rNode Render host element.
* @param def ComponentDef
*/ */
export function hostElement(rNode: RElement | null, def: ComponentDef<any>) { export function hostElement(rNode: RElement | null, def: ComponentDef<any>) {
resetApplicationState(); resetApplicationState();
createLNode( createLNode(
0, LNodeFlags.Element, rNode, createLView(-1, renderer, getTemplateStatic(def.template))); 0, LNodeFlags.Element, rNode, createLView(-1, renderer, getOrCreateTView(def.template)));
} }
@ -727,11 +725,11 @@ export function elementProperty<T>(index: number, propName: string, value: T | N
* *
* @param tagName * @param tagName
* @param attrs * @param attrs
* @param containerStatic * @param data
* @returns the TNode object * @returns the TNode object
*/ */
function createTNode( function createTNode(
tagName: string | null, attrs: string[] | null, containerStatic: (TNode | null)[][] | null, tagName: string | null, attrs: string[] | null, data: TContainer | null,
localName: string | null): TNode { localName: string | null): TNode {
return { return {
tagName: tagName, tagName: tagName,
@ -740,7 +738,7 @@ function createTNode(
initialInputs: undefined, initialInputs: undefined,
inputs: undefined, inputs: undefined,
outputs: undefined, outputs: undefined,
containerStatic: containerStatic data: data
}; };
} }
@ -757,17 +755,17 @@ function setInputsForProperty(inputs: (number | string)[], value: any): void {
/** /**
* This function consolidates all the inputs or outputs defined by directives * This function consolidates all the inputs or outputs defined by directives
* on this node into one object and stores it in ngStaticData so it can * on this node into one object and stores it in tData so it can
* be shared between all templates of this type. * be shared between all templates of this type.
* *
* @param index Index where data should be stored in ngStaticData * @param index Index where data should be stored in tData
*/ */
function generatePropertyAliases(flags: number, tNode: TNode, isInputData = false): TNode { function generatePropertyAliases(flags: number, tNode: TNode, isInputData = false): TNode {
const start = flags >> LNodeFlags.INDX_SHIFT; const start = flags >> LNodeFlags.INDX_SHIFT;
const size = (flags & LNodeFlags.SIZE_MASK) >> LNodeFlags.SIZE_SHIFT; const size = (flags & LNodeFlags.SIZE_MASK) >> LNodeFlags.SIZE_SHIFT;
for (let i = start, ii = start + size; i < ii; i++) { for (let i = start, ii = start + size; i < ii; i++) {
const directiveDef: DirectiveDef<any> = ngStaticData ![i] as DirectiveDef<any>; const directiveDef: DirectiveDef<any> = tData ![i] as DirectiveDef<any>;
const propertyAliasMap: {[publicName: string]: string} = const propertyAliasMap: {[publicName: string]: string} =
isInputData ? directiveDef.inputs : directiveDef.outputs; isInputData ? directiveDef.inputs : directiveDef.outputs;
for (let publicName in propertyAliasMap) { for (let publicName in propertyAliasMap) {
@ -946,12 +944,12 @@ export function directiveCreate<T>(
data[index] = instance = directive; data[index] = instance = directive;
if (index >= ngStaticData.length) { if (index >= tData.length) {
ngStaticData[index] = directiveDef !; tData[index] = directiveDef !;
if (queryName) { if (queryName) {
ngDevMode && assertNotNull(previousOrParentNode.tNode, 'previousOrParentNode.staticData'); ngDevMode && assertNotNull(previousOrParentNode.tNode, 'previousOrParentNode.tNode');
const nodeStaticData = previousOrParentNode !.tNode !; const tNode = previousOrParentNode !.tNode !;
(nodeStaticData.localNames || (nodeStaticData.localNames = [])).push(queryName, index); (tNode.localNames || (tNode.localNames = [])).push(queryName, index);
} }
} }
@ -960,9 +958,9 @@ export function directiveCreate<T>(
diPublic(directiveDef !); diPublic(directiveDef !);
} }
const staticData: TNode|null = previousOrParentNode.tNode !; const tNode: TNode|null = previousOrParentNode.tNode !;
if (staticData && staticData.attrs) { if (tNode && tNode.attrs) {
setInputsFromAttrs<T>(instance, directiveDef !.inputs, staticData); setInputsFromAttrs<T>(instance, directiveDef !.inputs, tNode);
} }
return instance; return instance;
} }
@ -1140,8 +1138,7 @@ export function container(
if (node.tNode == null) { if (node.tNode == null) {
// TODO(misko): implement queryName caching // TODO(misko): implement queryName caching
const queryName: string|null = hack_findQueryName(null, localRefs, ''); const queryName: string|null = hack_findQueryName(null, localRefs, '');
node.tNode = ngStaticData[index] = node.tNode = tData[index] = createTNode(tagName || null, attrs || null, [], queryName || null);
createTNode(tagName || null, attrs || null, [], queryName || null);
} }
// Containers are added to the current view tree instead of their embedded views // Containers are added to the current view tree instead of their embedded views
@ -1215,7 +1212,8 @@ export function viewStart(viewBlockId: number): boolean {
enterView((existingView as LViewNode).data, previousOrParentNode as LViewNode); enterView((existingView as LViewNode).data, previousOrParentNode as LViewNode);
} else { } else {
// When we create a new LView, we always reset the state of the instructions. // When we create a new LView, we always reset the state of the instructions.
const newView = createLView(viewBlockId, renderer, initViewStaticData(viewBlockId, container)); const newView =
createLView(viewBlockId, renderer, getOrCreateEmbeddedTView(viewBlockId, container));
enterView(newView, createLNode(null, LNodeFlags.View, null, newView)); enterView(newView, createLNode(null, LNodeFlags.View, null, newView));
lContainer.nextIndex++; lContainer.nextIndex++;
} }
@ -1224,24 +1222,24 @@ export function viewStart(viewBlockId: number): boolean {
} }
/** /**
* Initialize the static data for the active view. * Initialize the TView (e.g. static data) for the active embedded view.
* *
* Each embedded view needs to set the global ngStaticData variable to the static data for * Each embedded view needs to set the global tData variable to the static data for
* that view. Otherwise, the view's static data for a particular node would overwrite * that view. Otherwise, the view's static data for a particular node would overwrite
* the staticdata for a node in the view above it with the same index (since it's in the * the static data for a node in the view above it with the same index (since it's in the
* same template). * same template).
* *
* @param viewIndex The index of the view's static data in containerStatic * @param viewIndex The index of the TView in TContainer
* @param parent The parent container in which to look for the view's static data * @param parent The parent container in which to look for the view's static data
* @returns NgStaticData * @returns TView
*/ */
function initViewStaticData(viewIndex: number, parent: LContainerNode): NgStaticData { function getOrCreateEmbeddedTView(viewIndex: number, parent: LContainerNode): TView {
ngDevMode && assertNodeType(parent, LNodeFlags.Container); ngDevMode && assertNodeType(parent, LNodeFlags.Container);
const containerStatic = (parent !.tNode as TContainerNode).containerStatic; const tContainer = (parent !.tNode as TContainerNode).data;
if (viewIndex >= containerStatic.length || containerStatic[viewIndex] == null) { if (viewIndex >= tContainer.length || tContainer[viewIndex] == null) {
containerStatic[viewIndex] = []; tContainer[viewIndex] = { data: [] } as TView;
} }
return containerStatic[viewIndex]; return tContainer[viewIndex];
} }
/** Marks the end of the LViewNode. */ /** Marks the end of the LViewNode. */
@ -1900,8 +1898,8 @@ function valueInData<T>(data: any[], index: number, value?: T): T {
} else { } else {
// We don't store any static data for local variables, so the first time // We don't store any static data for local variables, so the first time
// we see the template, we should store as null to avoid a sparse array // we see the template, we should store as null to avoid a sparse array
if (index >= ngStaticData.length) { if (index >= tData.length) {
ngStaticData[index] = null; tData[index] = null;
} }
data[index] = value; data[index] = value;
} }

View File

@ -8,7 +8,7 @@
import {ComponentTemplate} from './definition'; import {ComponentTemplate} from './definition';
import {LElementNode, LViewNode} from './node'; import {LElementNode, LViewNode} from './node';
import {LView} from './view'; import {LView, TView} from './view';
/** The state associated with an LContainer */ /** The state associated with an LContainer */
@ -68,6 +68,24 @@ export interface LContainer {
readonly template: ComponentTemplate<any>|null; readonly template: ComponentTemplate<any>|null;
} }
/**
* The static equivalent of LContainer, used in TContainerNode.
*
* The container needs to store static data for each of its embedded views
* (TViews). Otherwise, nodes in embedded views with the same index as nodes
* in their parent views will overwrite each other, as they are in
* the same template.
*
* Each index in this array corresponds to the static data for a certain
* view. So if you had V(0) and V(1) in a container, you might have:
*
* [
* [{tagName: 'div', attrs: ...}, null], // V(0) TView
* [{tagName: 'button', attrs ...}, null] // V(1) TView
* ]
*/
export type TContainer = TView[];
// Note: This hack is necessary so we don't erroneously get a circular dependency // Note: This hack is necessary so we don't erroneously get a circular dependency
// failure based on types. // failure based on types.
export const unusedValueExportToPlacateAjd = 1; export const unusedValueExportToPlacateAjd = 1;

View File

@ -14,7 +14,7 @@ import {resolveRendererType2} from '../../view/util';
* Definition of what a template rendering function should look like. * Definition of what a template rendering function should look like.
*/ */
export type ComponentTemplate<T> = { export type ComponentTemplate<T> = {
(ctx: T, creationMode: boolean): void; ngStaticData?: never; (ctx: T, creationMode: boolean): void; ngPrivateData?: never;
}; };
export type EmbeddedTemplate<T> = (ctx: T) => void; export type EmbeddedTemplate<T> = (ctx: T) => void;

View File

@ -6,13 +6,13 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {LContainer} from './container'; import {LContainer, TContainer} from './container';
import {DirectiveDef} from './definition'; import {DirectiveDef} from './definition';
import {LInjector} from './injector'; import {LInjector} from './injector';
import {LProjection} from './projection'; import {LProjection} from './projection';
import {LQuery} from './query'; import {LQuery} from './query';
import {RComment, RElement, RText} from './renderer'; import {RComment, RElement, RText} from './renderer';
import {LView} from './view'; import {LView, TData, TView} from './view';
/** /**
@ -198,10 +198,6 @@ export interface LProjectionNode extends LNode {
readonly parent: LElementNode|LViewNode; readonly parent: LElementNode|LViewNode;
} }
/** The type of the global ngStaticData array. */
export type NgStaticData = (TNode | DirectiveDef<any>| null)[];
/** /**
* LNode binding data (flyweight) for a particular node that is shared between all templates * LNode binding data (flyweight) for a particular node that is shared between all templates
* of a specific type. * of a specific type.
@ -263,28 +259,21 @@ export interface TNode {
outputs: PropertyAliases|null|undefined; outputs: PropertyAliases|null|undefined;
/** /**
* The static data equivalent of LNode.data.
*
* If this TNode corresponds to an LContainerNode, the container will * If this TNode corresponds to an LContainerNode, the container will
* need to have nested static data for each of its embedded views. * need to store separate static data for each of its views (TContainer).
* Otherwise, nodes in embedded views with the same index as nodes
* in their parent views will overwrite each other, as they are in
* the same template.
* *
* Each index in this array corresponds to the static data for a certain * If this TNode corresponds to an LElementNode, data will be null.
* view. So if you had V(0) and V(1) in a container, you might have:
*
* [
* [{tagName: 'div', attrs: ...}, null], // V(0) ngData
* [{tagName: 'button', attrs ...}, null] // V(1) ngData
* ]
*/ */
containerStatic: (TNode|null)[][]|null; data: TContainer|null;
} }
/** Static data for an LElementNode */ /** Static data for an LElementNode */
export interface TElementNode extends TNode { containerStatic: null; } export interface TElementNode extends TNode { data: null; }
/** Static data for an LContainerNode */ /** Static data for an LContainerNode */
export interface TContainerNode extends TNode { containerStatic: (TNode|null)[][]; } export interface TContainerNode extends TNode { data: TContainer; }
/** /**
* This mapping is necessary so we can set input properties and output listeners * This mapping is necessary so we can set input properties and output listeners

View File

@ -129,19 +129,15 @@ export interface LView {
* appear in the template, starting with `bindingStartIndex`. * appear in the template, starting with `bindingStartIndex`.
* We use `bindingIndex` to internally keep track of which binding * We use `bindingIndex` to internally keep track of which binding
* is currently active. * is currently active.
*
* NOTE: We also use data == null as a marker for creationMode. We
* do this by creating ViewState in incomplete state with nodes == null
* and we initialize it on first run.
*/ */
readonly data: any[]; readonly data: any[];
/** /**
* The static data array for the current view. We need a reference to this so we * The static data for this view. We need a reference to this so we can easily walk up the
* can easily walk up the node tree in DI and get the ngStaticData array associated * node tree in DI and get the TView.data array associated with a node (where the
* with a node (where the directive defs are stored). * directive defs are stored).
*/ */
ngStaticData: (TNode|DirectiveDef<any>|null)[]; tView: TView;
} }
/** Interface necessary to work with view tree traversal */ /** Interface necessary to work with view tree traversal */
@ -152,6 +148,24 @@ export interface LViewOrLContainer {
parent: LView|null; parent: LView|null;
} }
/**
* The static data for an LView (shared between all templates of a
* given type).
*
* Stored on the template function as ngPrivateData.
*/
export interface TView { data: TData; }
/**
* Static data that corresponds to the instance-specific data array on an LView.
*
* Each node's static data is stored in tData at the same index that it's stored
* in the data array. Each directive's definition is stored here at the same index
* as its directive instance in the data array. Any nodes that do not have static
* data store a null value in tData to avoid a sparse array.
*/
export type TData = (TNode | DirectiveDef<any>| null)[];
// Note: This hack is necessary so we don't erroneously get a circular dependency // Note: This hack is necessary so we don't erroneously get a circular dependency
// failure based on types. // failure based on types.
export const unusedValueExportToPlacateAjd = 1; export const unusedValueExportToPlacateAjd = 1;

View File

@ -139,12 +139,12 @@ function getIdxOfMatchingSelector(tNode: TNode, selector: string): number|null {
* @returns Index of a found directive or null when none found. * @returns Index of a found directive or null when none found.
*/ */
function geIdxOfMatchingDirective(node: LNode, type: Type<any>): number|null { function geIdxOfMatchingDirective(node: LNode, type: Type<any>): number|null {
const ngStaticData = node.view.ngStaticData; const tData = node.view.tView.data;
const flags = node.flags; const flags = node.flags;
for (let i = flags >> LNodeFlags.INDX_SHIFT, for (let i = flags >> LNodeFlags.INDX_SHIFT,
ii = i + ((flags & LNodeFlags.SIZE_MASK) >> LNodeFlags.SIZE_SHIFT); ii = i + ((flags & LNodeFlags.SIZE_MASK) >> LNodeFlags.SIZE_SHIFT);
i < ii; i++) { i < ii; i++) {
const def = ngStaticData[i] as TypedDirectiveDef<any>; const def = tData[i] as TypedDirectiveDef<any>;
if (def.diPublic && def.type === type) { if (def.diPublic && def.type === type) {
return i; return i;
} }

View File

@ -272,7 +272,7 @@ describe('di', () => {
describe('getOrCreateNodeInjector', () => { describe('getOrCreateNodeInjector', () => {
it('should handle initial undefined state', () => { it('should handle initial undefined state', () => {
const contentView = createLView(-1, null !, []); const contentView = createLView(-1, null !, {data: []});
const oldView = enterView(contentView, null !); const oldView = enterView(contentView, null !);
try { try {
const parent = createLNode(0, LNodeFlags.Element, null, null); const parent = createLNode(0, LNodeFlags.Element, null, null);

View File

@ -604,22 +604,22 @@ describe('render3 integration test', () => {
cr(); cr();
} }
expect((Template as any).ngStaticData).toBeUndefined(); expect((Template as any).ngPrivateData).toBeUndefined();
renderToHtml(Template, {condition: true}); renderToHtml(Template, {condition: true});
const oldTemplateData = (Template as any).ngStaticData; const oldTemplateData = (Template as any).ngPrivateData;
const oldContainerData = (oldTemplateData as any)[0]; const oldContainerData = (oldTemplateData as any).data[0];
const oldElementData = oldContainerData.containerStatic[0][0]; const oldElementData = oldContainerData.data[0][0];
expect(oldContainerData).not.toBeNull(); expect(oldContainerData).not.toBeNull();
expect(oldElementData).not.toBeNull(); expect(oldElementData).not.toBeNull();
renderToHtml(Template, {condition: false}); renderToHtml(Template, {condition: false});
renderToHtml(Template, {condition: true}); renderToHtml(Template, {condition: true});
const newTemplateData = (Template as any).ngStaticData; const newTemplateData = (Template as any).ngPrivateData;
const newContainerData = (oldTemplateData as any)[0]; const newContainerData = (oldTemplateData as any).data[0];
const newElementData = oldContainerData.containerStatic[0][0]; const newElementData = oldContainerData.data[0][0];
expect(newTemplateData === oldTemplateData).toBe(true); expect(newTemplateData === oldTemplateData).toBe(true);
expect(newContainerData === oldContainerData).toBe(true); expect(newContainerData === oldContainerData).toBe(true);
expect(newElementData === oldElementData).toBe(true); expect(newElementData === oldElementData).toBe(true);

View File

@ -18,7 +18,7 @@ function testLStaticData(tagName: string, attrs: string[] | null): TNode {
initialInputs: undefined, initialInputs: undefined,
inputs: undefined, inputs: undefined,
outputs: undefined, outputs: undefined,
containerStatic: null, data: null,
}; };
} }