From 54303688fa28b9a57f51a48cbd064b1b70240d0a Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Tue, 13 Oct 2020 22:00:43 -0700 Subject: [PATCH] =?UTF-8?q?refactor(core):=20Consistent=20use=20of=20=20`H?= =?UTF-8?q?EADER=5FOFFSET`=20(in=20`=C9=B5=C9=B5*`=20instructions=20only)?= =?UTF-8?q?=20(#39233)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IMPORTANT: `HEADER_OFFSET` should only be refereed to the in the `ɵɵ*` instructions to translate instruction index into `LView` index. All other indexes should be in the `LView` index space and there should be no need to refer to `HEADER_OFFSET` anywhere else. PR Close #39233 --- .../size-tracking/integration-payloads.json | 2 +- packages/core/src/render3/component.ts | 15 ++-- packages/core/src/render3/component_ref.ts | 4 +- .../core/src/render3/context_discovery.ts | 2 +- packages/core/src/render3/i18n/i18n_apply.ts | 8 +- packages/core/src/render3/i18n/i18n_parse.ts | 33 ++----- .../core/src/render3/instructions/advance.ts | 4 +- .../core/src/render3/instructions/element.ts | 3 +- .../render3/instructions/element_container.ts | 3 +- .../core/src/render3/instructions/i18n.ts | 9 +- .../src/render3/instructions/lview_debug.ts | 15 ---- .../src/render3/instructions/projection.ts | 4 +- .../core/src/render3/instructions/shared.ts | 61 ++++++------- .../core/src/render3/instructions/storage.ts | 11 ++- .../core/src/render3/instructions/styling.ts | 10 +-- .../core/src/render3/instructions/template.ts | 8 +- .../core/src/render3/instructions/text.ts | 2 +- packages/core/src/render3/interfaces/view.ts | 8 +- packages/core/src/render3/pipe.ts | 41 +++++---- packages/core/src/render3/state.ts | 16 ++-- .../core/src/render3/util/discovery_utils.ts | 6 +- packages/core/src/render3/util/view_utils.ts | 14 +-- .../src/render3/view_engine_compatibility.ts | 4 +- packages/core/test/acceptance/i18n_spec.ts | 85 ++++++++++--------- .../i18n/i18n_insert_before_index_spec.ts | 84 +++++++++--------- .../core/test/render3/i18n/i18n_parse_spec.ts | 39 ++++----- packages/core/test/render3/i18n/i18n_spec.ts | 52 ++++++------ .../test/render3/instructions/shared_spec.ts | 7 +- .../test/render3/instructions/styling_spec.ts | 4 +- packages/core/test/render3/listeners_spec.ts | 5 +- packages/core/test/render3/matchers_spec.ts | 2 +- packages/core/test/render3/query_spec.ts | 55 ++++++------ packages/core/test/render3/render_util.ts | 6 +- .../test/render3/view_container_ref_spec.ts | 5 +- 34 files changed, 308 insertions(+), 319 deletions(-) diff --git a/goldens/size-tracking/integration-payloads.json b/goldens/size-tracking/integration-payloads.json index 75e91afd4d..e9db1e512f 100644 --- a/goldens/size-tracking/integration-payloads.json +++ b/goldens/size-tracking/integration-payloads.json @@ -21,7 +21,7 @@ "master": { "uncompressed": { "runtime-es2015": 1485, - "main-es2015": 147242, + "main-es2015": 146698, "polyfills-es2015": 36571 } } diff --git a/packages/core/src/render3/component.ts b/packages/core/src/render3/component.ts index 9027bb9fef..177bdae614 100644 --- a/packages/core/src/render3/component.ts +++ b/packages/core/src/render3/component.ts @@ -12,7 +12,6 @@ import {Type} from '../core'; import {Injector} from '../di/injector'; import {Sanitizer} from '../sanitization/sanitizer'; import {assertDefined, assertIndexInRange} from '../util/assert'; - import {assertComponentType} from './assert'; import {getComponentDef} from './definition'; import {diPublicInInjector, getOrCreateNodeInjectorForNode} from './di'; @@ -173,12 +172,13 @@ export function createRootComponentView( rNode: RElement|null, def: ComponentDef, rootView: LView, rendererFactory: RendererFactory3, hostRenderer: Renderer3, sanitizer?: Sanitizer|null): LView { const tView = rootView[TVIEW]; - ngDevMode && assertIndexInRange(rootView, 0 + HEADER_OFFSET); - rootView[0 + HEADER_OFFSET] = rNode; + const index = HEADER_OFFSET; + ngDevMode && assertIndexInRange(rootView, index); + rootView[index] = rNode; // '#host' is added here as we don't know the real host DOM name (we don't want to read it) and at // the same time we want to communicate the the debug `TNode` that this is a special `TNode` // representing a host element. - const tNode = getOrCreateTNode(tView, 0, TNodeType.Element, '#host', null); + const tNode: TElementNode = getOrCreateTNode(tView, index, TNodeType.Element, '#host', null); const mergedAttrs = tNode.mergedAttrs = def.hostAttrs; if (mergedAttrs !== null) { computeStaticStyling(tNode, mergedAttrs, true); @@ -196,7 +196,7 @@ export function createRootComponentView( const viewRenderer = rendererFactory.createRenderer(rNode, def); const componentView = createLView( rootView, getOrCreateTComponentView(def), null, - def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, rootView[HEADER_OFFSET], tNode, + def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, rootView[index], tNode, rendererFactory, viewRenderer, sanitizer || null, null); if (tView.firstCreatePass) { @@ -208,7 +208,7 @@ export function createRootComponentView( addToViewTree(rootView, componentView); // Store component view at node index, with node as the HOST - return rootView[HEADER_OFFSET] = componentView; + return rootView[index] = componentView; } /** @@ -237,8 +237,7 @@ export function createRootComponent( ngDevMode && assertDefined(rootTNode, 'tNode should have been already created'); if (tView.firstCreatePass && (componentDef.hostBindings !== null || componentDef.hostAttrs !== null)) { - const elementIndex = rootTNode.index - HEADER_OFFSET; - setSelectedIndex(elementIndex); + setSelectedIndex(rootTNode.index); const rootTView = rootLView[TVIEW]; addHostBindingsToExpandoInstructions(rootTView, componentDef); diff --git a/packages/core/src/render3/component_ref.ts b/packages/core/src/render3/component_ref.ts index 9aac1aacd0..b9980d0176 100644 --- a/packages/core/src/render3/component_ref.ts +++ b/packages/core/src/render3/component_ref.ts @@ -27,7 +27,7 @@ import {createLView, createTView, locateHostElement, renderView} from './instruc import {ComponentDef} from './interfaces/definition'; import {TContainerNode, TElementContainerNode, TElementNode, TNode} from './interfaces/node'; import {domRendererFactory3, RendererFactory3, RNode} from './interfaces/renderer'; -import {LView, LViewFlags, TViewType} from './interfaces/view'; +import {HEADER_OFFSET, LView, LViewFlags, TViewType} from './interfaces/view'; import {MATH_ML_NAMESPACE, SVG_NAMESPACE} from './namespaces'; import {createElementNode, writeDirectClass} from './node_manipulation'; import {extractAttrsAndClassesFromSelector, stringifyCSSSelectorList} from './node_selector_matcher'; @@ -192,7 +192,7 @@ export class ComponentFactory extends viewEngine_ComponentFactory { } } - tElementNode = getTNode(rootTView, 0) as TElementNode; + tElementNode = getTNode(rootTView, HEADER_OFFSET) as TElementNode; if (projectableNodes !== undefined) { const projection: (TNode|RNode[]|null)[] = tElementNode.projection = []; diff --git a/packages/core/src/render3/context_discovery.ts b/packages/core/src/render3/context_discovery.ts index fe28f11f06..f16dd7e48e 100644 --- a/packages/core/src/render3/context_discovery.ts +++ b/packages/core/src/render3/context_discovery.ts @@ -14,7 +14,7 @@ import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context'; import {TNode, TNodeFlags} from './interfaces/node'; import {RElement, RNode} from './interfaces/renderer'; import {CONTEXT, HEADER_OFFSET, HOST, LView, TVIEW} from './interfaces/view'; -import {getComponentLViewByIndex, getNativeByTNodeOrNull, readPatchedData, unwrapRNode} from './util/view_utils'; +import {getComponentLViewByIndex, readPatchedData, unwrapRNode} from './util/view_utils'; diff --git a/packages/core/src/render3/i18n/i18n_apply.ts b/packages/core/src/render3/i18n/i18n_apply.ts index 7b7148b998..f3b76d3ebe 100644 --- a/packages/core/src/render3/i18n/i18n_apply.ts +++ b/packages/core/src/render3/i18n/i18n_apply.ts @@ -65,7 +65,7 @@ export function setMaskBit(hasChange: boolean) { export function applyI18n(tView: TView, lView: LView, index: number) { if (changeMaskCounter > 0) { ngDevMode && assertDefined(tView, `tView should be defined`); - const tI18n = tView.data[index + HEADER_OFFSET] as TI18n | I18nUpdateOpCodes; + const tI18n = tView.data[index] as TI18n | I18nUpdateOpCodes; // When `index` points to an `ɵɵi18nAttributes` then we have an array otherwise `TI18n` const updateOpCodes: I18nUpdateOpCodes = Array.isArray(tI18n) ? tI18n as I18nUpdateOpCodes : (tI18n as TI18n).update; @@ -195,8 +195,8 @@ export function applyMutableOpCodes( // This code is used for ICU expressions only, since we don't support // directives/components in ICUs, we don't need to worry about inputs here setElementAttribute( - renderer, getNativeByIndex(elementNodeIndex - HEADER_OFFSET, lView) as RElement, null, - null, attrName, attrValue, null); + renderer, getNativeByIndex(elementNodeIndex, lView) as RElement, null, null, attrName, + attrValue, null); break; default: throw new Error(`Unable to determine the type of mutate operation for "${opCode}"`); @@ -281,7 +281,7 @@ export function applyUpdateOpCodes( const propName = updateOpCodes[++j] as string; const sanitizeFn = updateOpCodes[++j] as SanitizerFn | null; const tNodeOrTagName = tView.data[nodeIndex] as TNode | string; - ngDevMode && assertDefined(tNodeOrTagName, 'Expecting TNode or string'); + ngDevMode && assertDefined(tNodeOrTagName, 'Experting TNode or string'); if (typeof tNodeOrTagName === 'string') { // IF we don't have a `TNode`, then we are an element in ICU (as ICU content does // not have TNode), in which case we know that there are no directives, and hence diff --git a/packages/core/src/render3/i18n/i18n_parse.ts b/packages/core/src/render3/i18n/i18n_parse.ts index ec39a9ecab..49f9e2c8a1 100644 --- a/packages/core/src/render3/i18n/i18n_parse.ts +++ b/packages/core/src/render3/i18n/i18n_parse.ts @@ -132,7 +132,7 @@ export function i18nStartFirstCreatePass( } } - tView.data[index + HEADER_OFFSET] = { + tView.data[index] = { create: createOpCodes, update: updateOpCodes, }; @@ -247,11 +247,11 @@ export function i18nAttributesFirstPass( // Even indexes are text (including bindings) const hasBinding = !!value.match(BINDING_REGEXP); if (hasBinding) { - if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) { + if (tView.firstCreatePass && tView.data[index] === null) { generateBindingUpdateOpCodes(updateOpCodes, value, previousElementIndex, attrName); } } else { - const tNode = getTNode(tView, previousElementIndex - HEADER_OFFSET); + const tNode = getTNode(tView, previousElementIndex); // Set attributes for Elements only, for other types (like ElementContainer), // only set inputs below if (tNode.type & TNodeType.AnyRNode) { @@ -262,9 +262,7 @@ export function i18nAttributesFirstPass( if (dataValue) { setInputsForProperty(tView, lView, dataValue, attrName, value); if (ngDevMode) { - const element = - getNativeByIndex(previousElementIndex - HEADER_OFFSET, lView) as RElement | - RComment; + const element = getNativeByIndex(previousElementIndex, lView) as RElement | RComment; setNgReflectProperties(lView, element, tNode.type, dataValue, value); } } @@ -273,8 +271,8 @@ export function i18nAttributesFirstPass( } } - if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) { - tView.data[index + HEADER_OFFSET] = updateOpCodes; + if (tView.firstCreatePass && tView.data[index] === null) { + tView.data[index] = updateOpCodes; } } @@ -329,25 +327,6 @@ export function generateBindingUpdateOpCodes( return mask; } -function getBindingMask(icuExpression: IcuExpression, mask = 0): number { - mask = mask | toMaskBit(icuExpression.mainBinding); - let match; - for (let i = 0; i < icuExpression.values.length; i++) { - const valueArr = icuExpression.values[i]; - for (let j = 0; j < valueArr.length; j++) { - const value = valueArr[j]; - if (typeof value === 'string') { - while (match = BINDING_REGEXP.exec(value)) { - mask = mask | toMaskBit(parseInt(match[1], 10)); - } - } else { - mask = getBindingMask(value as IcuExpression, mask); - } - } - } - return mask; -} - /** * Convert binding index to mask bit. diff --git a/packages/core/src/render3/instructions/advance.ts b/packages/core/src/render3/instructions/advance.ts index 0aafa53159..fd06bdfbb7 100644 --- a/packages/core/src/render3/instructions/advance.ts +++ b/packages/core/src/render3/instructions/advance.ts @@ -8,7 +8,7 @@ import {assertGreaterThan} from '../../util/assert'; import {assertIndexInDeclRange} from '../assert'; import {executeCheckHooks, executeInitAndCheckHooks} from '../hooks'; -import {FLAGS, HEADER_OFFSET, InitPhaseState, LView, LViewFlags, TView} from '../interfaces/view'; +import {FLAGS, InitPhaseState, LView, LViewFlags, TView} from '../interfaces/view'; import {getLView, getSelectedIndex, getTView, isInCheckNoChangesMode, setSelectedIndex} from '../state'; @@ -42,7 +42,7 @@ export function ɵɵadvance(delta: number): void { export function selectIndexInternal( tView: TView, lView: LView, index: number, checkNoChangesMode: boolean) { - ngDevMode && assertIndexInDeclRange(lView, index + HEADER_OFFSET); + ngDevMode && assertIndexInDeclRange(lView, index); // Flush the initial hooks for elements in the view that have been added up to this point. // PERF WARNING: do NOT extract this to a separate function without running benchmarks diff --git a/packages/core/src/render3/instructions/element.ts b/packages/core/src/render3/instructions/element.ts index 4bfbe80d6c..b03b4fdbf8 100644 --- a/packages/core/src/render3/instructions/element.ts +++ b/packages/core/src/render3/instructions/element.ts @@ -83,7 +83,8 @@ export function ɵɵelementStart( const renderer = lView[RENDERER]; const native = lView[adjustedIndex] = createElementNode(renderer, name, getNamespace()); const tNode = tView.firstCreatePass ? - elementStartFirstCreatePass(index, tView, lView, native, name, attrsIndex, localRefsIndex) : + elementStartFirstCreatePass( + adjustedIndex, tView, lView, native, name, attrsIndex, localRefsIndex) : tView.data[adjustedIndex] as TElementNode; setCurrentTNode(tNode, true); diff --git a/packages/core/src/render3/instructions/element_container.ts b/packages/core/src/render3/instructions/element_container.ts index f8288a0d0b..cc550ae659 100644 --- a/packages/core/src/render3/instructions/element_container.ts +++ b/packages/core/src/render3/instructions/element_container.ts @@ -72,7 +72,8 @@ export function ɵɵelementContainerStart( 'element containers should be created before any bindings'); const tNode = tView.firstCreatePass ? - elementContainerStartFirstCreatePass(index, tView, lView, attrsIndex, localRefsIndex) : + elementContainerStartFirstCreatePass( + adjustedIndex, tView, lView, attrsIndex, localRefsIndex) : tView.data[adjustedIndex] as TElementContainerNode; setCurrentTNode(tNode, true); diff --git a/packages/core/src/render3/instructions/i18n.ts b/packages/core/src/render3/instructions/i18n.ts index a8319b08de..8557470809 100644 --- a/packages/core/src/render3/instructions/i18n.ts +++ b/packages/core/src/render3/instructions/i18n.ts @@ -49,15 +49,16 @@ export function ɵɵi18nStart( index: number, messageIndex: number, subTemplateIndex: number = -1): void { const tView = getTView(); const lView = getLView(); + const adjustedIndex = HEADER_OFFSET + index; ngDevMode && assertDefined(tView, `tView should be defined`); const message = getConstant(tView.consts, messageIndex)!; const parentTNode = getCurrentParentTNode() as TElementNode | null; if (tView.firstCreatePass) { i18nStartFirstCreatePass( - tView, parentTNode === null ? 0 : parentTNode.index, lView, index, message, + tView, parentTNode === null ? 0 : parentTNode.index, lView, adjustedIndex, message, subTemplateIndex); } - const tI18n = tView.data[HEADER_OFFSET + index] as TI18n; + const tI18n = tView.data[adjustedIndex] as TI18n; const sameViewParentTNode = parentTNode === lView[T_HOST] ? null : parentTNode; const parentRNode = getClosestRElement(tView, sameViewParentTNode, lView); // If `parentTNode` is an `ElementContainer` than it has ``. @@ -125,7 +126,7 @@ export function ɵɵi18nAttributes(index: number, attrsIndex: number): void { const tView = getTView(); ngDevMode && assertDefined(tView, `tView should be defined`); const attrs = getConstant(tView.consts, attrsIndex)!; - i18nAttributesFirstPass(lView, tView, index, attrs); + i18nAttributesFirstPass(lView, tView, index + HEADER_OFFSET, attrs); } @@ -154,7 +155,7 @@ export function ɵɵi18nExp(value: T): typeof ɵɵi18nExp { * @codeGenApi */ export function ɵɵi18nApply(index: number) { - applyI18n(getTView(), getLView(), index); + applyI18n(getTView(), getLView(), index + HEADER_OFFSET); } /** diff --git a/packages/core/src/render3/instructions/lview_debug.ts b/packages/core/src/render3/instructions/lview_debug.ts index 421a6cd04d..ed2ed31987 100644 --- a/packages/core/src/render3/instructions/lview_debug.ts +++ b/packages/core/src/render3/instructions/lview_debug.ts @@ -676,18 +676,3 @@ export class LContainerDebug implements ILContainerDebug { return toDebug(this._raw_lContainer[NEXT]); } } - -/** - * Return an `LView` value if found. - * - * @param value `LView` if any - */ -export function readLViewValue(value: any): LView|null { - while (Array.isArray(value)) { - // This check is not quite right, as it does not take into account `StylingContext` - // This is why it is in debug, not in util.ts - if (value.length >= HEADER_OFFSET - 1) return value as LView; - value = value[HOST]; - } - return null; -} diff --git a/packages/core/src/render3/instructions/projection.ts b/packages/core/src/render3/instructions/projection.ts index 4b4f56d38c..612534414b 100644 --- a/packages/core/src/render3/instructions/projection.ts +++ b/packages/core/src/render3/instructions/projection.ts @@ -8,7 +8,7 @@ import {newArray} from '../../util/array_utils'; import {TAttributes, TElementNode, TNode, TNodeFlags, TNodeType} from '../interfaces/node'; import {ProjectionSlots} from '../interfaces/projection'; -import {DECLARATION_COMPONENT_VIEW, T_HOST} from '../interfaces/view'; +import {DECLARATION_COMPONENT_VIEW, HEADER_OFFSET, T_HOST} from '../interfaces/view'; import {applyProjection} from '../node_manipulation'; import {getProjectAsAttrValue, isNodeMatchingSelectorList, isSelectorInSelectorList} from '../node_selector_matcher'; import {getLView, getTView, setCurrentTNodeAsNotParent} from '../state'; @@ -120,7 +120,7 @@ export function ɵɵprojection( const lView = getLView(); const tView = getTView(); const tProjectionNode = - getOrCreateTNode(tView, nodeIndex, TNodeType.Projection, null, attrs || null); + getOrCreateTNode(tView, HEADER_OFFSET + nodeIndex, TNodeType.Projection, null, attrs || null); // We can't use viewData[HOST_NODE] because projection nodes can be nested in embedded views. if (tProjectionNode.projection === null) tProjectionNode.projection = selectorIndex; diff --git a/packages/core/src/render3/instructions/shared.ts b/packages/core/src/render3/instructions/shared.ts index 2ea07375b8..53a38ab907 100644 --- a/packages/core/src/render3/instructions/shared.ts +++ b/packages/core/src/render3/instructions/shared.ts @@ -12,7 +12,7 @@ import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, SchemaMetadata} from '../../me import {ViewEncapsulation} from '../../metadata/view'; import {validateAgainstEventAttributes, validateAgainstEventProperties} from '../../sanitization/sanitization'; import {Sanitizer} from '../../sanitization/sanitizer'; -import {assertDefined, assertDomNode, assertEqual, assertGreaterThan, assertIndexInRange, assertLessThan, assertNotEqual, assertNotSame, assertSame, assertString} from '../../util/assert'; +import {assertDefined, assertDomNode, assertEqual, assertGreaterThan, assertGreaterThanOrEqual, assertIndexInRange, assertLessThan, assertNotEqual, assertNotSame, assertSame, assertString} from '../../util/assert'; import {createNamedArrayType} from '../../util/named_array_type'; import {initNgDevMode} from '../../util/ng_dev_mode'; import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../../util/ng_reflect'; @@ -214,12 +214,14 @@ export function getOrCreateTNode( export function getOrCreateTNode( tView: TView, index: number, type: TNodeType, name: string|null, attrs: TAttributes|null): TElementNode&TContainerNode&TElementContainerNode&TProjectionNode&TIcuContainerNode { + ngDevMode && index !== 0 && // 0 are bogus nodes and they are OK. See `createContainerRef` in + // `view_engine_compatibility` for additional context. + assertGreaterThanOrEqual(index, HEADER_OFFSET, 'TNodes can\'t be in the LView header.'); // Keep this function short, so that the VM will inline it. ngDevMode && assertPureTNodeType(type); - const adjustedIndex = index + HEADER_OFFSET; - let tNode = tView.data[adjustedIndex] as TNode; + let tNode = tView.data[index] as TNode; if (tNode === null) { - tNode = createTNodeAtIndex(tView, adjustedIndex, type, name, attrs); + tNode = createTNodeAtIndex(tView, index, type, name, attrs); if (isInI18nBlock()) { // If we are in i18n block then all elements should be pre declared through `Placeholder` // See `TNodeType.Placeholder` and `LFrame.inI18n` for more context. @@ -234,7 +236,7 @@ export function getOrCreateTNode( const parent = getCurrentParentTNode(); tNode.injectorIndex = parent === null ? -1 : parent.injectorIndex; ngDevMode && assertTNodeForTView(tNode, tView); - ngDevMode && assertEqual(index + HEADER_OFFSET, tNode.index, 'Expecting same index'); + ngDevMode && assertEqual(index, tNode.index, 'Expecting same index'); } setCurrentTNode(tNode, true); return tNode as TElementNode & TContainerNode & TElementContainerNode & TProjectionNode & @@ -242,14 +244,13 @@ export function getOrCreateTNode( } export function createTNodeAtIndex( - tView: TView, adjustedIndex: number, type: TNodeType, name: string|null, - attrs: TAttributes|null) { + tView: TView, index: number, type: TNodeType, name: string|null, attrs: TAttributes|null) { const currentTNode = getCurrentTNodePlaceholderOk(); const isParent = isCurrentTNodeParent(); const parent = isParent ? currentTNode : currentTNode && currentTNode.parent; // Parents cannot cross component boundaries because components will be used in multiple places. - const tNode = tView.data[adjustedIndex] = - createTNode(tView, parent as TElementNode | TContainerNode, type, adjustedIndex, name, attrs); + const tNode = tView.data[index] = + createTNode(tView, parent as TElementNode | TContainerNode, type, index, name, attrs); // Assign a pointer to the first child node of a given view. The first node is not always the one // at index 0, in case of i18n, index 0 can be the instruction `i18nStart` and the first node has // the index 1 or more, so we can't just check node index. @@ -546,7 +547,7 @@ function executeTemplate( if (rf & RenderFlags.Update && lView.length > HEADER_OFFSET) { // When we're updating, inherently select 0 so we don't // have to generate that instruction for most update blocks. - selectIndexInternal(tView, lView, 0, isInCheckNoChangesMode()); + selectIndexInternal(tView, lView, HEADER_OFFSET, isInCheckNoChangesMode()); } templateFn(rf, context); } finally { @@ -810,7 +811,7 @@ export function storeCleanupWithContext( * @param tView `TView` to which this `TNode` belongs (used only in `ngDevMode`) * @param tParent Parent `TNode` * @param type The type of the node - * @param adjustedIndex The index of the TNode in TView.data, adjusted for HEADER_OFFSET + * @param index The index of the TNode in TView.data, adjusted for HEADER_OFFSET * @param tagName The tag name of the node * @param attrs The attributes defined on this node * @param tViews Any TViews attached to this node @@ -818,25 +819,28 @@ export function storeCleanupWithContext( */ export function createTNode( tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType.Container, - adjustedIndex: number, tagName: string|null, attrs: TAttributes|null): TContainerNode; + index: number, tagName: string|null, attrs: TAttributes|null): TContainerNode; export function createTNode( tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType.Element|TNodeType.Text, - adjustedIndex: number, tagName: string|null, attrs: TAttributes|null): TElementNode; + index: number, tagName: string|null, attrs: TAttributes|null): TElementNode; export function createTNode( tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType.ElementContainer, - adjustedIndex: number, tagName: string|null, attrs: TAttributes|null): TElementContainerNode; + index: number, tagName: string|null, attrs: TAttributes|null): TElementContainerNode; export function createTNode( - tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType.Icu, - adjustedIndex: number, tagName: string|null, attrs: TAttributes|null): TIcuContainerNode; + tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType.Icu, index: number, + tagName: string|null, attrs: TAttributes|null): TIcuContainerNode; export function createTNode( tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType.Projection, - adjustedIndex: number, tagName: string|null, attrs: TAttributes|null): TProjectionNode; + index: number, tagName: string|null, attrs: TAttributes|null): TProjectionNode; export function createTNode( - tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType, adjustedIndex: number, + tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType, index: number, tagName: string|null, attrs: TAttributes|null): TNode; export function createTNode( - tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType, adjustedIndex: number, + tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType, index: number, value: string|null, attrs: TAttributes|null): TNode { + ngDevMode && index !== 0 && // 0 are bogus nodes and they are OK. See `createContainerRef` in + // `view_engine_compatibility` for additional context. + assertGreaterThanOrEqual(index, HEADER_OFFSET, 'TNodes can\'t be in the LView header.'); ngDevMode && assertNotSame(attrs, undefined, '\'undefined\' is not valid value for \'attrs\''); ngDevMode && ngDevMode.tNode++; ngDevMode && tParent && assertTNodeForTView(tParent, tView); @@ -845,7 +849,7 @@ export function createTNode( new TNodeDebug( tView, // tView_: TView type, // type: TNodeType - adjustedIndex, // index: number + index, // index: number null, // insertBeforeIndex: null|-1|number|number[] injectorIndex, // injectorIndex: number -1, // directiveStart: number @@ -877,10 +881,10 @@ export function createTNode( 0 as any, // styleBindings: TStylingRange; ) : { - type: type, - index: adjustedIndex, + type, + index, insertBeforeIndex: null, - injectorIndex: injectorIndex, + injectorIndex, directiveStart: -1, directiveEnd: -1, directiveStylingLast: -1, @@ -1213,13 +1217,12 @@ export function resolveDirectives( // We will push the actual hook function into this array later during dir instantiation. // We cannot do it now because we must ensure hooks are registered in the same // order that directives are created (i.e. injection order). - (tView.preOrderHooks || (tView.preOrderHooks = [])).push(tNode.index - HEADER_OFFSET); + (tView.preOrderHooks || (tView.preOrderHooks = [])).push(tNode.index); preOrderHooksFound = true; } if (!preOrderCheckHooksFound && (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngDoCheck)) { - (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])) - .push(tNode.index - HEADER_OFFSET); + (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(tNode.index); preOrderCheckHooksFound = true; } @@ -1325,7 +1328,7 @@ function invokeDirectivesHostBindings(tView: TView, lView: LView, tNode: TNode) const end = tNode.directiveEnd; const expando = tView.expandoInstructions!; const firstCreatePass = tView.firstCreatePass; - const elementIndex = tNode.index - HEADER_OFFSET; + const elementIndex = tNode.index; const currentDirectiveIndex = getCurrentDirectiveIndex(); try { setSelectedIndex(elementIndex); @@ -1373,7 +1376,7 @@ export function generateExpandoInstructionBlock( // Important: In JS `-x` and `0-x` is not the same! If `x===0` then `-x` will produce `-0` which // requires non standard math arithmetic and it can prevent VM optimizations. // `0-0` will always produce `0` and will not cause a potential deoptimization in VM. - const elementIndex = HEADER_OFFSET - tNode.index; + const elementIndex = 0 - tNode.index; const providerStartIndex = tNode.providerIndexes & TNodeProviderIndexes.ProvidersStartIndexMask; const providerCount = tView.data.length - providerStartIndex; (tView.expandoInstructions || (tView.expandoInstructions = [])) @@ -2087,7 +2090,7 @@ export function setInputsForProperty( export function textBindingInternal(lView: LView, index: number, value: string): void { ngDevMode && assertString(value, 'Value should be a string'); ngDevMode && assertNotSame(value, NO_CHANGE as any, 'value should not be NO_CHANGE'); - ngDevMode && assertIndexInRange(lView, index + HEADER_OFFSET); + ngDevMode && assertIndexInRange(lView, index); const element = getNativeByIndex(index, lView) as any as RText; ngDevMode && assertDefined(element, 'native element should exist'); updateTextNode(lView[RENDERER], element, value); diff --git a/packages/core/src/render3/instructions/storage.ts b/packages/core/src/render3/instructions/storage.ts index ea1cf2fd7a..676ee4d928 100644 --- a/packages/core/src/render3/instructions/storage.ts +++ b/packages/core/src/render3/instructions/storage.ts @@ -14,12 +14,11 @@ import {load} from '../util/view_utils'; export function store(tView: TView, lView: LView, index: number, value: T): void { // 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 - const adjustedIndex = index + HEADER_OFFSET; - if (adjustedIndex >= tView.data.length) { - tView.data[adjustedIndex] = null; - tView.blueprint[adjustedIndex] = null; + if (index >= tView.data.length) { + tView.data[index] = null; + tView.blueprint[index] = null; } - lView[adjustedIndex] = value; + lView[index] = value; } /** @@ -34,5 +33,5 @@ export function store(tView: TView, lView: LView, index: number, value: T): v */ export function ɵɵreference(index: number) { const contextLView = getContextLView(); - return load(contextLView, index); + return load(contextLView, HEADER_OFFSET + index); } diff --git a/packages/core/src/render3/instructions/styling.ts b/packages/core/src/render3/instructions/styling.ts index e956e9a6e5..16ac4d3d7a 100644 --- a/packages/core/src/render3/instructions/styling.ts +++ b/packages/core/src/render3/instructions/styling.ts @@ -17,14 +17,13 @@ import {DirectiveDef} from '../interfaces/definition'; import {AttributeMarker, TAttributes, TNode, TNodeFlags, TNodeType} from '../interfaces/node'; import {RElement, Renderer3} from '../interfaces/renderer'; import {getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate, TStylingKey, TStylingRange} from '../interfaces/styling'; -import {HEADER_OFFSET, LView, RENDERER, TData, TView} from '../interfaces/view'; +import {LView, RENDERER, TData, TView} from '../interfaces/view'; import {applyStyling} from '../node_manipulation'; import {getCurrentDirectiveDef, getLView, getSelectedIndex, getTView, incrementBindingIndex} from '../state'; import {insertTStylingBinding} from '../styling/style_binding_list'; import {getLastParsedKey, getLastParsedValue, parseClassName, parseClassNameNext, parseStyle, parseStyleNext} from '../styling/styling_parser'; import {NO_CHANGE} from '../tokens'; import {getNativeByIndex} from '../util/view_utils'; - import {setDirectiveInputsWhichShadowsStyling} from './property'; @@ -174,7 +173,7 @@ export function checkStylingProperty( stylingFirstUpdatePass(tView, prop, bindingIndex, isClassBased); } if (value !== NO_CHANGE && bindingUpdated(lView, bindingIndex, value)) { - const tNode = tView.data[getSelectedIndex() + HEADER_OFFSET] as TNode; + const tNode = tView.data[getSelectedIndex()] as TNode; updateStyling( tView, tNode, lView, lView[RENDERER], prop, lView[bindingIndex + 1] = normalizeSuffix(value, suffix), isClassBased, bindingIndex); @@ -204,7 +203,7 @@ export function checkStylingMap( if (value !== NO_CHANGE && bindingUpdated(lView, bindingIndex, value)) { // `getSelectedIndex()` should be here (rather than in instruction) so that it is guarded by the // if so as not to read unnecessarily. - const tNode = tView.data[getSelectedIndex() + HEADER_OFFSET] as TNode; + const tNode = tView.data[getSelectedIndex()] as TNode; if (hasStylingInputShadow(tNode, isClassBased) && !isInHostBindings(tView, bindingIndex)) { if (ngDevMode) { // verify that if we are shadowing then `TData` is appropriately marked so that we skip @@ -271,7 +270,8 @@ function stylingFirstUpdatePass( // itself to the list. // `getSelectedIndex()` should be here (rather than in instruction) so that it is guarded by the // if so as not to read unnecessarily. - const tNode = tData[getSelectedIndex() + HEADER_OFFSET] as TNode; + const tNode = tData[getSelectedIndex()] as TNode; + ngDevMode && assertDefined(tNode, 'TNode expected'); const isHostBindings = isInHostBindings(tView, bindingIndex); if (hasStylingInputShadow(tNode, isClassBased) && tStylingKey === null && !isHostBindings) { // `tStylingKey === null` implies that we are either `[style]` or `[class]` binding. diff --git a/packages/core/src/render3/instructions/template.ts b/packages/core/src/render3/instructions/template.ts index 9c933d2ca7..43e476ca61 100644 --- a/packages/core/src/render3/instructions/template.ts +++ b/packages/core/src/render3/instructions/template.ts @@ -73,10 +73,10 @@ export function ɵɵtemplate( const tView = getTView(); const adjustedIndex = index + HEADER_OFFSET; - const tNode = tView.firstCreatePass ? - templateFirstCreatePass( - index, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) : - tView.data[adjustedIndex] as TContainerNode; + const tNode = tView.firstCreatePass ? templateFirstCreatePass( + adjustedIndex, tView, lView, templateFn, decls, vars, + tagName, attrsIndex, localRefsIndex) : + tView.data[adjustedIndex] as TContainerNode; setCurrentTNode(tNode, false); const comment = lView[RENDERER].createComment(ngDevMode ? 'container' : ''); diff --git a/packages/core/src/render3/instructions/text.ts b/packages/core/src/render3/instructions/text.ts index f834fc7dbe..0c9fad222a 100644 --- a/packages/core/src/render3/instructions/text.ts +++ b/packages/core/src/render3/instructions/text.ts @@ -35,7 +35,7 @@ export function ɵɵtext(index: number, value: string = ''): void { ngDevMode && assertIndexInRange(lView, adjustedIndex); const tNode = tView.firstCreatePass ? - getOrCreateTNode(tView, index, TNodeType.Text, value, null) : + getOrCreateTNode(tView, adjustedIndex, TNodeType.Text, value, null) : tView.data[adjustedIndex] as TElementNode; const textNative = lView[adjustedIndex] = createTextNode(lView[RENDERER], value); diff --git a/packages/core/src/render3/interfaces/view.ts b/packages/core/src/render3/interfaces/view.ts index f026c21a7a..5d2d667a6f 100644 --- a/packages/core/src/render3/interfaces/view.ts +++ b/packages/core/src/render3/interfaces/view.ts @@ -47,7 +47,13 @@ export const DECLARATION_COMPONENT_VIEW = 16; export const DECLARATION_LCONTAINER = 17; export const PREORDER_HOOK_FLAGS = 18; export const QUERIES = 19; -/** Size of LView's header. Necessary to adjust for it when setting slots. */ +/** + * Size of LView's header. Necessary to adjust for it when setting slots. + * + * IMPORTANT: `HEADER_OFFSET` should only be referred to the in the `ɵɵ*` instructions to translate + * instruction index into `LView` index. All other indexes should be in the `LView` index space and + * there should be no need to refer to `HEADER_OFFSET` anywhere else. + */ export const HEADER_OFFSET = 20; diff --git a/packages/core/src/render3/pipe.ts b/packages/core/src/render3/pipe.ts index 8afba415db..0d33ad41f1 100644 --- a/packages/core/src/render3/pipe.ts +++ b/packages/core/src/render3/pipe.ts @@ -54,7 +54,7 @@ export function ɵɵpipe(index: number, pipeName: string): any { const previousIncludeViewProviders = setIncludeViewProviders(false); const pipeInstance = pipeFactory(); setIncludeViewProviders(previousIncludeViewProviders); - store(tView, getLView(), index, pipeInstance); + store(tView, getLView(), adjustedIndex, pipeInstance); return pipeInstance; } finally { // we have to restore the injector implementation in finally, just in case the creation of the @@ -96,11 +96,12 @@ function getPipeDef(name: string, registry: PipeDefList|null): PipeDef { * @codeGenApi */ export function ɵɵpipeBind1(index: number, slotOffset: number, v1: any): any { + const adjustedIndex = index + HEADER_OFFSET; const lView = getLView(); - const pipeInstance = load(lView, index); + const pipeInstance = load(lView, adjustedIndex); return unwrapValue( lView, - isPure(lView, index) ? + isPure(lView, adjustedIndex) ? pureFunction1Internal( lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, pipeInstance) : pipeInstance.transform(v1)); @@ -120,11 +121,12 @@ export function ɵɵpipeBind1(index: number, slotOffset: number, v1: any): any { * @codeGenApi */ export function ɵɵpipeBind2(index: number, slotOffset: number, v1: any, v2: any): any { + const adjustedIndex = index + HEADER_OFFSET; const lView = getLView(); - const pipeInstance = load(lView, index); + const pipeInstance = load(lView, adjustedIndex); return unwrapValue( lView, - isPure(lView, index) ? + isPure(lView, adjustedIndex) ? pureFunction2Internal( lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, v2, pipeInstance) : pipeInstance.transform(v1, v2)); @@ -145,14 +147,15 @@ export function ɵɵpipeBind2(index: number, slotOffset: number, v1: any, v2: an * @codeGenApi */ export function ɵɵpipeBind3(index: number, slotOffset: number, v1: any, v2: any, v3: any): any { + const adjustedIndex = index + HEADER_OFFSET; const lView = getLView(); - const pipeInstance = load(lView, index); + const pipeInstance = load(lView, adjustedIndex); return unwrapValue( lView, - isPure(lView, index) ? pureFunction3Internal( - lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, - v2, v3, pipeInstance) : - pipeInstance.transform(v1, v2, v3)); + isPure(lView, adjustedIndex) ? pureFunction3Internal( + lView, getBindingRoot(), slotOffset, + pipeInstance.transform, v1, v2, v3, pipeInstance) : + pipeInstance.transform(v1, v2, v3)); } /** @@ -172,14 +175,15 @@ export function ɵɵpipeBind3(index: number, slotOffset: number, v1: any, v2: an */ export function ɵɵpipeBind4( index: number, slotOffset: number, v1: any, v2: any, v3: any, v4: any): any { + const adjustedIndex = index + HEADER_OFFSET; const lView = getLView(); - const pipeInstance = load(lView, index); + const pipeInstance = load(lView, adjustedIndex); return unwrapValue( lView, - isPure(lView, index) ? pureFunction4Internal( - lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, - v2, v3, v4, pipeInstance) : - pipeInstance.transform(v1, v2, v3, v4)); + isPure(lView, adjustedIndex) ? pureFunction4Internal( + lView, getBindingRoot(), slotOffset, + pipeInstance.transform, v1, v2, v3, v4, pipeInstance) : + pipeInstance.transform(v1, v2, v3, v4)); } /** @@ -195,18 +199,19 @@ export function ɵɵpipeBind4( * @codeGenApi */ export function ɵɵpipeBindV(index: number, slotOffset: number, values: [any, ...any[]]): any { + const adjustedIndex = index + HEADER_OFFSET; const lView = getLView(); - const pipeInstance = load(lView, index); + const pipeInstance = load(lView, adjustedIndex); return unwrapValue( lView, - isPure(lView, index) ? + isPure(lView, adjustedIndex) ? pureFunctionVInternal( lView, getBindingRoot(), slotOffset, pipeInstance.transform, values, pipeInstance) : pipeInstance.transform.apply(pipeInstance, values)); } function isPure(lView: LView, index: number): boolean { - return (>lView[TVIEW].data[index + HEADER_OFFSET]).pure; + return (>lView[TVIEW].data[index]).pure; } /** diff --git a/packages/core/src/render3/state.ts b/packages/core/src/render3/state.ts index e625c8e2b7..d4e971dcf6 100644 --- a/packages/core/src/render3/state.ts +++ b/packages/core/src/render3/state.ts @@ -6,11 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ -import {assertDefined, assertEqual, assertNotEqual} from '../util/assert'; +import {assertDefined, assertEqual, assertGreaterThanOrEqual, assertLessThan, assertNotEqual} from '../util/assert'; import {assertLViewOrUndefined, assertTNodeForTView} from './assert'; import {DirectiveDef} from './interfaces/definition'; import {TNode, TNodeType} from './interfaces/node'; -import {CONTEXT, DECLARATION_VIEW, LView, OpaqueViewState, TData, TVIEW, TView} from './interfaces/view'; +import {CONTEXT, DECLARATION_VIEW, HEADER_OFFSET, LView, OpaqueViewState, TData, TVIEW, TView} from './interfaces/view'; import {MATH_ML_NAMESPACE, SVG_NAMESPACE} from './namespaces'; import {assertTNodeType} from './node_assert'; import {getTNode} from './util/view_utils'; @@ -458,13 +458,14 @@ export function enterDI(newView: LView, tNode: TNode) { * @returns the previously active lView; */ export function enterView(newView: LView): void { + ngDevMode && assertNotEqual(newView[0], newView[1] as any, '????'); ngDevMode && assertLViewOrUndefined(newView); const newLFrame = allocLFrame(); if (ngDevMode) { assertEqual(newLFrame.isParent, true, 'Expected clean LFrame'); assertEqual(newLFrame.lView, null, 'Expected clean LFrame'); assertEqual(newLFrame.tView, null, 'Expected clean LFrame'); - assertEqual(newLFrame.selectedIndex, 0, 'Expected clean LFrame'); + assertEqual(newLFrame.selectedIndex, -1, 'Expected clean LFrame'); assertEqual(newLFrame.elementDepthCount, 0, 'Expected clean LFrame'); assertEqual(newLFrame.currentDirectiveIndex, -1, 'Expected clean LFrame'); assertEqual(newLFrame.currentNamespace, null, 'Expected clean LFrame'); @@ -498,7 +499,7 @@ function createLFrame(parent: LFrame|null): LFrame { isParent: true, lView: null!, tView: null!, - selectedIndex: 0, + selectedIndex: -1, contextLView: null!, elementDepthCount: 0, currentNamespace: null, @@ -551,7 +552,7 @@ export function leaveView() { const oldLFrame = leaveViewLight(); oldLFrame.isParent = true; oldLFrame.tView = null!; - oldLFrame.selectedIndex = 0; + oldLFrame.selectedIndex = -1; oldLFrame.contextLView = null!; oldLFrame.elementDepthCount = 0; oldLFrame.currentDirectiveIndex = -1; @@ -599,6 +600,11 @@ export function getSelectedIndex() { * run if and when the provided `index` value is different from the current selected index value.) */ export function setSelectedIndex(index: number) { + ngDevMode && index !== -1 && + assertGreaterThanOrEqual(index, HEADER_OFFSET, 'Index must be past HEADER_OFFSET (or -1).'); + ngDevMode && + assertLessThan( + index, instructionState.lFrame.lView.length, 'Can\'t set index passed end of LView'); instructionState.lFrame.selectedIndex = index; } diff --git a/packages/core/src/render3/util/discovery_utils.ts b/packages/core/src/render3/util/discovery_utils.ts index ec6913f145..e081eb3a75 100644 --- a/packages/core/src/render3/util/discovery_utils.ts +++ b/packages/core/src/render3/util/discovery_utils.ts @@ -16,7 +16,7 @@ import {LContext} from '../interfaces/context'; import {DirectiveDef} from '../interfaces/definition'; import {TElementNode, TNode, TNodeProviderIndexes} from '../interfaces/node'; import {isLView} from '../interfaces/type_checks'; -import {CLEANUP, CONTEXT, DebugNode, FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, T_HOST, TVIEW, TViewType} from '../interfaces/view'; +import {CLEANUP, CONTEXT, DebugNode, FLAGS, LView, LViewFlags, T_HOST, TVIEW, TViewType} from '../interfaces/view'; import {stringifyForError} from './misc_utils'; import {getLViewParent, getRootContext} from './view_traversal_utils'; @@ -387,8 +387,8 @@ export function getDebugNode(element: Element): DebugNode|null { const valueInLView = lView[nodeIndex]; // this means that value in the lView is a component with its own // data. In this situation the TNode is not accessed at the same spot. - const tNode = isLView(valueInLView) ? (valueInLView[T_HOST] as TNode) : - getTNode(lView[TVIEW], nodeIndex - HEADER_OFFSET); + const tNode = + isLView(valueInLView) ? (valueInLView[T_HOST] as TNode) : getTNode(lView[TVIEW], nodeIndex); ngDevMode && assertEqual(tNode.index, nodeIndex, 'Expecting that TNode at index is same as index'); debugNode = buildDebugNode(tNode, lView); diff --git a/packages/core/src/render3/util/view_utils.ts b/packages/core/src/render3/util/view_utils.ts index bd95000995..75c9d23611 100644 --- a/packages/core/src/render3/util/view_utils.ts +++ b/packages/core/src/render3/util/view_utils.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {assertDefined, assertDomNode, assertGreaterThan, assertIndexInRange, assertLessThan} from '../../util/assert'; +import {assertDefined, assertDomNode, assertGreaterThan, assertGreaterThanOrEqual, assertIndexInRange, assertLessThan} from '../../util/assert'; import {assertTNode, assertTNodeForLView} from '../assert'; import {LContainer, TYPE} from '../interfaces/container'; import {LContext, MONKEY_PATCH_KEY_NAME} from '../interfaces/context'; @@ -78,7 +78,9 @@ export function unwrapLContainer(value: RNode|LView|LContainer): LContainer|null * from any containers, component views, or style contexts. */ export function getNativeByIndex(index: number, lView: LView): RNode { - return unwrapRNode(lView[index + HEADER_OFFSET]); + ngDevMode && assertIndexInRange(lView, index); + ngDevMode && assertGreaterThanOrEqual(index, HEADER_OFFSET, 'Expected to be past HEADER_OFFSET'); + return unwrapRNode(lView[index]); } /** @@ -120,16 +122,16 @@ export function getNativeByTNodeOrNull(tNode: TNode|null, lView: LView): RNode|n // fixme(misko): The return Type should be `TNode|null` export function getTNode(tView: TView, index: number): TNode { ngDevMode && assertGreaterThan(index, -1, 'wrong index for TNode'); - ngDevMode && assertLessThan(index, tView.data.length - HEADER_OFFSET, 'wrong index for TNode'); - const tNode = tView.data[index + HEADER_OFFSET] as TNode; + ngDevMode && assertLessThan(index, tView.data.length, 'wrong index for TNode'); + const tNode = tView.data[index] as TNode; ngDevMode && tNode !== null && assertTNode(tNode); return tNode; } /** Retrieves a value from any `LView` or `TData`. */ export function load(view: LView|TData, index: number): T { - ngDevMode && assertIndexInRange(view, index + HEADER_OFFSET); - return view[index + HEADER_OFFSET]; + ngDevMode && assertIndexInRange(view, index); + return view[index]; } export function getComponentLViewByIndex(nodeIndex: number, hostView: LView): LView { diff --git a/packages/core/src/render3/view_engine_compatibility.ts b/packages/core/src/render3/view_engine_compatibility.ts index 794f176f01..ad01f9b616 100644 --- a/packages/core/src/render3/view_engine_compatibility.ts +++ b/packages/core/src/render3/view_engine_compatibility.ts @@ -391,8 +391,8 @@ export function createContainerRef( } else { // The TNode created here is bogus, in that it is not added to the TView. It is only created // to allow us to create a dynamic Comment node. - const commentTNode = createTNode( - hostView[TVIEW], hostTNode.parent, TNodeType.Container, hostTNode.type, null, null); + const commentTNode = + createTNode(hostView[TVIEW], hostTNode.parent, TNodeType.Container, 0, null, null); appendChild(hostView[TVIEW], hostView, commentNode, commentTNode); } } diff --git a/packages/core/test/acceptance/i18n_spec.ts b/packages/core/test/acceptance/i18n_spec.ts index 6ce9eafcb8..bcbce5a482 100644 --- a/packages/core/test/acceptance/i18n_spec.ts +++ b/packages/core/test/acceptance/i18n_spec.ts @@ -652,12 +652,12 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { const lViewDebug = lView.debug!; fixture.detectChanges(); expect((fixture.nativeElement as Element).textContent).toEqual('just now'); - expect(lViewDebug.nodes.map(toTypeContent)).toEqual(['IcuContainer()']); + expect(lViewDebug.nodes.map(toTypeContent)).toEqual(['IcuContainer()']); // We want to ensure that the ICU container does not have any content! // This is because the content is instance dependent and therefore can't be shared // across `TNode`s. expect(lViewDebug.nodes[0].children.map(toTypeContent)).toEqual([]); - expect(fixture.nativeElement.innerHTML).toEqual('just now'); + expect(fixture.nativeElement.innerHTML).toEqual('just now'); }); it('should support multiple ICUs', () => { @@ -674,15 +674,15 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { `); const lView = getComponentLView(fixture.componentInstance); expect(lView.debug!.nodes.map(toTypeContent)).toEqual([ - 'IcuContainer()', - 'IcuContainer()', + 'IcuContainer()', + 'IcuContainer()', ]); // We want to ensure that the ICU container does not have any content! // This is because the content is instance dependent and therefore can't be shared // across `TNode`s. expect(lView.debug!.nodes[0].children.map(toTypeContent)).toEqual([]); expect(fixture.nativeElement.innerHTML) - .toEqual('just nowMr. Angular'); + .toEqual('just nowMr. Angular'); }); }); }); @@ -778,19 +778,19 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { other {({{name}})} }`); expect(fixture.nativeElement.innerHTML) - .toEqual(`
aucun email! - (Angular)
`); + .toEqual(`
aucun email! - (Angular)
`); fixture.componentRef.instance.count = 4; fixture.detectChanges(); expect(fixture.nativeElement.innerHTML) .toEqual( - `
4 emails - (Angular)
`); + `
4 emails - (Angular)
`); fixture.componentRef.instance.count = 0; fixture.componentRef.instance.name = 'John'; fixture.detectChanges(); expect(fixture.nativeElement.innerHTML) - .toEqual(`
aucun email! - (John)
`); + .toEqual(`
aucun email! - (John)
`); }); it('with custom interpolation config', () => { @@ -829,9 +829,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { expect(fixture.nativeElement.innerHTML) .toEqual( `
` + - `aucun email!` + + `aucun email!` + ` - ` + - `(Angular)` + + `(Angular)` + `
`); fixture.componentRef.instance.count = 4; @@ -839,9 +839,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { expect(fixture.nativeElement.innerHTML) .toEqual( `
` + - `4 emails` + + `4 emails` + ` - ` + - `(Angular)` + + `(Angular)` + `
`); fixture.componentRef.instance.count = 0; @@ -850,9 +850,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { expect(fixture.nativeElement.innerHTML) .toEqual( `
` + - `aucun email!` + + `aucun email!` + ` - ` + - `(John)` + + `(John)` + `
`); }); @@ -867,7 +867,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { other {({{name}})} }`); expect(fixture.nativeElement.innerHTML) - .toEqual(`
(Angular)
`); @@ -886,7 +886,8 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { const fixture = initWithTemplate(AppComp, `{name, select, other {({{name}})} }`); - expect(fixture.nativeElement.innerHTML).toEqual(`(Angular)`); + expect(fixture.nativeElement.innerHTML) + .toEqual(`(Angular)`); }); it('inside ', () => { @@ -921,12 +922,12 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { other {animals} }!} }`); - expect(fixture.nativeElement.innerHTML).toEqual(`
zero
`); + expect(fixture.nativeElement.innerHTML).toEqual(`
zero
`); fixture.componentRef.instance.count = 4; fixture.detectChanges(); expect(fixture.nativeElement.innerHTML) - .toEqual(`
4 animaux!
`); + .toEqual(`
4 animaux!
`); }); it('nested with interpolations in "other" blocks', () => { @@ -946,16 +947,16 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { }!} other {other - {{count}}} }`); - expect(fixture.nativeElement.innerHTML).toEqual(`
zero
`); + expect(fixture.nativeElement.innerHTML).toEqual(`
zero
`); fixture.componentRef.instance.count = 2; fixture.detectChanges(); expect(fixture.nativeElement.innerHTML) - .toEqual(`
2 animaux!
`); + .toEqual(`
2 animaux!
`); fixture.componentRef.instance.count = 4; fixture.detectChanges(); - expect(fixture.nativeElement.innerHTML).toEqual(`
autre - 4
`); + expect(fixture.nativeElement.innerHTML).toEqual(`
autre - 4
`); }); it('should return the correct plural form for ICU expressions when using "ro" locale', () => { @@ -988,31 +989,31 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { =other {lots of emails} }`); - expect(fixture.nativeElement.innerHTML).toEqual('no email'); + expect(fixture.nativeElement.innerHTML).toEqual('no email'); // Change detection cycle, no model changes fixture.detectChanges(); - expect(fixture.nativeElement.innerHTML).toEqual('no email'); + expect(fixture.nativeElement.innerHTML).toEqual('no email'); fixture.componentInstance.count = 3; fixture.detectChanges(); - expect(fixture.nativeElement.innerHTML).toEqual('a few emails'); + expect(fixture.nativeElement.innerHTML).toEqual('a few emails'); fixture.componentInstance.count = 1; fixture.detectChanges(); - expect(fixture.nativeElement.innerHTML).toEqual('one email'); + expect(fixture.nativeElement.innerHTML).toEqual('one email'); fixture.componentInstance.count = 10; fixture.detectChanges(); - expect(fixture.nativeElement.innerHTML).toEqual('a few emails'); + expect(fixture.nativeElement.innerHTML).toEqual('a few emails'); fixture.componentInstance.count = 20; fixture.detectChanges(); - expect(fixture.nativeElement.innerHTML).toEqual('lots of emails'); + expect(fixture.nativeElement.innerHTML).toEqual('lots of emails'); fixture.componentInstance.count = 0; fixture.detectChanges(); - expect(fixture.nativeElement.innerHTML).toEqual('no email'); + expect(fixture.nativeElement.innerHTML).toEqual('no email'); }); it(`should return the correct plural form for ICU expressions when using "es" locale`, () => { @@ -1039,31 +1040,31 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { =other {lots of emails} }`); - expect(fixture.nativeElement.innerHTML).toEqual('no email'); + expect(fixture.nativeElement.innerHTML).toEqual('no email'); // Change detection cycle, no model changes fixture.detectChanges(); - expect(fixture.nativeElement.innerHTML).toEqual('no email'); + expect(fixture.nativeElement.innerHTML).toEqual('no email'); fixture.componentInstance.count = 3; fixture.detectChanges(); - expect(fixture.nativeElement.innerHTML).toEqual('lots of emails'); + expect(fixture.nativeElement.innerHTML).toEqual('lots of emails'); fixture.componentInstance.count = 1; fixture.detectChanges(); - expect(fixture.nativeElement.innerHTML).toEqual('one email'); + expect(fixture.nativeElement.innerHTML).toEqual('one email'); fixture.componentInstance.count = 10; fixture.detectChanges(); - expect(fixture.nativeElement.innerHTML).toEqual('lots of emails'); + expect(fixture.nativeElement.innerHTML).toEqual('lots of emails'); fixture.componentInstance.count = 20; fixture.detectChanges(); - expect(fixture.nativeElement.innerHTML).toEqual('lots of emails'); + expect(fixture.nativeElement.innerHTML).toEqual('lots of emails'); fixture.componentInstance.count = 0; fixture.detectChanges(); - expect(fixture.nativeElement.innerHTML).toEqual('no email'); + expect(fixture.nativeElement.innerHTML).toEqual('no email'); }); it('projection', () => { @@ -1158,12 +1159,12 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { const fixture = TestBed.createComponent(App); fixture.detectChanges(); expect(fixture.debugElement.nativeElement.innerHTML) - .toContain('
ONE
'); + .toContain('
ONE
'); fixture.componentRef.instance.count = 2; fixture.detectChanges(); expect(fixture.debugElement.nativeElement.innerHTML) - .toContain('
OTHER
'); + .toContain('
OTHER
'); // destroy component fixture.componentInstance.condition = false; @@ -1175,7 +1176,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { fixture.componentInstance.count = 1; fixture.detectChanges(); expect(fixture.debugElement.nativeElement.innerHTML) - .toContain('
ONE
'); + .toContain('
ONE
'); }); it('with nested ICU expression and inside a container when creating a view via vcr.createEmbeddedView', @@ -1247,12 +1248,12 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement.innerHTML) .toBe( - '
2 animals!
'); + '
2 animals!
'); fixture.componentRef.instance.count = 1; fixture.detectChanges(); expect(fixture.debugElement.nativeElement.innerHTML) - .toBe('
ONE
'); + .toBe('
ONE
'); }); it('with nested containers', () => { @@ -2369,13 +2370,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { fixture.detectChanges(); expect(fixture.nativeElement.innerHTML) .toEqual( - `
Contenu enfant et projection depuis Parent
`); + `
Contenu enfant et projection depuis Parent
`); fixture.componentRef.instance.name = 'angular'; fixture.detectChanges(); expect(fixture.nativeElement.innerHTML) .toEqual( - `
Contenu enfant et projection depuis Angular
`); + `
Contenu enfant et projection depuis Angular
`); }); it(`shouldn't project deleted projections in i18n blocks`, () => { diff --git a/packages/core/test/render3/i18n/i18n_insert_before_index_spec.ts b/packages/core/test/render3/i18n/i18n_insert_before_index_spec.ts index 396c09199e..2921d9a2e7 100644 --- a/packages/core/test/render3/i18n/i18n_insert_before_index_spec.ts +++ b/packages/core/test/render3/i18n/i18n_insert_before_index_spec.ts @@ -54,44 +54,44 @@ describe('addTNodeAndUpdateInsertBeforeIndex', () => { describe('whose index is smaller than current nodes', () => { it('should update the previous insertBeforeIndex', () => { const previousTNodes: TNode[] = [ - tPlaceholderElementNode(20), tPlaceholderElementNode(21), + tPlaceholderElementNode(22), ]; - addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(19)); + addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(20)); expect(previousTNodes).toEqual([ - matchTNode({index: 20, insertBeforeIndex: 19}), - matchTNode({index: 21, insertBeforeIndex: 19}), - matchTNode({index: 19, insertBeforeIndex: null}), + matchTNode({index: 21, insertBeforeIndex: 20}), + matchTNode({index: 22, insertBeforeIndex: 20}), + matchTNode({index: 20, insertBeforeIndex: null}), ]); }); it('should not update the previous insertBeforeIndex if it is already set', () => { const previousTNodes: TNode[] = [ - tPlaceholderElementNode(20, 19), - tPlaceholderElementNode(21, 19), - tPlaceholderElementNode(19), + tPlaceholderElementNode(22, 21), + tPlaceholderElementNode(23, 21), + tPlaceholderElementNode(21), ]; - addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(18)); + addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(20)); expect(previousTNodes).toEqual([ - matchTNode({index: 20, insertBeforeIndex: 19}), - matchTNode({index: 21, insertBeforeIndex: 19}), - matchTNode({index: 19, insertBeforeIndex: 18}), - matchTNode({index: 18, insertBeforeIndex: null}), + matchTNode({index: 22, insertBeforeIndex: 21}), + matchTNode({index: 23, insertBeforeIndex: 21}), + matchTNode({index: 21, insertBeforeIndex: 20}), + matchTNode({index: 20, insertBeforeIndex: null}), ]); }); it('should not update the previous insertBeforeIndex if it is created after', () => { const previousTNodes: TNode[] = [ - tPlaceholderElementNode(20, 15), - tPlaceholderElementNode(21, 15), - tPlaceholderElementNode(15), + tPlaceholderElementNode(25, 20), + tPlaceholderElementNode(26, 20), + tPlaceholderElementNode(20), ]; - addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(18)); + addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(23)); expect(previousTNodes).toEqual([ - matchTNode({index: 20, insertBeforeIndex: 15}), - matchTNode({index: 21, insertBeforeIndex: 15}), - matchTNode({index: 15, insertBeforeIndex: null}), - matchTNode({index: 18, insertBeforeIndex: null}), + matchTNode({index: 25, insertBeforeIndex: 20}), + matchTNode({index: 26, insertBeforeIndex: 20}), + matchTNode({index: 20, insertBeforeIndex: null}), + matchTNode({index: 23, insertBeforeIndex: null}), ]); }); }); @@ -116,44 +116,44 @@ describe('addTNodeAndUpdateInsertBeforeIndex', () => { describe('whose index is smaller than current nodes', () => { it('should update the previous insertBeforeIndex', () => { const previousTNodes: TNode[] = [ - tPlaceholderElementNode(20), tPlaceholderElementNode(21), + tPlaceholderElementNode(22), ]; - addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(19)); + addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(20)); expect(previousTNodes).toEqual([ - matchTNode({index: 20, insertBeforeIndex: 19}), - matchTNode({index: 21, insertBeforeIndex: 19}), - matchTNode({index: 19, insertBeforeIndex: null}), + matchTNode({index: 21, insertBeforeIndex: 20}), + matchTNode({index: 22, insertBeforeIndex: 20}), + matchTNode({index: 20, insertBeforeIndex: null}), ]); }); it('should not update the previous insertBeforeIndex if it is already set', () => { const previousTNodes: TNode[] = [ - tPlaceholderElementNode(20, 19), - tPlaceholderElementNode(21, 19), - tPlaceholderElementNode(19), + tPlaceholderElementNode(22, 21), + tPlaceholderElementNode(23, 21), + tPlaceholderElementNode(21), ]; - addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(18)); + addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(20)); expect(previousTNodes).toEqual([ - matchTNode({index: 20, insertBeforeIndex: 19}), - matchTNode({index: 21, insertBeforeIndex: 19}), - matchTNode({index: 19, insertBeforeIndex: 18}), - matchTNode({index: 18, insertBeforeIndex: null}), + matchTNode({index: 22, insertBeforeIndex: 21}), + matchTNode({index: 23, insertBeforeIndex: 21}), + matchTNode({index: 21, insertBeforeIndex: 20}), + matchTNode({index: 20, insertBeforeIndex: null}), ]); }); it('should not update the previous insertBeforeIndex if it is created after', () => { const previousTNodes: TNode[] = [ - tPlaceholderElementNode(20, 15), - tPlaceholderElementNode(21, 15), - tPlaceholderElementNode(15), + tPlaceholderElementNode(25, 20), + tPlaceholderElementNode(26, 20), + tPlaceholderElementNode(20), ]; - addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(18)); + addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(23)); expect(previousTNodes).toEqual([ - matchTNode({index: 20, insertBeforeIndex: 15}), - matchTNode({index: 21, insertBeforeIndex: 15}), - matchTNode({index: 15, insertBeforeIndex: 18}), - matchTNode({index: 18, insertBeforeIndex: null}), + matchTNode({index: 25, insertBeforeIndex: 20}), + matchTNode({index: 26, insertBeforeIndex: 20}), + matchTNode({index: 20, insertBeforeIndex: 23}), + matchTNode({index: 23, insertBeforeIndex: null}), ]); }); }); diff --git a/packages/core/test/render3/i18n/i18n_parse_spec.ts b/packages/core/test/render3/i18n/i18n_parse_spec.ts index a8bdfca305..339453a1b0 100644 --- a/packages/core/test/render3/i18n/i18n_parse_spec.ts +++ b/packages/core/test/render3/i18n/i18n_parse_spec.ts @@ -45,7 +45,7 @@ describe('i18n_parse', () => { // 21: Binding for ICU | // ----- EXPANDO ----- // 22: null | #text(before|) - // 23: TIcu | + // 23: TIcu | // 24: null | currently selected ICU case // 25: null | #text(caseA) // 26: null | #text(otherCase) @@ -59,7 +59,7 @@ describe('i18n_parse', () => { create: matchDebug([ 'lView[22] = document.createText("before|");', 'parent.appendChild(lView[22]);', - 'lView[23] = document.createComment("ICU 0:0");', + 'lView[23] = document.createComment("ICU 20:0");', 'parent.appendChild(lView[23]);', 'lView[27] = document.createText("|after");', 'parent.appendChild(lView[27]);', @@ -95,22 +95,22 @@ describe('i18n_parse', () => { fixture.apply(() => { applyCreateOpCodes(fixture.lView, tI18n.create, fixture.host, null); - expect(fixture.host.innerHTML).toEqual('before||after'); + expect(fixture.host.innerHTML).toEqual('before||after'); }); fixture.apply(() => { ɵɵi18nExp('A'); ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20; - expect(fixture.host.innerHTML).toEqual('before|caseA|after'); + expect(fixture.host.innerHTML).toEqual('before|caseA|after'); }); fixture.apply(() => { ɵɵi18nExp('x'); ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20; - expect(fixture.host.innerHTML).toEqual('before|otherCase|after'); + expect(fixture.host.innerHTML).toEqual('before|otherCase|after'); }); fixture.apply(() => { ɵɵi18nExp('A'); ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20; - expect(fixture.host.innerHTML).toEqual('before|caseA|after'); + expect(fixture.host.innerHTML).toEqual('before|caseA|after'); }); }); @@ -122,23 +122,23 @@ describe('i18n_parse', () => { }`); fixture.apply(() => { applyCreateOpCodes(fixture.lView, tI18n.create, fixture.host, null); - expect(fixture.host.innerHTML).toEqual(''); + expect(fixture.host.innerHTML).toEqual(''); }); fixture.apply(() => { ɵɵi18nExp('A'); ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20; - expect(fixture.host.innerHTML).toEqual('Hello world!'); + expect(fixture.host.innerHTML).toEqual('Hello world!'); }); fixture.apply(() => { ɵɵi18nExp('x'); ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20; expect(fixture.host.innerHTML) - .toEqual('
nestedOther
'); + .toEqual('
nestedOther
'); }); fixture.apply(() => { ɵɵi18nExp('A'); ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20; - expect(fixture.host.innerHTML).toEqual('Hello world!'); + expect(fixture.host.innerHTML).toEqual('Hello world!'); }); }); @@ -154,7 +154,7 @@ describe('i18n_parse', () => { // 22: Binding for child ICU | // 23: Binding for child ICU | // ----- EXPANDO ----- - // 24: TIcu (parent) | + // 24: TIcu (parent) | // 25: null | currently selected ICU case // 26: null | #text( parentA ) // 27: TIcu (child) | @@ -170,7 +170,7 @@ describe('i18n_parse', () => { }`); expect(tI18n).toEqual(matchTI18n({ create: matchDebug([ - 'lView[24] = document.createComment("ICU 0:0");', + 'lView[24] = document.createComment("ICU 20:0");', 'parent.appendChild(lView[24]);', ]), update: matchDebug([ @@ -244,45 +244,46 @@ describe('i18n_parse', () => { fixture.apply(() => { applyCreateOpCodes(fixture.lView, tI18n.create, fixture.host, null); - expect(fixture.host.innerHTML).toEqual(''); + expect(fixture.host.innerHTML).toEqual(''); }); fixture.apply(() => { ɵɵi18nExp('A'); ɵɵi18nExp('0'); ɵɵi18nExp('value1'); ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20; - expect(fixture.host.innerHTML).toEqual('parentA nested0!'); + expect(fixture.host.innerHTML) + .toEqual('parentA nested0!'); }); fixture.apply(() => { ɵɵi18nExp('A'); ɵɵi18nExp('x'); ɵɵi18nExp('value1'); ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20; - expect(fixture.host.innerHTML).toEqual('parentA value1!'); + expect(fixture.host.innerHTML).toEqual('parentA value1!'); }); fixture.apply(() => { ɵɵi18nExp('x'); ɵɵi18nExp('x'); ɵɵi18nExp('value2'); ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20; - expect(fixture.host.innerHTML).toEqual('parentOther'); + expect(fixture.host.innerHTML).toEqual('parentOther'); }); fixture.apply(() => { ɵɵi18nExp('A'); ɵɵi18nExp('A'); ɵɵi18nExp('value2'); ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20; - expect(fixture.host.innerHTML).toEqual('parentA value2!'); + expect(fixture.host.innerHTML).toEqual('parentA value2!'); }); }); }); function toT18n(text: string) { - const tNodeIndex = 0; + const tNodeIndex = HEADER_OFFSET; fixture.enterView(); i18nStartFirstCreatePass(fixture.tView, 0, fixture.lView, tNodeIndex, text, -1); fixture.leaveView(); - const tI18n = fixture.tView.data[tNodeIndex + HEADER_OFFSET] as TI18n; + const tI18n = fixture.tView.data[tNodeIndex] as TI18n; expect(tI18n).toEqual(matchTI18n({})); return tI18n; } diff --git a/packages/core/test/render3/i18n/i18n_spec.ts b/packages/core/test/render3/i18n/i18n_spec.ts index fa4debd43b..cd72a4dec2 100644 --- a/packages/core/test/render3/i18n/i18n_spec.ts +++ b/packages/core/test/render3/i18n/i18n_spec.ts @@ -67,7 +67,7 @@ describe('Runtime i18n', () => { const fixture = new TemplateFixture( {create: createTemplate, update: updateTemplate, decls: nbDecls, consts: [messageOrAtrs]}); tView = fixture.hostView[TVIEW]; - return tView.data[index + HEADER_OFFSET] as TI18n; + return tView.data[index] as TI18n | I18nUpdateOpCodes; } describe('i18nStart', () => { @@ -79,7 +79,7 @@ describe('Runtime i18n', () => { ɵɵelementStart(0, 'div'); ɵɵi18nStart(index, 0); ɵɵelementEnd(); - }, undefined, nbConsts, index) as TI18n; + }, undefined, nbConsts, HEADER_OFFSET + index) as TI18n; expect(opCodes).toEqual({ create: matchDebug([ @@ -100,7 +100,7 @@ describe('Runtime i18n', () => { ɵɵelementStart(0, 'div'); ɵɵi18nStart(index, 0); ɵɵelementEnd(); - }, undefined, nbConsts, index); + }, undefined, nbConsts, HEADER_OFFSET + index); expect(opCodes).toEqual({ create: matchDebug([ @@ -125,7 +125,7 @@ describe('Runtime i18n', () => { ɵɵelementStart(0, 'div'); ɵɵi18nStart(index, 0); ɵɵelementEnd(); - }, undefined, nbConsts, index); + }, undefined, nbConsts, HEADER_OFFSET + index); expect((opCodes as any).update.debug).toEqual([ 'if (mask & 0b1) { (lView[22] as Text).textContent = `Hello ${lView[i-1]}!`; }' @@ -150,7 +150,7 @@ describe('Runtime i18n', () => { ɵɵelementStart(0, 'div'); ɵɵi18nStart(index, 0); ɵɵelementEnd(); - }, undefined, nbConsts, index); + }, undefined, nbConsts, HEADER_OFFSET + index); expect(opCodes).toEqual({ create: matchDebug([ @@ -183,7 +183,7 @@ describe('Runtime i18n', () => { ɵɵelementStart(0, 'div'); ɵɵi18nStart(index, 0); ɵɵelementEnd(); - }, undefined, nbConsts, index); + }, undefined, nbConsts, HEADER_OFFSET + index); expect(opCodes).toEqual({ create: matchDebug([ @@ -205,7 +205,7 @@ describe('Runtime i18n', () => { opCodes = getOpCodes(message, () => { ɵɵelementStart(0, 'div'); ɵɵi18nStart(index, 0, 1); - }, undefined, nbConsts, index); + }, undefined, nbConsts, index + HEADER_OFFSET); expect(opCodes).toEqual({ create: matchDebug([ @@ -223,7 +223,7 @@ describe('Runtime i18n', () => { opCodes = getOpCodes(message, () => { ɵɵelementStart(0, 'div'); ɵɵi18nStart(index, 0, 2); - }, undefined, nbConsts, index); + }, undefined, nbConsts, index + HEADER_OFFSET); expect(opCodes).toEqual({ create: matchDebug([ @@ -245,11 +245,11 @@ describe('Runtime i18n', () => { ɵɵelementStart(0, 'div'); ɵɵi18nStart(index, 0); ɵɵelementEnd(); - }, undefined, nbConsts, index) as TI18n; + }, undefined, nbConsts, HEADER_OFFSET + index) as TI18n; expect(opCodes).toEqual({ create: matchDebug([ - `lView[${HEADER_OFFSET + 2}] = document.createComment("ICU 1:0");`, + `lView[${HEADER_OFFSET + 2}] = document.createComment("ICU 21:0");`, `parent.appendChild(lView[${HEADER_OFFSET + 2}]);`, ]), update: matchDebug([ @@ -332,11 +332,11 @@ describe('Runtime i18n', () => { ɵɵelementStart(0, 'div'); ɵɵi18n(index, 0); ɵɵelementEnd(); - }, undefined, nbConsts, index); + }, undefined, nbConsts, HEADER_OFFSET + index); expect(opCodes).toEqual({ create: matchDebug([ - `lView[${HEADER_OFFSET + 2}] = document.createComment("ICU 1:0");`, + `lView[${HEADER_OFFSET + 2}] = document.createComment("ICU 21:0");`, `parent.appendChild(lView[${HEADER_OFFSET + 2}]);`, ]), update: matchDebug([ @@ -432,11 +432,11 @@ describe('Runtime i18n', () => { consts: [attrs], }); const tView = fixture.hostView[TVIEW]; - const opCodes = tView.data[index + HEADER_OFFSET] as I18nUpdateOpCodes; + const opCodes = tView.data[HEADER_OFFSET + index] as I18nUpdateOpCodes; expect(opCodes).toEqual([]); - expect( - (getNativeByIndex(0, fixture.hostView as LView) as any as Element).getAttribute('title')) + expect((getNativeByIndex(HEADER_OFFSET, fixture.hostView as LView) as any as Element) + .getAttribute('title')) .toEqual(message); }); @@ -449,7 +449,7 @@ describe('Runtime i18n', () => { ɵɵelementStart(0, 'div'); ɵɵi18nAttributes(index, 0); ɵɵelementEnd(); - }, undefined, nbConsts, index); + }, undefined, nbConsts, HEADER_OFFSET + index); expect(opCodes).toEqual(matchDebug([ 'if (mask & 0b1) { (lView[20] as Element).setAttribute(\'title\', `Hello ${lView[i-1]}!`); }', @@ -465,7 +465,7 @@ describe('Runtime i18n', () => { ɵɵelementStart(0, 'div'); ɵɵi18nAttributes(index, 0); ɵɵelementEnd(); - }, undefined, nbConsts, index); + }, undefined, nbConsts, HEADER_OFFSET + index); expect(opCodes).toEqual(matchDebug([ 'if (mask & 0b11) { (lView[20] as Element).setAttribute(\'title\', `Hello ${lView[i-1]} and ${lView[i-2]}, again ${lView[i-1]}!`); }', @@ -481,7 +481,7 @@ describe('Runtime i18n', () => { ɵɵelementStart(0, 'div'); ɵɵi18nAttributes(index, 0); ɵɵelementEnd(); - }, undefined, nbConsts, index); + }, undefined, nbConsts, HEADER_OFFSET + index); expect(opCodes).toEqual(matchDebug([ 'if (mask & 0b1) { (lView[20] as Element).setAttribute(\'title\', `Hello ${lView[i-1]}!`); }', @@ -631,14 +631,12 @@ describe('Runtime i18n', () => { describe('i18nStartFirstCreatePass', () => { let fixture: ViewFixture; - let divTNode: TElementNode; const DECLS = 20; const VARS = 10; beforeEach(() => { fixture = new ViewFixture({decls: DECLS, vars: VARS}); fixture.enterView(); ɵɵelementStart(0, 'div'); - divTNode = getCurrentTNode() as TElementNode; }); afterEach(ViewFixture.cleanUp); @@ -661,7 +659,8 @@ describe('Runtime i18n', () => { } it('should process text node with no siblings and no children', () => { - i18nStartFirstCreatePass(fixture.tView, 0, fixture.lView, 1, 'Hello World!', -1); + i18nStartFirstCreatePass( + fixture.tView, 0, fixture.lView, HEADER_OFFSET + 1, 'Hello World!', -1); const ti18n = fixture.tView.data[HEADER_OFFSET + 1] as TI18n; // Expect that we only create the `Hello World!` text node and nothing else. expect(ti18n.create).toEqual([ @@ -672,7 +671,8 @@ describe('Runtime i18n', () => { }); it('should process text with a child node', () => { - i18nStartFirstCreatePass(fixture.tView, 0, fixture.lView, 1, 'Hello �#2��/#2�!', -1); + i18nStartFirstCreatePass( + fixture.tView, 0, fixture.lView, HEADER_OFFSET + 1, 'Hello �#2��/#2�!', -1); const ti18n = fixture.tView.data[HEADER_OFFSET + 1] as TI18n; expect(ti18n.create).toEqual([ i18nRangeOffsetOpcode(0), 'Hello ', // @@ -689,7 +689,8 @@ describe('Runtime i18n', () => { }); it('should process text with a child node that has text', () => { - i18nStartFirstCreatePass(fixture.tView, 0, fixture.lView, 1, 'Hello �#2�World�/#2�!', -1); + i18nStartFirstCreatePass( + fixture.tView, 0, fixture.lView, HEADER_OFFSET + 1, 'Hello �#2�World�/#2�!', -1); const ti18n = fixture.tView.data[HEADER_OFFSET + 1] as TI18n; expect(ti18n.create).toEqual([ i18nRangeOffsetOpcode(0), 'Hello ', // @@ -708,7 +709,7 @@ describe('Runtime i18n', () => { it('should process text with a child node that has text and with bindings', () => { i18nStartFirstCreatePass( - fixture.tView, 0, fixture.lView, 1, + fixture.tView, 0, fixture.lView, HEADER_OFFSET + 1, '�0� �#2��1��/#2�!' /* {{salutation}} {{name}}! */, -1); const ti18n = fixture.tView.data[HEADER_OFFSET + 1] as TI18n; expect(ti18n.create).toEqual([ @@ -733,7 +734,8 @@ describe('Runtime i18n', () => { }); it('should process text with a child template', () => { - i18nStartFirstCreatePass(fixture.tView, 0, fixture.lView, 1, 'Hello �*2:1�World�/*2:1�!', -1); + i18nStartFirstCreatePass( + fixture.tView, 0, fixture.lView, HEADER_OFFSET + 1, 'Hello �*2:1�World�/*2:1�!', -1); const ti18n = fixture.tView.data[HEADER_OFFSET + 1] as TI18n; expect(ti18n.create.debug).toEqual([ 'lView[50] = document.createText("Hello ");', diff --git a/packages/core/test/render3/instructions/shared_spec.ts b/packages/core/test/render3/instructions/shared_spec.ts index 8af4ecc973..c994820ace 100644 --- a/packages/core/test/render3/instructions/shared_spec.ts +++ b/packages/core/test/render3/instructions/shared_spec.ts @@ -10,7 +10,7 @@ import {createLView, createTNode, createTView} from '@angular/core/src/render3/i import {TNodeType} from '@angular/core/src/render3/interfaces/node'; import {domRendererFactory3} from '@angular/core/src/render3/interfaces/renderer'; import {HEADER_OFFSET, LViewFlags, TVIEW, TViewType} from '@angular/core/src/render3/interfaces/view'; -import {enterView, getBindingRoot, getLView, setBindingIndex} from '@angular/core/src/render3/state'; +import {enterView, getBindingRoot, getLView, setBindingIndex, setSelectedIndex} from '@angular/core/src/render3/state'; @@ -43,9 +43,10 @@ export function enterViewWithOneDiv() { const lView = createLView( null, tView, null, LViewFlags.CheckAlways, null, null, domRendererFactory3, renderer, null, null); - lView[0 + HEADER_OFFSET] = div; - tView.data[0 + HEADER_OFFSET] = tNode; + lView[HEADER_OFFSET] = div; + tView.data[HEADER_OFFSET] = tNode; enterView(lView); + setSelectedIndex(HEADER_OFFSET); } export function clearFirstUpdatePass() { diff --git a/packages/core/test/render3/instructions/styling_spec.ts b/packages/core/test/render3/instructions/styling_spec.ts index e11658cf0c..2e5abdf4ab 100644 --- a/packages/core/test/render3/instructions/styling_spec.ts +++ b/packages/core/test/render3/instructions/styling_spec.ts @@ -14,8 +14,6 @@ import {getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePre import {HEADER_OFFSET, TVIEW} from '@angular/core/src/render3/interfaces/view'; import {getLView, leaveView, setBindingRootForHostBindings} from '@angular/core/src/render3/state'; import {getNativeByIndex} from '@angular/core/src/render3/util/view_utils'; -import {bypassSanitizationTrustStyle} from '@angular/core/src/sanitization/bypass'; -import {ɵɵsanitizeStyle} from '@angular/core/src/sanitization/sanitization'; import {keyValueArraySet} from '@angular/core/src/util/array_utils'; import {ngDevModeResetPerfCounters} from '@angular/core/src/util/ng_dev_mode'; import {getElementClasses, getElementStyles} from '@angular/core/testing/src/styling'; @@ -28,7 +26,7 @@ describe('styling', () => { afterEach(leaveView); let div!: HTMLElement; - beforeEach(() => div = getNativeByIndex(0, getLView()) as HTMLElement); + beforeEach(() => div = getNativeByIndex(HEADER_OFFSET, getLView()) as HTMLElement); it('should do set basic style', () => { ɵɵstyleProp('color', 'red'); diff --git a/packages/core/test/render3/listeners_spec.ts b/packages/core/test/render3/listeners_spec.ts index 3fe1e5ac3c..8adc97ccdc 100644 --- a/packages/core/test/render3/listeners_spec.ts +++ b/packages/core/test/render3/listeners_spec.ts @@ -6,14 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ +import {HEADER_OFFSET} from '@angular/core/src/render3/interfaces/view'; import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util'; - import {ɵɵdefineComponent, ɵɵdefineDirective, ɵɵreference, ɵɵresolveBody, ɵɵresolveDocument} from '../../src/render3/index'; import {ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵgetCurrentView, ɵɵlistener, ɵɵtext} from '../../src/render3/instructions/all'; import {RenderFlags} from '../../src/render3/interfaces/definition'; import {GlobalTargetResolver} from '../../src/render3/interfaces/renderer'; import {ɵɵrestoreView} from '../../src/render3/state'; - import {getRendererFactory2} from './imported_renderer2'; import {ComponentFixture, containerEl, createComponent, getDirectiveOnNode, renderToHtml, TemplateFixture} from './render_util'; @@ -497,7 +496,7 @@ describe('event listeners', () => { } // testing only - compInstance = getDirectiveOnNode(0); + compInstance = getDirectiveOnNode(HEADER_OFFSET); }, directives: [Comp] }); diff --git a/packages/core/test/render3/matchers_spec.ts b/packages/core/test/render3/matchers_spec.ts index a9f0e1fc71..01964b9140 100644 --- a/packages/core/test/render3/matchers_spec.ts +++ b/packages/core/test/render3/matchers_spec.ts @@ -56,7 +56,7 @@ describe('render3 matchers', () => { }); describe('matchTNode', () => { const tView = createTView(TViewType.Root, null, null, 2, 3, null, null, null, null, null); - const tNode = createTNode(tView, null, TNodeType.Element, 1, 'tagName', []); + const tNode = createTNode(tView, null, TNodeType.Element, 0, 'tagName', []); it('should match', () => { expect(tNode).toEqual(matchTNode()); diff --git a/packages/core/test/render3/query_spec.ts b/packages/core/test/render3/query_spec.ts index 4b8cca9ca7..586f29ce25 100644 --- a/packages/core/test/render3/query_spec.ts +++ b/packages/core/test/render3/query_spec.ts @@ -7,6 +7,7 @@ */ import {ElementRef, QueryList, TemplateRef, ViewContainerRef} from '@angular/core'; +import {HEADER_OFFSET} from '@angular/core/src/render3/interfaces/view'; import {AttributeMarker, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵProvidersFeature} from '../../src/render3/index'; import {ɵɵdirectiveInject, ɵɵelement, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementStart, ɵɵtemplate, ɵɵtext} from '../../src/render3/instructions/all'; @@ -72,8 +73,8 @@ describe('query', () => { ɵɵelementEnd(); } if (rf & RenderFlags.Update) { - child1 = getDirectiveOnNode(0); - child2 = getDirectiveOnNode(1); + child1 = getDirectiveOnNode(HEADER_OFFSET); + child2 = getDirectiveOnNode(HEADER_OFFSET + 1); } }, 2, 0, [Child], [], @@ -112,7 +113,7 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵelement(0, 'div', 0); - elToQuery = getNativeByIndex(0, getLView()); + elToQuery = getNativeByIndex(HEADER_OFFSET, getLView()); } }, 1, 0, [Child], [], @@ -150,7 +151,7 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵelementStart(0, 'div', 0); - { otherChildInstance = getDirectiveOnNode(0, 1); } + { otherChildInstance = getDirectiveOnNode(HEADER_OFFSET, 1); } ɵɵelementEnd(); } }, @@ -345,7 +346,7 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵelement(0, 'div', null, 0); - elToQuery = getNativeByIndex(0, getLView()); + elToQuery = getNativeByIndex(HEADER_OFFSET, getLView()); ɵɵelement(2, 'div'); } }, @@ -384,7 +385,7 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵelement(0, 'div', null, 0); - elToQuery = getNativeByIndex(0, getLView()); + elToQuery = getNativeByIndex(HEADER_OFFSET, getLView()); ɵɵelement(3, 'div'); } }, @@ -431,10 +432,10 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵelement(0, 'div', null, 0); - el1ToQuery = getNativeByIndex(0, getLView()); + el1ToQuery = getNativeByIndex(HEADER_OFFSET, getLView()); ɵɵelement(2, 'div'); ɵɵelement(3, 'div', null, 1); - el2ToQuery = getNativeByIndex(3, getLView()); + el2ToQuery = getNativeByIndex(HEADER_OFFSET + 3, getLView()); } }, 5, 0, [], [], @@ -471,7 +472,7 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵelement(0, 'div', null, 0); - elToQuery = getNativeByIndex(0, getLView()); + elToQuery = getNativeByIndex(HEADER_OFFSET, getLView()); ɵɵelement(2, 'div'); } }, @@ -509,7 +510,7 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵelementContainerStart(0, null, 0); - elToQuery = getNativeByIndex(0, getLView()); + elToQuery = getNativeByIndex(HEADER_OFFSET, getLView()); ɵɵelementContainerEnd(); } }, @@ -546,7 +547,7 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵelementContainerStart(0, null, 0); - elToQuery = getNativeByIndex(0, getLView()); + elToQuery = getNativeByIndex(HEADER_OFFSET, getLView()); ɵɵelementContainerEnd(); } }, @@ -756,7 +757,7 @@ describe('query', () => { ɵɵelement(0, 'child', null, 0); } if (rf & RenderFlags.Update) { - childInstance = getDirectiveOnNode(0); + childInstance = getDirectiveOnNode(HEADER_OFFSET); } }, 2, 0, [Child], [], @@ -843,7 +844,7 @@ describe('query', () => { ɵɵelement(0, 'div', 0, 1); } if (rf & RenderFlags.Update) { - childInstance = getDirectiveOnNode(0); + childInstance = getDirectiveOnNode(HEADER_OFFSET); } }, 2, 0, [Child], [], @@ -883,8 +884,8 @@ describe('query', () => { ɵɵelement(0, 'div', 0, 1); } if (rf & RenderFlags.Update) { - child1Instance = getDirectiveOnNode(0, 0); - child2Instance = getDirectiveOnNode(0, 1); + child1Instance = getDirectiveOnNode(HEADER_OFFSET, 0); + child2Instance = getDirectiveOnNode(HEADER_OFFSET, 1); } }, 3, 0, [Child1, Child2], [], @@ -925,7 +926,7 @@ describe('query', () => { ɵɵelement(0, 'div', 0, 1); } if (rf & RenderFlags.Update) { - childInstance = getDirectiveOnNode(0); + childInstance = getDirectiveOnNode(HEADER_OFFSET); } }, 3, 0, [Child], [], @@ -970,7 +971,7 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵelement(0, 'div', 0, 1); - div = getNativeByIndex(0, getLView()); + div = getNativeByIndex(HEADER_OFFSET, getLView()); } }, 2, 0, [Child], [], @@ -1007,10 +1008,10 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵelement(0, 'div', 0, 1); - div = getNativeByIndex(0, getLView()); + div = getNativeByIndex(HEADER_OFFSET, getLView()); } if (rf & RenderFlags.Update) { - childInstance = getDirectiveOnNode(0); + childInstance = getDirectiveOnNode(HEADER_OFFSET); } }, 3, 0, [Child], [], @@ -1570,8 +1571,8 @@ describe('query', () => { } if (rf & RenderFlags.Update) { const lView = getLView(); - outInstance = load(lView, 1); - inInstance = load(lView, 5); + outInstance = load(lView, HEADER_OFFSET + 1); + inInstance = load(lView, HEADER_OFFSET + 5); } }, 10, 0, [QueryDirective], [], null, [], [], undefined, [ @@ -1632,8 +1633,8 @@ describe('query', () => { } if (rf & RenderFlags.Update) { const lView = getLView(); - outInstance = load(lView, 1); - inInstance = load(lView, 3); + outInstance = load(lView, HEADER_OFFSET + 1); + inInstance = load(lView, HEADER_OFFSET + 3); } }, 7, 0, [QueryDirective], [], null, [], [], undefined, [ @@ -1692,8 +1693,8 @@ describe('query', () => { } if (rf & RenderFlags.Update) { const lView = getLView(); - outInstance = load(lView, 1); - inInstance = load(lView, 3); + outInstance = load(lView, HEADER_OFFSET + 1); + inInstance = load(lView, HEADER_OFFSET + 3); } }, 7, 0, [QueryDirective], [], null, [], [], undefined, [ @@ -1783,8 +1784,8 @@ describe('query', () => { } if (rf & RenderFlags.Update) { const lView = getLView(); - shallowInstance = load(lView, 1); - deepInstance = load(lView, 2); + shallowInstance = load(lView, HEADER_OFFSET + 1); + deepInstance = load(lView, HEADER_OFFSET + 2); } }, 8, 0, [ShallowQueryDirective, DeepQueryDirective], [], null, [], [], undefined, [ diff --git a/packages/core/test/render3/render_util.ts b/packages/core/test/render3/render_util.ts index 912f3bbac8..4f44afc48b 100644 --- a/packages/core/test/render3/render_util.ts +++ b/packages/core/test/render3/render_util.ts @@ -17,7 +17,6 @@ import {TConstants, TNodeType} from '@angular/core/src/render3/interfaces/node'; import {enterView, getLView} from '@angular/core/src/render3/state'; import {EMPTY_ARRAY} from '@angular/core/src/util/empty'; import {stringifyElement} from '@angular/platform-browser/testing/src/browser_util'; - import {SWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__ as R3_CHANGE_DETECTOR_REF_FACTORY} from '../../src/change_detection/change_detector_ref'; import {Injector} from '../../src/di/injector'; import {Type} from '../../src/interface/type'; @@ -33,11 +32,10 @@ import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveT import {DirectiveDefList, DirectiveDefListOrFactory, DirectiveTypesOrFactory, HostBindingsFunction, PipeDef, PipeDefList, PipeDefListOrFactory, PipeTypesOrFactory} from '../../src/render3/interfaces/definition'; import {PlayerHandler} from '../../src/render3/interfaces/player'; import {domRendererFactory3, ProceduralRenderer3, RComment, RElement, Renderer3, RendererFactory3, RendererStyleFlags3, RNode, RText} from '../../src/render3/interfaces/renderer'; -import {HEADER_OFFSET, LView, LViewFlags, T_HOST, TVIEW, TViewType} from '../../src/render3/interfaces/view'; +import {HEADER_OFFSET, LView, LViewFlags, TVIEW, TViewType} from '../../src/render3/interfaces/view'; import {destroyLView} from '../../src/render3/node_manipulation'; import {getRootView} from '../../src/render3/util/view_traversal_utils'; import {Sanitizer} from '../../src/sanitization/sanitizer'; - import {getRendererFactory2} from './imported_renderer2'; @@ -434,7 +432,7 @@ export function createDirective( /** Gets the directive on the given node at the given index */ export function getDirectiveOnNode(nodeIndex: number, dirIndex: number = 0) { - const directives = getDirectivesAtNodeIndex(nodeIndex + HEADER_OFFSET, getLView(), true); + const directives = getDirectivesAtNodeIndex(nodeIndex, getLView(), true); if (directives == null) { throw new Error(`No directives exist on node in slot ${nodeIndex}`); } diff --git a/packages/core/test/render3/view_container_ref_spec.ts b/packages/core/test/render3/view_container_ref_spec.ts index 10ee8debb0..96f0415814 100644 --- a/packages/core/test/render3/view_container_ref_spec.ts +++ b/packages/core/test/render3/view_container_ref_spec.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ +import {HEADER_OFFSET} from '@angular/core/src/render3/interfaces/view'; import {ChangeDetectorRef, Component as _Component, ComponentFactoryResolver, ElementRef, QueryList, TemplateRef, ViewContainerRef, ViewRef} from '../../src/core'; import {ViewEncapsulation} from '../../src/metadata'; import {injectComponentFactoryResolver, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵlistener, ɵɵloadQuery, ɵɵqueryRefresh, ɵɵviewQuery} from '../../src/render3/index'; @@ -14,9 +15,9 @@ import {RenderFlags} from '../../src/render3/interfaces/definition'; import {RElement} from '../../src/render3/interfaces/renderer'; import {getLView} from '../../src/render3/state'; import {getNativeByIndex} from '../../src/render3/util/view_utils'; - import {ComponentFixture, createComponent, TemplateFixture} from './render_util'; + const Component: typeof _Component = function(...args: any[]): any { // In test we use @Component for documentation only so it's safe to mock out the implementation. return () => undefined; @@ -362,7 +363,7 @@ describe('ViewContainerRef', () => { ɵɵelement(0, 'div', 1, 0); } // testing only - fooEl = getNativeByIndex(0, getLView()) as RElement; + fooEl = getNativeByIndex(HEADER_OFFSET, getLView()) as RElement; }, viewQuery: function(rf: RenderFlags, ctx: any) {