diff --git a/packages/core/src/render3/component.ts b/packages/core/src/render3/component.ts index eb722513cb..14c2f5d18e 100644 --- a/packages/core/src/render3/component.ts +++ b/packages/core/src/render3/component.ts @@ -9,10 +9,10 @@ import {ComponentRef, EmbeddedViewRef, Injector} from '../core'; import {assertNotNull} from './assert'; import {NG_HOST_SYMBOL, createError, createViewState, directiveCreate, elementHost, enterView, leaveView} from './instructions'; -import {LElement} from './interfaces'; +import {LElement} from './l_node'; import {ComponentDef, ComponentType} from './public_interfaces'; import {RElement, Renderer3, RendererFactory3} from './renderer'; -import {stringify} from './util'; +import {stringify, notImplemented} from './util'; @@ -71,27 +71,28 @@ export function createComponentRef( function createViewRef(detectChanges: () => void, context: T): EmbeddedViewRef { return addDestroyable( { + // TODO: rootNodes should be replaced when properly implemented rootNodes: null !, // inherited from core/ChangeDetectorRef markForCheck: () => { if (ngDevMode) { - implement(); + throw notImplemented(); } }, detach: () => { if (ngDevMode) { - implement(); + throw notImplemented(); } }, detectChanges: detectChanges, checkNoChanges: () => { if (ngDevMode) { - implement(); + throw notImplemented(); } }, reattach: () => { if (ngDevMode) { - implement(); + throw notImplemented(); } }, }, @@ -105,10 +106,6 @@ interface DestroyRef { onDestroy(cb: Function): void; } -function implement() { - throw new Error('NotImplemented'); -} - function addDestroyable(obj: any, context: C): T&DestroyRef { let destroyFn: Function[]|null = null; obj.destroyed = false; diff --git a/packages/core/src/render3/di.ts b/packages/core/src/render3/di.ts index 036e778938..f0d589e006 100644 --- a/packages/core/src/render3/di.ts +++ b/packages/core/src/render3/di.ts @@ -10,7 +10,7 @@ // correctly implementing its interfaces for backwards compatibility. import * as viewEngine from '../core'; import {BLOOM_SIZE, NG_ELEMENT_ID, getOrCreateNodeInjector} from './instructions'; -import {LContainer, LNodeFlags, LNodeInjector} from './interfaces'; +import {LContainer, LNodeFlags, LNodeInjector} from './l_node'; import {ComponentTemplate, DirectiveDef} from './public_interfaces'; import {stringify, notImplemented} from './util'; diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index febac3e1ea..1299a20620 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -10,11 +10,9 @@ import './ng_dev_mode'; import {Type} from '../core'; import {assertEqual, assertLessThan, assertNotEqual, assertNotNull} from './assert'; -import { - CSSSelector, ContainerState, InitialInputData, InitialInputs, LContainer, LContainerStatic, LElement, LNode, - LNodeFlags, LNodeInjector, LNodeStatic, LProjection, LText, LView, MinificationData, MinificationDataValue, - ProjectionState, QueryState, ViewState, NgStaticData -} from './interfaces'; +import {CssSelector, ContainerState, ProjectionState, QueryState, ViewState} from './interfaces'; +import {LText, LView, LElement, LNode, LNodeFlags, LNodeInjector, LContainer, LProjection} from './l_node'; +import {NgStaticData, LNodeStatic, LContainerStatic, InitialInputData, InitialInputs, PropertyAliases, PropertyAliasValue,} from './l_node_static'; import {assertNodeType} from './node_assert'; import {appendChild, insertChild, insertView, processProjectedNode, removeView} from './node_manipulation'; import {isNodeMatchingSelector} from './node_selector_matcher'; @@ -439,7 +437,7 @@ export function listenerCreate( // if we create LNodeStatic here, inputs must be undefined so we know they still need to be // checked mergeData.outputs = null; - mergeData = generateMinifiedData(node.flags, mergeData); + mergeData = generatePropertyAliases(node.flags, mergeData); } const outputs = mergeData.outputs; @@ -474,7 +472,7 @@ export function elementEnd() { } ngDevMode && assertNodeType(previousOrParentNode, LNodeFlags.Element); const query = previousOrParentNode.query; - query && query.add(previousOrParentNode); + query && query.addNode(previousOrParentNode); } /** @@ -525,11 +523,11 @@ export function elementProperty(index: number, propName: string, value: T | N if (staticData.inputs === undefined) { // mark inputs as checked staticData.inputs = null; - staticData = generateMinifiedData(node.flags, staticData, true); + staticData = generatePropertyAliases(node.flags, staticData, true); } const inputData = staticData.inputs; - let dataValue: MinificationDataValue|null; + let dataValue: PropertyAliasValue|null; if (inputData && (dataValue = inputData[propName])) { setInputsForProperty(dataValue, value); } else { @@ -572,22 +570,22 @@ function setInputsForProperty(inputs: (number | string)[], value: any): void { * * @param index Index where data should be stored in ngStaticData */ -function generateMinifiedData(flags: number, data: LNodeStatic, isInputData = false): LNodeStatic { +function generatePropertyAliases(flags: number, data: LNodeStatic, isInputData = false): LNodeStatic { const start = flags >> LNodeFlags.INDX_SHIFT; const size = (flags & LNodeFlags.SIZE_MASK) >> LNodeFlags.SIZE_SHIFT; for (let i = start, ii = start + size; i < ii; i++) { const directiveDef: DirectiveDef = ngStaticData ![i] as DirectiveDef; - const minifiedPropertyMap: {[minifiedKey: string]: string} = + const propertyAliasMap: {[publicName: string]: string} = isInputData ? directiveDef.inputs : directiveDef.outputs; - for (let unminifiedKey in minifiedPropertyMap) { - if (minifiedPropertyMap.hasOwnProperty(unminifiedKey)) { - const minifiedKey = minifiedPropertyMap[unminifiedKey]; - const staticDirData: MinificationData = isInputData ? (data.inputs || (data.inputs = {})) : + for (let publicName in propertyAliasMap) { + if (propertyAliasMap.hasOwnProperty(publicName)) { + const internalName = propertyAliasMap[publicName]; + const staticDirData: PropertyAliases = isInputData ? (data.inputs || (data.inputs = {})) : (data.outputs || (data.outputs = {})); - const hasProperty: boolean = staticDirData.hasOwnProperty(unminifiedKey); - hasProperty ? staticDirData[unminifiedKey].push(i, minifiedKey) : - (staticDirData[unminifiedKey] = [i, minifiedKey]); + const hasProperty: boolean = staticDirData.hasOwnProperty(publicName); + hasProperty ? staticDirData[publicName].push(i, internalName) : + (staticDirData[publicName] = [i, internalName]); } } } @@ -851,9 +849,9 @@ export function containerCreate( index: number, template?: ComponentTemplate, tagName?: string, attrs?: string[]): void { ngDevMode && assertEqual(currentView.bindingStartIndex, null, 'bindingStartIndex'); - // If the direct parent of the container is a view, its children (including its comment) + // If the direct parent of the container is a view, its views (including its comment) // will need to be added through insertView() when its parent view is being inserted. - // For now, it is marked "headless" so we know to append its children later. + // For now, it is marked "headless" so we know to append its views later. let comment = renderer.createComment(ngDevMode ? 'container' : ''); let renderParent: LElement|null = null; const currentParent = isParent ? previousOrParentNode : previousOrParentNode.parent !; @@ -866,7 +864,7 @@ export function containerCreate( } const node = createLNode(index, LNodeFlags.Container, comment, { - children: [], + views: [], nextIndex: 0, renderParent, template: template == null ? null : template, next: null, @@ -922,7 +920,7 @@ export function refreshContainerEnd(): void { const container = previousOrParentNode as LContainer; ngDevMode && assertNodeType(container, LNodeFlags.Container); const nextIndex = container.data.nextIndex; - while (nextIndex < container.data.children.length) { + while (nextIndex < container.data.views.length) { // remove extra view. removeView(container, nextIndex); } @@ -938,14 +936,14 @@ export function viewCreate(viewBlockId: number): boolean { const container = (isParent ? previousOrParentNode : previousOrParentNode.parent !) as LContainer; ngDevMode && assertNodeType(container, LNodeFlags.Container); const containerState = container.data; - const children = containerState.children; + const views = containerState.views; - const existingView: LView|false = !creationMode && containerState.nextIndex < children.length && - children[containerState.nextIndex]; + const existingView: LView|false = !creationMode && containerState.nextIndex < views.length && + views[containerState.nextIndex]; let viewUpdateMode = existingView && viewBlockId === (existingView as LView).data.id; if (viewUpdateMode) { - previousOrParentNode = children[containerState.nextIndex++]; + previousOrParentNode = views[containerState.nextIndex++]; ngDevMode && assertNodeType(previousOrParentNode, LNodeFlags.View); isParent = true; enterView((existingView as LView).data, previousOrParentNode as LView); @@ -990,8 +988,8 @@ export function viewEnd(): void { ngDevMode && assertNodeType(viewNode, LNodeFlags.View); ngDevMode && assertNodeType(container, LNodeFlags.Container); const containerState = container.data; - const previousView = containerState.nextIndex <= containerState.children.length ? - containerState.children[containerState.nextIndex - 1] as LView : + const previousView = containerState.nextIndex <= containerState.views.length ? + containerState.views[containerState.nextIndex - 1] as LView : null; const viewIdChanged = previousView == null ? true : previousView.data.id !== viewNode.data.id; @@ -1033,9 +1031,9 @@ export const refreshComponent: * each projected node belongs (it re-distributes nodes among "buckets" where each "bucket" is * backed by a selector). * - * @param {CSSSelector[]} selectors + * @param {CssSelector[]} selectors */ -export function distributeProjectedNodes(selectors?: CSSSelector[]): LNode[][] { +export function distributeProjectedNodes(selectors?: CssSelector[]): LNode[][] { const noOfNodeBuckets = selectors ? selectors.length + 1 : 1; const distributedNodes = new Array(noOfNodeBuckets); for (let i = 0; i < noOfNodeBuckets; i++) { diff --git a/packages/core/src/render3/interfaces.ts b/packages/core/src/render3/interfaces.ts index 4a6cc20037..32ae264b39 100644 --- a/packages/core/src/render3/interfaces.ts +++ b/packages/core/src/render3/interfaces.ts @@ -6,47 +6,22 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementRef, Injector, QueryList, TemplateRef, Type, ViewContainerRef} from '../core'; +import {QueryList, Type} from '../core'; import {ComponentTemplate, DirectiveDef} from './public_interfaces'; -import {RComment, RElement, RText, Renderer3} from './renderer'; +import {Renderer3} from './renderer'; +import {LNode, LView, LElement, LContainer, LText} from './l_node'; +import {LNodeStatic} from './l_node_static'; declare global { const ngDevMode: boolean; } -export const enum LNodeFlags { - Container = 0b00, - Projection = 0b01, - View = 0b10, - Element = 0b11, - ViewOrElement = 0b10, - SIZE_SKIP = 0b100, - SIZE_SHIFT = 2, - INDX_SHIFT = 12, - TYPE_MASK = 0b00000000000000000000000000000011, - SIZE_MASK = 0b00000000000000000000111111111100, - INDX_MASK = 0b11111111111111111111000000000000, -} - -/** - * NOTES: - * - * Each Array costs 70 bytes and is composed of `Array` and `(array)` object - * - `Array` javascript visible object: 32 bytes - * - `(array)` VM object where the array is actually stored in: 38 bytes - * - * Each Object cost is 24 bytes plus 8 bytes per property. - * - * For small arrays, it is more efficient to store the data as a linked list - * of items rather than small arrays. However, the array access is faster as - * shown here: https://jsperf.com/small-arrays-vs-linked-objects - */ - - /** * `ViewState` stores all of the information needed to process the instructions as - * they are invoked from the template. `ViewState` is saved when a child `View` is - * being processed and restored when the child `View` is done. + * they are invoked from the template. Each embedded view and component view has its + * own `ViewState`. When processing a particular view, we set the `currentView` to that + * `ViewState`. When that view is done processing, the `currentView` is set back to + * whatever the original `currentView` was before(the parent `ViewState`). * * Keeping separate state for each view facilities view insertion / deletion, so we * don't have to edit the data array based on which views are present. @@ -60,9 +35,12 @@ export interface ViewState { readonly parent: ViewState|null; /** - * Pointer to the `LView` node which represents the root of the view. We - * need this to be able to efficiently find the `LView` when inserting the - * view into an anchor. + * Pointer to the `LView` or `LElement` node which represents the root of the view. + * + * If `LView`, this is an embedded view of a container. We need this to be able to + * efficiently find the `LView` when inserting the view into an anchor. + * + * If `LElement`, this is the ViewState of a component. */ readonly node: LView|LElement; @@ -87,10 +65,11 @@ export interface ViewState { bindingStartIndex: number|null; /** - * When a view is destroyed, listeners need to be released - * and onDestroy callbacks need to be called. This cleanup array - * stores both listener data (in chunks of 4) and onDestroy data - * (in chunks of 2), as they'll be processed at the same time. + * When a view is destroyed, listeners need to be released and onDestroy callbacks + * need to be called. This cleanup array stores both listener data (in chunks of 4) + * and onDestroy data (in chunks of 2) for a particular view. Combining the arrays + * saves on memory (70 bytes per array) and on a few bytes of code size (for two + * separate for loops). * * If it's a listener being stored: * 1st index is: event name to remove @@ -105,25 +84,31 @@ export interface ViewState { cleanup: any[]|null; /** - * Necessary so views can traverse through their nested views + * The first ViewState or ContainerState beneath this ViewState in the hierarchy. + * + * Necessary to store this so views can traverse through their nested views * to remove listeners and call onDestroy callbacks. * - * For embedded views, we store the container rather than the - * first view to avoid managing splicing when views are added/removed. + * For embedded views, we store the ContainerState rather than the first ViewState + * to avoid managing splicing when views are added/removed. */ child: ViewState|ContainerState|null; /** - * The tail allows us to quickly add a new state to the end of the - * view list without having to propagate starting from the first child. + * The last ViewState or ContainerState beneath this ViewState in the hierarchy. + * + * The tail allows us to quickly add a new state to the end of the view list + * without having to propagate starting from the first child. */ tail: ViewState|ContainerState|null; /** - * Allows us to propagate between view states. + * The next sibling ViewState or ContainerState. * - * Embedded views already have a node.next, but it is only set for views - * in the same container. We need a way to link component views as well. + * Allows us to propagate between sibling view states that aren't in the same + * container. Embedded views already have a node.next, but it is only set for + * views in the same container. We need a way to link component views and views + * across containers as well. */ next: ViewState|ContainerState|null; @@ -152,183 +137,12 @@ export interface ViewState { ngStaticData: (LNodeStatic|DirectiveDef|null)[]; } -export interface LNodeInjector { - /** - * We need to store a reference to the injector's parent so DI can keep looking up - * the injector tree until it finds the dependency it's looking for. - */ - readonly parent: LNodeInjector|null; - - /** - * Allows access to the directives array in that node's static data and to - * the node's flags (for starting directive index and directive size). Necessary - * for DI to retrieve a directive from the data array if injector indicates - * it is there. - */ - readonly node: LElement|LContainer; - - /** - * The following bloom filter determines whether a directive is available - * on the associated node or not. This prevents us from searching the directives - * array at this level unless it's probable the directive is in it. - * - * - bf0: Check directive IDs 0-31 (IDs are % 128) - * - bf1: Check directive IDs 33-63 - * - bf2: Check directive IDs 64-95 - * - bf3: Check directive IDs 96-127 - */ - bf0: number; - bf1: number; - bf2: number; - bf3: number; - - /** - * cbf0 - cbf3 properties determine whether a directive is available through a - * parent injector. They refer to the merged values of parent bloom filters. This - * allows us to skip looking up the chain unless it's probable that directive exists - * up the chain. - */ - cbf0: number; - cbf1: number; - cbf2: number; - cbf3: number; - injector: Injector|null; - - /** Stores the TemplateRef so subsequent injections of the TemplateRef get the same instance. */ - templateRef: TemplateRef|null; - - /** Stores the ViewContainerRef so subsequent injections of the ViewContainerRef get the same - * instance. */ - viewContainerRef: ViewContainerRef|null; - - /** Stores the ElementRef so subsequent injections of the ElementRef get the same instance. */ - elementRef: ElementRef|null; -} - -/** - * LNode is an internal data structure which is used for the incremental DOM algorithm. - * - * The data structure is optimized for speed and size. - * - * In order to be fast, all subtypes of `LNode` should have the same shape. - * Because size of the `LNode` matters, many fields have multiple roles depending - * on the `LNode` subtype. - * - * NOTE: This is a private data structure and should not be exported by any of the - * instructions. - */ -export interface LNode { - /** - * This number stores three values using its bits: - * - * - 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: - * - append children to their element parents in the DOM (e.g. `parent.native.appendChild(...)`) - * - retrieve the sibling elements of text nodes whose creation / insertion has been delayed - * - mark locations where child views should be inserted (for containers) - */ - readonly native: RElement|RText|RComment|null; - - /** - * We need a reference to a node's parent so we can append the node to its parent's native - * element at the appropriate time. - */ - readonly parent: LNode|null; - - /** - * First child of the current node. - */ - child: LNode|null; - - /** - * The next sibling node. Necessary so we can propagate through the root nodes of a view - * to insert them or remove them from the DOM. - */ - next: LNode|null; - - /** - * If ViewState, then `data` contains lightDOM. - * If LContainer, then `data` contains ContainerState - */ - readonly data: ViewState|ContainerState|ProjectionState|null; - - - /** - * Each node belongs to a view. - * - * When the injector is walking up a tree, it needs access to the `directives` (part of view). - */ - readonly view: ViewState; - - /** The injector associated with this node. Necessary for DI. */ - nodeInjector: LNodeInjector|null; - - /** - * Optional `QueryState` used for tracking queries. - * - * If present the node creation/updates are reported to the `QueryState`. - */ - query: QueryState|null; - - /** - * Pointer to the corresponding LNodeStatic object, which stores static - * data about this node. - */ - staticData: LNodeStatic|null; -} - -/** - * Used for tracking queries. - */ -export interface QueryState { - /** - * Used to ask query if it should be cloned to the child element. - * - * For example in the case of deep queries the `child()` returns - * query for the child node. In case of shallow queries it returns - * `null`. - */ - child(): QueryState|null; - - /** - * Notify `QueryState` that a `LNode` has been created. - */ - add(node: LNode): void; - - /** - * Notify `QueryState` that a `LView` has been added to `LContainer`. - */ - insert(container: LContainer, view: LView, insertIndex: number): void; - - /** - * Notify `QueryState` that a `LView` has been removed from `LContainer`. - */ - remove(container: LContainer, view: LView, removeIndex: number): void; - - /** - * Add additional `QueryList` to track. - * - * @param queryList `QueryList` to update with changes. - * @param predicate Either `Type` or selector array of [key, value] predicates. - * @param descend If true the query will recursively apply to the children. - */ - track(queryList: QueryList, predicate: Type|any[], descend?: boolean): void; -} /** The state associated with an LContainer */ export interface ContainerState { /** - * The next active index in the children array to read or write to. This helps us - * keep track of where we are in the children array. + * The next active index in the views array to read or write to. This helps us + * keep track of where we are in the views array. */ nextIndex: number; @@ -351,7 +165,7 @@ export interface ContainerState { * (and don't need to be re-added) and so we can remove views from the DOM when they * are no longer required. */ - readonly children: LView[]; + readonly views: LView[]; /** * Parent Element which will contain the location where all of the Views will be @@ -361,16 +175,16 @@ export interface ContainerState { * in another `LView` which in turn is contained in another `LContainer` and therefore * it does not yet have its own parent. * - * If `renderParent` is not `null` than it may be: + * If `renderParent` is not `null` then it may be: * - same as `LContainer.parent` in which case it is just a normal container. * - different from `LContainer.parent` in which case it has been re-projected. * In other words `LContainer.parent` is logical parent where as * `ContainerState.projectedParent` is render parent. * - * When views are inserted into `LContainer` than `renderParent` is: + * When views are inserted into `LContainer` then `renderParent` is: * - `null`, we are in `LView` keep going up a hierarchy until actual * `renderParent` is found. - * - not `null`, than use the `projectedParent.native` as the `RElement` to insert + * - not `null`, then use the `projectedParent.native` as the `RElement` to insert * `LView`s into. */ renderParent: LElement|null; @@ -381,211 +195,61 @@ export interface ContainerState { readonly template: ComponentTemplate|null; } -/** - * This mapping is necessary so we can set input properties and output listeners - * properly at runtime when property names are minified. - * - * Key: original unminified input or output name - * Value: array containing minified name and related directive index - * - * The value must be an array to support inputs and outputs with the same name - * on the same node. - */ -export type MinificationData = { - [key: string]: MinificationDataValue -}; - -/** - * The value in MinificationData objects. - * - * In each array: - * Even indices: directive index - * Odd indices: minified name - * - * e.g. [0, 'change-minified'] - */ -export type MinificationDataValue = (number | string)[]; - - -/** - * This array contains information about input properties that - * need to be set once from attribute data. It's ordered by - * directive index (relative to element) so it's simple to - * look up a specific directive's initial input data. - * - * Within each sub-array: - * - * Even indices: minified input name - * Odd indices: initial value - * - * If a directive on a node does not have any input properties - * that should be set from attributes, its index is set to null - * to avoid a sparse array. - * - * e.g. [null, ['role-min', 'button']] - */ -export type InitialInputData = (InitialInputs | null)[]; - -/** - * Used by InitialInputData to store input properties - * that should be set once from attributes. - * - * Even indices: minified input name - * Odd indices: initial value - * - * e.g. ['role-min', 'button'] - */ -export type InitialInputs = string[]; - -/** The type of the global ngStaticData array. */ -export type NgStaticData = (LNodeStatic | DirectiveDef | null)[]; - -/** - * LNode binding data for a particular node that is shared between all templates - * of a specific type. - * - * If a property is: - * - Minification Data: that property's data was generated and this is it - * - Null: that property's data was already generated and nothing was found. - * - Undefined: that property's data has not yet been generated - */ -export interface LNodeStatic { - /** The tag name associated with this node. */ - tagName: string|null; - - /** - * Static attributes associated with an element. We need to store - * static attributes to support content projection with selectors. - * Attributes are stored statically because reading them from the DOM - * would be way too slow for content projection and queries. - * - * Since attrs will always be calculated first, they will never need - * to be marked undefined by other instructions. - */ - attrs: string[]|null; - - /** - * This property contains information about input properties that - * need to be set once from attribute data. - */ - initialInputs: InitialInputData|null|undefined; - - /** Input data for all directives on this node. */ - inputs: MinificationData|null|undefined; - - /** Output data for all directives on this node. */ - outputs: MinificationData|null|undefined; - - /** - * If this LNodeStatic corresponds to an LContainer, the container will - * need to have nested static data for each of its embedded views. - * 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) ngData - * [{tagName: 'button', attrs ...}, null] // V(1) ngData - * ] - */ - containerStatic: (LNodeStatic|null)[][]|null; -} - -/** Static data for an LElement */ -export interface LElementStatic extends LNodeStatic { containerStatic: null; } - -/** Static data for an LContainer */ -export interface LContainerStatic extends LNodeStatic { containerStatic: (LNodeStatic|null)[][]; } /** Interface necessary to work with view tree traversal */ export interface ViewOrContainerState { next: ViewState|ContainerState|null; child?: ViewState|ContainerState|null; - children?: LView[]; + views?: LView[]; parent: ViewState|null; } -/** LNode representing an element. */ -export interface LElement extends LNode { - /** The DOM element associated with this node. */ - readonly native: RElement; - - child: LContainer|LElement|LText|LProjection|null; - next: LContainer|LElement|LText|LProjection|null; - - /** If Component than data has ViewState (light DOM) */ - readonly data: ViewState|null; - - /** LElement nodes can be inside other LElement nodes or inside LViews. */ - readonly parent: LElement|LView; -} - -/** LNode representing a #text node. */ -export interface LText extends LNode { - /** The text node associated with this node. */ - native: RText; - child: null; - next: LContainer|LElement|LText|LProjection|null; - - /** LText nodes can be inside LElement nodes or inside LViews. */ - readonly parent: LElement|LView; - readonly data: null; -} - -/** - * Abstract node which contains root nodes of a view. - */ -export interface LView extends LNode { - readonly native: null; - child: LContainer|LElement|LText|LProjection|null; - next: LView|null; - - /** LView nodes can only be added to LContainers. */ - readonly parent: LContainer|null; - readonly data: ViewState; -} - -/** - * Abstract node container which contains other views. - */ -export interface LContainer extends LNode { - /** - * This comment node is appended to the container's parent element to mark where - * in the DOM the container's child views should be added. - * - * If the container is a root node of a view, this comment will not be appended - * until the parent view is processed. - */ - readonly native: RComment; - readonly data: ContainerState; - child: null; - next: LContainer|LElement|LText|LProjection|null; - - /** Containers can be added to elements or views. */ - readonly parent: LElement|LView|null; -} - /** * A projection state is just an array of projected nodes. * - * It would be nice if we could not need an array, but since a projected note can be + * It would be nice if we could not need an array, but since a projected node can be * re-projected, the same node can be part of more than one LProjection which makes * list approach not possible. */ export type ProjectionState = Array; -export interface LProjection extends LNode { - readonly native: null; - child: null; - next: LContainer|LElement|LText|LProjection|null; - readonly data: ProjectionState; +/** + * Used for tracking queries (e.g. ViewChild, ContentChild). + */ +export interface QueryState { + /** + * Used to ask query if it should be cloned to the child element. + * + * For example in the case of deep queries the `child()` returns + * query for the child node. In case of shallow queries it returns + * `null`. + */ + child(): QueryState|null; - /** Projections can be added to elements or views. */ - readonly parent: LElement|LView; + /** + * Notify `QueryState` that a `LNode` has been created. + */ + addNode(node: LNode): void; + + /** + * Notify `QueryState` that a `LView` has been added to `LContainer`. + */ + insertView(container: LContainer, view: LView, insertIndex: number): void; + + /** + * Notify `QueryState` that a `LView` has been removed from `LContainer`. + */ + removeView(container: LContainer, view: LView, removeIndex: number): void; + + /** + * Add additional `QueryList` to track. + * + * @param queryList `QueryList` to update with changes. + * @param predicate Either `Type` or selector array of [key, value] predicates. + * @param descend If true the query will recursively apply to the children. + */ + track(queryList: QueryList, predicate: Type|any[], descend?: boolean): void; } /** @@ -603,16 +267,16 @@ export interface LProjection extends LNode { * - class names in a selector are at the end of an array (after the attribute with the name * 'class'). */ -export type SimpleCSSSelector = string[]; +export type SimpleCssSelector = string[]; /** * A complex selector expressed as an Array where: * - element at index 0 is a selector (SimpleCSSSelector) to match * - elements at index 1..n is a selector (SimpleCSSSelector) that should NOT match */ -export type CSSSelectorWithNegations = [SimpleCSSSelector | null, SimpleCSSSelector[] | null]; +export type CssSelectorWithNegations = [SimpleCssSelector | null, SimpleCssSelector[] | null]; /** * A collection of complex selectors (CSSSelectorWithNegations) in a parsed form */ -export type CSSSelector = CSSSelectorWithNegations[]; +export type CssSelector = CssSelectorWithNegations[]; diff --git a/packages/core/src/render3/l_node.ts b/packages/core/src/render3/l_node.ts new file mode 100644 index 0000000000..ce53280ed7 --- /dev/null +++ b/packages/core/src/render3/l_node.ts @@ -0,0 +1,268 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {ElementRef, Injector, TemplateRef, ViewContainerRef} from '../core'; +import {RComment, RElement, RText} from './renderer'; +import {ViewState, ContainerState, ProjectionState, QueryState} from './interfaces'; +import {LNodeStatic} from './l_node_static'; + +/** + * LNodeFlags corresponds to the LNode.flags property. It contains information + * on how to map a particular set of bits in LNode.flags to the node type, directive + * 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 { + Container = 0b00, + Projection = 0b01, + View = 0b10, + Element = 0b11, + ViewOrElement = 0b10, + SIZE_SKIP = 0b100, + SIZE_SHIFT = 2, + INDX_SHIFT = 12, + TYPE_MASK = 0b00000000000000000000000000000011, + SIZE_MASK = 0b00000000000000000000111111111100, + INDX_MASK = 0b11111111111111111111000000000000 +} + +/** + * 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 + * node) and our logical representation of DOM nodes, `LNodes`. + * + * The data structure is optimized for speed and size. + * + * In order to be fast, all subtypes of `LNode` should have the same shape. + * Because size of the `LNode` matters, many fields have multiple roles depending + * on the `LNode` subtype. + * + * See: https://en.wikipedia.org/wiki/Inline_caching#Monomorphic_inline_caching + * + * NOTE: This is a private data structure and should not be exported by any of the + * instructions. + */ +export interface LNode { + /** + * This number stores three values using its bits: + * + * - 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: + * - append children to their element parents in the DOM (e.g. `parent.native.appendChild(...)`) + * - retrieve the sibling elements of text nodes whose creation / insertion has been delayed + * - mark locations where child views should be inserted (for containers) + */ + readonly native: RElement|RText|RComment|null; + + /** + * We need a reference to a node's parent so we can append the node to its parent's native + * element at the appropriate time. + */ + readonly parent: LNode|null; + + /** + * First child of the current node. + */ + child: LNode|null; + + /** + * The next sibling node. Necessary so we can propagate through the root nodes of a view + * to insert them or remove them from the DOM. + */ + next: LNode|null; + + /** + * If regular LElement, then `data` will be null. + * If LElement with component, then `data` contains ViewState. + * If LView, then `data` contains the ViewState. + * If LContainer, then `data` contains ContainerState. + * If LProjection, then `data` contains ProjectionState. + */ + readonly data: ViewState|ContainerState|ProjectionState|null; + + + /** + * Each node belongs to a view. + * + * When the injector is walking up a tree, it needs access to the `directives` (part of view). + */ + readonly view: ViewState; + + /** The injector associated with this node. Necessary for DI. */ + nodeInjector: LNodeInjector|null; + + /** + * Optional `QueryState` used for tracking queries. + * + * If present the node creation/updates are reported to the `QueryState`. + */ + query: QueryState|null; + + /** + * Pointer to the corresponding LNodeStatic object, which stores static + * data about this node. + */ + staticData: LNodeStatic|null; +} + + +/** LNode representing an element. */ +export interface LElement extends LNode { + /** The DOM element associated with this node. */ + readonly native: RElement; + + child: LContainer|LElement|LText|LProjection|null; + next: LContainer|LElement|LText|LProjection|null; + + /** If Component than data has ViewState (light DOM) */ + readonly data: ViewState|null; + + /** LElement nodes can be inside other LElement nodes or inside LViews. */ + readonly parent: LElement|LView; +} + +/** LNode representing a #text node. */ +export interface LText extends LNode { + /** The text node associated with this node. */ + native: RText; + child: null; + next: LContainer|LElement|LText|LProjection|null; + + /** LText nodes can be inside LElement nodes or inside LViews. */ + readonly parent: LElement|LView; + readonly data: null; +} + +/** + * Abstract node which contains root nodes of a view. + */ +export interface LView extends LNode { + readonly native: null; + child: LContainer|LElement|LText|LProjection|null; + next: LView|null; + + /** LView nodes can only be added to LContainers. */ + readonly parent: LContainer|null; + readonly data: ViewState; +} + +/** + * Abstract node container which contains other views. + */ +export interface LContainer extends LNode { + /** + * This comment node is appended to the container's parent element to mark where + * in the DOM the container's child views should be added. + * + * If the container is a root node of a view, this comment will not be appended + * until the parent view is processed. + */ + readonly native: RComment; + readonly data: ContainerState; + child: null; + next: LContainer|LElement|LText|LProjection|null; + + /** Containers can be added to elements or views. */ + readonly parent: LElement|LView|null; +} + + +export interface LProjection extends LNode { + readonly native: null; + child: null; + next: LContainer|LElement|LText|LProjection|null; + + readonly data: ProjectionState; + + /** Projections can be added to elements or views. */ + readonly parent: LElement|LView; +} + +/** + * NOTES: + * + * Each Array costs 70 bytes and is composed of `Array` and `(array)` object + * - `Array` javascript visible object: 32 bytes + * - `(array)` VM object where the array is actually stored in: 38 bytes + * + * Each Object cost is 24 bytes plus 8 bytes per property. + * + * For small arrays, it is more efficient to store the data as a linked list + * of items rather than small arrays. However, the array access is faster as + * shown here: https://jsperf.com/small-arrays-vs-linked-objects + */ + +export interface LNodeInjector { + /** + * We need to store a reference to the injector's parent so DI can keep looking up + * the injector tree until it finds the dependency it's looking for. + */ + readonly parent: LNodeInjector|null; + + /** + * Allows access to the directives array in that node's static data and to + * the node's flags (for starting directive index and directive size). Necessary + * for DI to retrieve a directive from the data array if injector indicates + * it is there. + */ + readonly node: LElement|LContainer; + + /** + * The following bloom filter determines whether a directive is available + * on the associated node or not. This prevents us from searching the directives + * array at this level unless it's probable the directive is in it. + * + * - bf0: Check directive IDs 0-31 (IDs are % 128) + * - bf1: Check directive IDs 33-63 + * - bf2: Check directive IDs 64-95 + * - bf3: Check directive IDs 96-127 + * + * See: https://en.wikipedia.org/wiki/Bloom_filter for more about bloom filters. + */ + bf0: number; + bf1: number; + bf2: number; + bf3: number; + + /** + * cbf0 - cbf3 properties determine whether a directive is available through a + * parent injector. They refer to the merged values of parent bloom filters. This + * allows us to skip looking up the chain unless it's probable that directive exists + * up the chain. + */ + cbf0: number; + cbf1: number; + cbf2: number; + cbf3: number; + injector: Injector|null; + + /** Stores the TemplateRef so subsequent injections of the TemplateRef get the same instance. */ + templateRef: TemplateRef|null; + + /** Stores the ViewContainerRef so subsequent injections of the ViewContainerRef get the same + * instance. */ + viewContainerRef: ViewContainerRef|null; + + /** Stores the ElementRef so subsequent injections of the ElementRef get the same instance. */ + elementRef: ElementRef|null; +} diff --git a/packages/core/src/render3/l_node_static.ts b/packages/core/src/render3/l_node_static.ts new file mode 100644 index 0000000000..00c7bf6287 --- /dev/null +++ b/packages/core/src/render3/l_node_static.ts @@ -0,0 +1,132 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {DirectiveDef} from './public_interfaces'; + +/** The type of the global ngStaticData array. */ +export type NgStaticData = (LNodeStatic | DirectiveDef | null)[]; + +/** + * LNode binding data (flywiehgt) for a particular node that is shared between all templates + * of a specific type. + * + * If a property is: + * - Minification Data: that property's data was generated and this is it + * - Null: that property's data was already generated and nothing was found. + * - Undefined: that property's data has not yet been generated + */ +export interface LNodeStatic { + /** The tag name associated with this node. */ + tagName: string|null; + + /** + * Static attributes associated with an element. We need to store + * static attributes to support content projection with selectors. + * Attributes are stored statically because reading them from the DOM + * would be way too slow for content projection and queries. + * + * Since attrs will always be calculated first, they will never need + * to be marked undefined by other instructions. + * + * The name of the attribute and its value alternate in the array. + * e.g. ['role', 'checkbox'] + */ + attrs: string[]|null; + + /** + * This property contains information about input properties that + * need to be set once from attribute data. + */ + initialInputs: InitialInputData|null|undefined; + + /** Input data for all directives on this node. */ + inputs: PropertyAliases|null|undefined; + + /** Output data for all directives on this node. */ + outputs: PropertyAliases|null|undefined; + + /** + * If this LNodeStatic corresponds to an LContainer, the container will + * need to have nested static data for each of its embedded views. + * 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) ngData + * [{tagName: 'button', attrs ...}, null] // V(1) ngData + * ] + */ + containerStatic: (LNodeStatic|null)[][]|null; +} + +/** Static data for an LElement */ +export interface LElementStatic extends LNodeStatic { containerStatic: null; } + +/** Static data for an LContainer */ +export interface LContainerStatic extends LNodeStatic { containerStatic: (LNodeStatic|null)[][]; } + +/** + * This mapping is necessary so we can set input properties and output listeners + * properly at runtime when property names are minified or aliased. + * + * Key: unminified / public input or output name + * Value: array containing minified / internal name and related directive index + * + * The value must be an array to support inputs and outputs with the same name + * on the same node. + */ +export type PropertyAliases = { + // This uses an object map because using the Map type would be too slow + [key: string]: PropertyAliasValue +}; + +/** + * The value in PropertyAliases. + * + * In each array: + * Even indices: directive index + * Odd indices: minified / internal name + * + * e.g. [0, 'change-minified'] + */ +export type PropertyAliasValue = (number | string)[]; + + +/** + * This array contains information about input properties that + * need to be set once from attribute data. It's ordered by + * directive index (relative to element) so it's simple to + * look up a specific directive's initial input data. + * + * Within each sub-array: + * + * Even indices: minified/internal input name + * Odd indices: initial value + * + * If a directive on a node does not have any input properties + * that should be set from attributes, its index is set to null + * to avoid a sparse array. + * + * e.g. [null, ['role-min', 'button']] + */ +export type InitialInputData = (InitialInputs | null)[]; + +/** + * Used by InitialInputData to store input properties + * that should be set once from attributes. + * + * Even indices: minified/internal input name + * Odd indices: initial value + * + * e.g. ['role-min', 'button'] + */ +export type InitialInputs = string[]; diff --git a/packages/core/src/render3/node_assert.ts b/packages/core/src/render3/node_assert.ts index 46aa989c29..54c6d79bc0 100644 --- a/packages/core/src/render3/node_assert.ts +++ b/packages/core/src/render3/node_assert.ts @@ -7,7 +7,7 @@ */ import {assertEqual, assertNotEqual} from './assert'; -import {LNode, LNodeFlags} from './interfaces'; +import {LNode, LNodeFlags} from './l_node'; export function assertNodeType(node: LNode, type: LNodeFlags) { assertNotEqual(node, null, 'node'); diff --git a/packages/core/src/render3/node_manipulation.ts b/packages/core/src/render3/node_manipulation.ts index 3c97c31061..db5485a76b 100644 --- a/packages/core/src/render3/node_manipulation.ts +++ b/packages/core/src/render3/node_manipulation.ts @@ -7,7 +7,8 @@ */ import {assertNotNull} from './assert'; -import {ContainerState, LContainer, LElement, LNode, LNodeFlags, LProjection, LText, LView, ProjectionState, ViewOrContainerState, ViewState} from './interfaces'; +import {ContainerState, ProjectionState, ViewOrContainerState, ViewState} from './interfaces'; +import {LContainer, LElement, LNode, LNodeFlags, LProjection, LText, LView} from './l_node'; import {assertNodeType} from './node_assert'; import {RComment, RElement, RNode, RText, Renderer3Fn} from './renderer'; @@ -56,10 +57,10 @@ export function findNativeParent(containerNode: LContainer): RNode|null { */ export function findBeforeNode(index: number, state: ContainerState, native: RComment): RElement| RText|RComment { - const children = state.children; + const views = state.views; // Find the node to insert in front of - return index + 1 < children.length ? - (children[index + 1].child as LText | LElement | LContainer).native : + return index + 1 < views.length ? + (views[index + 1].child as LText | LElement | LContainer).native : native; } @@ -112,7 +113,7 @@ export function addRemoveViewFromContainer( (isFnRenderer ? (renderer as Renderer3Fn).removeChild !(parent as RElement, node.native !) : parent.removeChild(node.native !)); - nextNode = childContainerData.children.length ? childContainerData.children[0].child : null; + nextNode = childContainerData.views.length ? childContainerData.views[0].child : null; } else if (type === LNodeFlags.Projection) { nextNode = (node as LProjection).data[0]; } else { @@ -150,8 +151,8 @@ export function destroyViewTree(rootView: ViewState): void { while (viewOrContainerState) { let next: ViewOrContainerState|null = null; - if (viewOrContainerState.children && viewOrContainerState.children.length) { - next = viewOrContainerState.children[0].data; + if (viewOrContainerState.views && viewOrContainerState.views.length) { + next = viewOrContainerState.views[0].data; } else if (viewOrContainerState.child) { next = viewOrContainerState.child; } else if (viewOrContainerState.next) { @@ -175,7 +176,7 @@ export function destroyViewTree(rootView: ViewState): void { /** * Inserts a view into a container. * - * This adds the view to the container's array of active children in the correct + * This adds the view to the container's array of active views in the correct * position. It also adds the view's elements to the DOM if the container isn't a * root node of another view (in that case, the view's elements will be added when * the container's parent view is added later). @@ -187,19 +188,19 @@ export function destroyViewTree(rootView: ViewState): void { */ export function insertView(container: LContainer, newView: LView, index: number): LView { const state = container.data; - const children = state.children; + const views = state.views; if (index > 0) { // This is a new view, we need to add it to the children. - setViewNext(children[index - 1], newView); + setViewNext(views[index - 1], newView); } - if (index < children.length && children[index].data.id !== newView.data.id) { + if (index < views.length && views[index].data.id !== newView.data.id) { // View ID change replace the view. - setViewNext(newView, children[index]); - children.splice(index, 0, newView); - } else if (index >= children.length) { - children.push(newView); + setViewNext(newView, views[index]); + views.splice(index, 0, newView); + } else if (index >= views.length) { + views.push(newView); } if (state.nextIndex <= index) { @@ -215,14 +216,14 @@ export function insertView(container: LContainer, newView: LView, index: number) } // Notify query that view has been inserted - container.query && container.query.insert(container, newView, index); + container.query && container.query.insertView(container, newView, index); return newView; } /** * Removes a view from a container. * - * This method splices the view from the container's array of active children. It also + * This method splices the view from the container's array of active views. It also * removes the view's elements from the DOM and conducts cleanup (e.g. removing * listeners, calling onDestroys). * @@ -231,16 +232,16 @@ export function insertView(container: LContainer, newView: LView, index: number) * @returns The removed view */ export function removeView(container: LContainer, removeIndex: number): LView { - const children = container.data.children; - const viewNode = children[removeIndex]; + const views = container.data.views; + const viewNode = views[removeIndex]; if (removeIndex > 0) { - setViewNext(children[removeIndex - 1], viewNode.next); + setViewNext(views[removeIndex - 1], viewNode.next); } - children.splice(removeIndex, 1); + views.splice(removeIndex, 1); destroyViewTree(viewNode.data); addRemoveViewFromContainer(container, viewNode, false); // Notify query that view has been removed - container.query && container.query.remove(container, viewNode, removeIndex); + container.query && container.query.removeView(container, viewNode, removeIndex); return viewNode; } @@ -401,7 +402,7 @@ export function processProjectedNode( // Assignee the final projection location in those cases. const containerState = (node as LContainer).data; containerState.renderParent = currentParent as LElement; - const views = containerState.children; + const views = containerState.views; for (let i = 0; i < views.length; i++) { addRemoveViewFromContainer(node as LContainer, views[i], true, null); } diff --git a/packages/core/src/render3/node_selector_matcher.ts b/packages/core/src/render3/node_selector_matcher.ts index f3e18417c2..99823f4e3e 100644 --- a/packages/core/src/render3/node_selector_matcher.ts +++ b/packages/core/src/render3/node_selector_matcher.ts @@ -9,7 +9,8 @@ import './ng_dev_mode'; import {assertNotNull} from './assert'; -import {CSSSelector, CSSSelectorWithNegations, LNodeStatic, SimpleCSSSelector} from './interfaces'; +import {CssSelector, CssSelectorWithNegations, SimpleCssSelector} from './interfaces'; +import {LNodeStatic} from './l_node_static'; function isCssClassMatching(nodeClassAttrVal: string, cssClassToMatch: string): boolean { const nodeClassesLen = nodeClassAttrVal.length; @@ -29,11 +30,11 @@ function isCssClassMatching(nodeClassAttrVal: string, cssClassToMatch: string): * A utility function to match an Ivy node static data against a simple CSS selector * * @param {LNodeStatic} node static data to match - * @param {SimpleCSSSelector} selector + * @param {SimpleCssSelector} selector * @returns {boolean} */ export function isNodeMatchingSimpleSelector( - lNodeStaticData: LNodeStatic, selector: SimpleCSSSelector): boolean { + lNodeStaticData: LNodeStatic, selector: SimpleCssSelector): boolean { const noOfSelectorParts = selector.length; ngDevMode && assertNotNull(selector[0], 'selector[0]'); const tagNameInSelector = selector[0]; @@ -83,7 +84,7 @@ export function isNodeMatchingSimpleSelector( } export function isNodeMatchingSelectorWithNegations( - lNodeStaticData: LNodeStatic, selector: CSSSelectorWithNegations): boolean { + lNodeStaticData: LNodeStatic, selector: CssSelectorWithNegations): boolean { const positiveSelector = selector[0]; if (positiveSelector != null && !isNodeMatchingSimpleSelector(lNodeStaticData, positiveSelector)) { @@ -105,7 +106,7 @@ export function isNodeMatchingSelectorWithNegations( } export function isNodeMatchingSelector( - lNodeStaticData: LNodeStatic, selector: CSSSelector): boolean { + lNodeStaticData: LNodeStatic, selector: CssSelector): boolean { for (let i = 0; i < selector.length; i++) { if (isNodeMatchingSelectorWithNegations(lNodeStaticData, selector[i])) { return true; diff --git a/packages/core/src/render3/query.ts b/packages/core/src/render3/query.ts index 13186e9fab..fb7f58e8f9 100644 --- a/packages/core/src/render3/query.ts +++ b/packages/core/src/render3/query.ts @@ -6,11 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ +import * as viewEngine from '../core'; import {Observable} from 'rxjs/Observable'; -import {QueryList as IQueryList, Type} from '../core'; import {assertNotNull} from './assert'; -import {LContainer, LNode, LNodeFlags, LView, QueryState} from './interfaces'; +import {QueryState} from './interfaces'; import {DirectiveDef} from '@angular/core/src/render3/public_interfaces'; +import {LContainer, LNode, LNodeFlags, LView} from './l_node'; @@ -31,7 +32,7 @@ export interface QueryPredicate { /** * If looking for directives than it contains the directive type. */ - type: Type|null; + type: viewEngine.Type|null; /** * If selector then contains the selector parts where: @@ -59,7 +60,7 @@ export class QueryState_ implements QueryState { constructor(deep?: QueryPredicate) { this.deep = deep == null ? null : deep; } - track(queryList: IQueryList, predicate: Type|any[], descend?: boolean): void { + track(queryList: viewEngine.QueryList, predicate: viewEngine.Type|any[], descend?: boolean): void { // TODO(misko): This is not right. In case of inherited state, a calling track will incorrectly // mutate parent. if (descend) { @@ -84,16 +85,16 @@ export class QueryState_ implements QueryState { } } - add(node: LNode): void { + addNode(node: LNode): void { add(this.shallow, node); add(this.deep, node); } - insert(container: LContainer, view: LView, index: number): void { + insertView(container: LContainer, view: LView, index: number): void { throw new Error('Method not implemented.'); } - remove(container: LContainer, view: LView, index: number): void { + removeView(container: LContainer, view: LView, index: number): void { throw new Error('Method not implemented.'); } } @@ -119,7 +120,7 @@ function add(predicate: QueryPredicate| null, node: LNode) { function createPredicate( previous: QueryPredicate| null, queryList: QueryList, - predicate: Type| any[]): QueryPredicate { + predicate: viewEngine.Type| any[]): QueryPredicate { const isArray = Array.isArray(predicate); const values = []; if ((queryList as any as QueryList_)._valuesTree === null) { @@ -128,13 +129,13 @@ function createPredicate( return { next: previous, list: queryList, - type: isArray ? null : predicate as Type, + type: isArray ? null : predicate as viewEngine.Type, selector: isArray ? predicate as any[] : null, values: values }; } -class QueryList_/* implements IQueryList */ { +class QueryList_/* implements viewEngine.QueryList */ { dirty: boolean = false; changes: Observable; @@ -201,8 +202,8 @@ class QueryList_/* implements IQueryList */ { // NOTE: this hack is here because IQueryList has private members and therefore // it can't be implemented only extended. -export type QueryList = IQueryList; -export const QueryList: typeof IQueryList = QueryList_ as any; +export type QueryList = viewEngine.QueryList; +export const QueryList: typeof viewEngine.QueryList = QueryList_ as any; export function refreshQuery(query: QueryList): boolean { return (query as any as QueryList_)._refresh(); diff --git a/packages/core/test/render3/di_spec.ts b/packages/core/test/render3/di_spec.ts index f31ebcebb9..465ac8b29c 100644 --- a/packages/core/test/render3/di_spec.ts +++ b/packages/core/test/render3/di_spec.ts @@ -11,7 +11,7 @@ import {ElementRef, TemplateRef, ViewContainerRef} from '@angular/core'; import {bloomFindPossibleInjector} from '../../src/render3/di'; import {C, D, E, PublicFeature, T, V, b, b2, c, defineDirective, e, inject, injectElementRef, injectTemplateRef, injectViewContainerRef, rC, rc, t, v} from '../../src/render3/index'; import {bloomAdd, createLNode, createViewState, enterView, getOrCreateNodeInjector, leaveView} from '../../src/render3/instructions'; -import {LNodeFlags, LNodeInjector} from '../../src/render3/interfaces'; +import {LNodeFlags, LNodeInjector} from '../../src/render3/l_node'; import {renderToHtml} from './render_util'; diff --git a/packages/core/test/render3/node_selector_matcher_spec.ts b/packages/core/test/render3/node_selector_matcher_spec.ts index ccb1f85f2f..138ef8ddf6 100644 --- a/packages/core/test/render3/node_selector_matcher_spec.ts +++ b/packages/core/test/render3/node_selector_matcher_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {CSSSelector, CSSSelectorWithNegations, LNodeStatic, SimpleCSSSelector} from '../../src/render3/interfaces'; +import {CssSelector, CssSelectorWithNegations, SimpleCssSelector} from '../../src/render3/interfaces'; +import {LNodeStatic} from '../../src/render3/l_node_static'; import {isNodeMatchingSelector, isNodeMatchingSelectorWithNegations, isNodeMatchingSimpleSelector} from '../../src/render3/node_selector_matcher'; function testLStaticData(tagName: string, attrs: string[] | null): LNodeStatic { @@ -25,7 +26,7 @@ describe('css selector matching', () => { describe('isNodeMatchingSimpleSelector', () => { function isMatching( - tagName: string, attrs: string[] | null, selector: SimpleCSSSelector): boolean { + tagName: string, attrs: string[] | null, selector: SimpleCssSelector): boolean { return isNodeMatchingSimpleSelector(testLStaticData(tagName, attrs), selector); } @@ -139,7 +140,7 @@ describe('css selector matching', () => { describe('isNodeMatchingSelectorWithNegations', () => { function isMatching( - tagName: string, attrs: string[] | null, selector: CSSSelectorWithNegations): boolean { + tagName: string, attrs: string[] | null, selector: CssSelectorWithNegations): boolean { return isNodeMatchingSelectorWithNegations(testLStaticData(tagName, attrs), selector); } @@ -157,7 +158,7 @@ describe('css selector matching', () => { describe('isNodeMatchingSelector', () => { - function isMatching(tagName: string, attrs: string[] | null, selector: CSSSelector): boolean { + function isMatching(tagName: string, attrs: string[] | null, selector: CssSelector): boolean { return isNodeMatchingSelector(testLStaticData(tagName, attrs), selector); } diff --git a/packages/core/test/render3/render_util.ts b/packages/core/test/render3/render_util.ts index 0a9062cd95..fdac5d9924 100644 --- a/packages/core/test/render3/render_util.ts +++ b/packages/core/test/render3/render_util.ts @@ -8,7 +8,7 @@ import {ComponentTemplate, ComponentType, PublicFeature, defineComponent, renderComponent as _renderComponent} from '../../src/render3/index'; import {NG_HOST_SYMBOL, createLNode, createViewState, renderTemplate} from '../../src/render3/instructions'; -import {LElement, LNodeFlags} from '../../src/render3/interfaces'; +import {LElement, LNodeFlags} from '../../src/render3/l_node'; import {RElement, RText, Renderer3} from '../../src/render3/renderer'; import {getRenderer2} from './imported_renderer2';