refactor(ivy): flatten LInjector into LViewData (#26220)
PR Close #26220
This commit is contained in:
parent
cb59d87489
commit
730679964f
@ -47,10 +47,7 @@ class Render3DebugContext implements DebugContext {
|
|||||||
get injector(): Injector {
|
get injector(): Injector {
|
||||||
if (this.nodeIndex !== null) {
|
if (this.nodeIndex !== null) {
|
||||||
const tNode = this.view[TVIEW].data[this.nodeIndex];
|
const tNode = this.view[TVIEW].data[this.nodeIndex];
|
||||||
const nodeInjector = di.getInjector(tNode, this.view);
|
return new di.NodeInjector(tNode, this.view);
|
||||||
if (nodeInjector) {
|
|
||||||
return new di.NodeInjector(nodeInjector);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return Injector.NULL;
|
return Injector.NULL;
|
||||||
}
|
}
|
||||||
|
@ -20,10 +20,10 @@ import {getComponentDef, getDirectiveDef, getPipeDef} from './definition';
|
|||||||
import {NG_ELEMENT_ID} from './fields';
|
import {NG_ELEMENT_ID} from './fields';
|
||||||
import {_getViewData, assertPreviousIsParent, getPreviousOrParentTNode, resolveDirective, setEnvironment} from './instructions';
|
import {_getViewData, assertPreviousIsParent, getPreviousOrParentTNode, resolveDirective, setEnvironment} from './instructions';
|
||||||
import {DirectiveDefInternal} from './interfaces/definition';
|
import {DirectiveDefInternal} from './interfaces/definition';
|
||||||
import {LInjector} from './interfaces/injector';
|
import {INJECTOR_SIZE, InjectorLocationFlags, PARENT_INJECTOR, TNODE,} from './interfaces/injector';
|
||||||
import {AttributeMarker, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType} from './interfaces/node';
|
import {AttributeMarker, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType} from './interfaces/node';
|
||||||
import {isProceduralRenderer} from './interfaces/renderer';
|
import {isProceduralRenderer} from './interfaces/renderer';
|
||||||
import {DECLARATION_VIEW, DIRECTIVES, HOST_NODE, INJECTOR, LViewData, RENDERER, TVIEW, TView} from './interfaces/view';
|
import {DECLARATION_VIEW, DIRECTIVES, HOST_NODE, INJECTOR, LViewData, PARENT, RENDERER, TData, TVIEW, TView} from './interfaces/view';
|
||||||
import {assertNodeOfPossibleTypes} from './node_assert';
|
import {assertNodeOfPossibleTypes} from './node_assert';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,43 +41,47 @@ let nextNgElementId = 0;
|
|||||||
* Registers this directive as present in its node's injector by flipping the directive's
|
* Registers this directive as present in its node's injector by flipping the directive's
|
||||||
* corresponding bit in the injector's bloom filter.
|
* corresponding bit in the injector's bloom filter.
|
||||||
*
|
*
|
||||||
* @param injector The node injector in which the directive should be registered
|
* @param injectorIndex The index of the node injector where this token should be registered
|
||||||
* @param type The directive to register
|
* @param tView The TView for the injector's bloom filters
|
||||||
|
* @param type The directive token to register
|
||||||
*/
|
*/
|
||||||
export function bloomAdd(injector: LInjector, type: Type<any>): void {
|
export function bloomAdd(injectorIndex: number, tView: TView, type: Type<any>): void {
|
||||||
let id: number|undefined = (type as any)[NG_ELEMENT_ID];
|
if (tView.firstTemplatePass) {
|
||||||
|
let id: number|undefined = (type as any)[NG_ELEMENT_ID];
|
||||||
|
|
||||||
// Set a unique ID on the directive type, so if something tries to inject the directive,
|
// Set a unique ID on the directive type, so if something tries to inject the directive,
|
||||||
// we can easily retrieve the ID and hash it into the bloom bit that should be checked.
|
// we can easily retrieve the ID and hash it into the bloom bit that should be checked.
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
id = (type as any)[NG_ELEMENT_ID] = nextNgElementId++;
|
id = (type as any)[NG_ELEMENT_ID] = nextNgElementId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only have BLOOM_SIZE (256) slots in our bloom filter (8 buckets * 32 bits each),
|
// We only have BLOOM_SIZE (256) slots in our bloom filter (8 buckets * 32 bits each),
|
||||||
// so all unique IDs must be modulo-ed into a number from 0 - 255 to fit into the filter.
|
// so all unique IDs must be modulo-ed into a number from 0 - 255 to fit into the filter.
|
||||||
const bloomBit = id & BLOOM_MASK;
|
const bloomBit = id & BLOOM_MASK;
|
||||||
|
|
||||||
// Create a mask that targets the specific bit associated with the directive.
|
// Create a mask that targets the specific bit associated with the directive.
|
||||||
// JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
|
// JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
|
||||||
// to bit positions 0 - 31 in a 32 bit integer.
|
// to bit positions 0 - 31 in a 32 bit integer.
|
||||||
const mask = 1 << bloomBit;
|
const mask = 1 << bloomBit;
|
||||||
|
|
||||||
// Use the raw bloomBit number to determine which bloom filter bucket we should check
|
// Use the raw bloomBit number to determine which bloom filter bucket we should check
|
||||||
// e.g: bf0 = [0 - 31], bf1 = [32 - 63], bf2 = [64 - 95], bf3 = [96 - 127], etc
|
// e.g: bf0 = [0 - 31], bf1 = [32 - 63], bf2 = [64 - 95], bf3 = [96 - 127], etc
|
||||||
const b7 = bloomBit & 0x80;
|
const b7 = bloomBit & 0x80;
|
||||||
const b6 = bloomBit & 0x40;
|
const b6 = bloomBit & 0x40;
|
||||||
const b5 = bloomBit & 0x20;
|
const b5 = bloomBit & 0x20;
|
||||||
|
const tData = tView.data as number[];
|
||||||
|
|
||||||
if (b7) {
|
if (b7) {
|
||||||
b6 ? (b5 ? (injector.bf7 |= mask) : (injector.bf6 |= mask)) :
|
b6 ? (b5 ? (tData[injectorIndex + 7] |= mask) : (tData[injectorIndex + 6] |= mask)) :
|
||||||
(b5 ? (injector.bf5 |= mask) : (injector.bf4 |= mask));
|
(b5 ? (tData[injectorIndex + 5] |= mask) : (tData[injectorIndex + 4] |= mask));
|
||||||
} else {
|
} else {
|
||||||
b6 ? (b5 ? (injector.bf3 |= mask) : (injector.bf2 |= mask)) :
|
b6 ? (b5 ? (tData[injectorIndex + 3] |= mask) : (tData[injectorIndex + 2] |= mask)) :
|
||||||
(b5 ? (injector.bf1 |= mask) : (injector.bf0 |= mask));
|
(b5 ? (tData[injectorIndex + 1] |= mask) : (tData[injectorIndex] |= mask));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getOrCreateNodeInjector(): LInjector {
|
export function getOrCreateNodeInjector(): number {
|
||||||
ngDevMode && assertPreviousIsParent();
|
ngDevMode && assertPreviousIsParent();
|
||||||
return getOrCreateNodeInjectorForNode(
|
return getOrCreateNodeInjectorForNode(
|
||||||
getPreviousOrParentTNode() as TElementNode | TElementContainerNode | TContainerNode,
|
getPreviousOrParentTNode() as TElementNode | TElementContainerNode | TContainerNode,
|
||||||
@ -92,67 +96,97 @@ export function getOrCreateNodeInjector(): LInjector {
|
|||||||
* @returns Node injector
|
* @returns Node injector
|
||||||
*/
|
*/
|
||||||
export function getOrCreateNodeInjectorForNode(
|
export function getOrCreateNodeInjectorForNode(
|
||||||
tNode: TElementNode | TContainerNode | TElementContainerNode, hostView: LViewData): LInjector {
|
tNode: TElementNode | TContainerNode | TElementContainerNode, hostView: LViewData): number {
|
||||||
const injector = getInjector(tNode, hostView);
|
const existingInjectorIndex = getInjectorIndex(tNode, hostView);
|
||||||
if (injector) return injector;
|
if (existingInjectorIndex !== -1) {
|
||||||
|
return existingInjectorIndex;
|
||||||
|
}
|
||||||
|
|
||||||
const tView = hostView[TVIEW];
|
const tView = hostView[TVIEW];
|
||||||
if (tView.firstTemplatePass) {
|
if (tView.firstTemplatePass) {
|
||||||
// TODO(kara): Store node injector with host bindings for that node (see VIEW_DATA.md)
|
// TODO(kara): Store node injector with host bindings for that node (see VIEW_DATA.md)
|
||||||
tNode.injectorIndex = hostView.length;
|
tNode.injectorIndex = hostView.length;
|
||||||
tView.blueprint.push(null);
|
tView.blueprint.push(0, 0, 0, 0, 0, 0, 0, 0, null); // foundation for cumulative bloom
|
||||||
tView.hostBindingStartIndex++;
|
tView.data.push(0, 0, 0, 0, 0, 0, 0, 0, tNode); // foundation for node bloom
|
||||||
|
tView.hostBindingStartIndex += INJECTOR_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
const parentInjector = getParentInjector(tNode, hostView);
|
const parentLoc = getParentInjectorLocation(tNode, hostView);
|
||||||
return hostView[tNode.injectorIndex] = {
|
const parentIndex = parentLoc & InjectorLocationFlags.InjectorIndexMask;
|
||||||
parent: parentInjector,
|
const parentView: LViewData = getParentInjectorView(parentLoc, hostView);
|
||||||
tNode: tNode,
|
|
||||||
view: hostView,
|
const parentData = parentView[TVIEW].data as any;
|
||||||
bf0: 0,
|
const injectorIndex = tNode.injectorIndex;
|
||||||
bf1: 0,
|
|
||||||
bf2: 0,
|
for (let i = 0; i < PARENT_INJECTOR; i++) {
|
||||||
bf3: 0,
|
const bloomIndex = parentIndex + i;
|
||||||
bf4: 0,
|
hostView[injectorIndex + i] =
|
||||||
bf5: 0,
|
parentLoc === -1 ? 0 : parentView[bloomIndex] | parentData[bloomIndex];
|
||||||
bf6: 0,
|
}
|
||||||
bf7: 0,
|
|
||||||
cbf0: parentInjector == null ? 0 : parentInjector.cbf0 | parentInjector.bf0,
|
hostView[injectorIndex + PARENT_INJECTOR] = parentLoc;
|
||||||
cbf1: parentInjector == null ? 0 : parentInjector.cbf1 | parentInjector.bf1,
|
return injectorIndex;
|
||||||
cbf2: parentInjector == null ? 0 : parentInjector.cbf2 | parentInjector.bf2,
|
|
||||||
cbf3: parentInjector == null ? 0 : parentInjector.cbf3 | parentInjector.bf3,
|
|
||||||
cbf4: parentInjector == null ? 0 : parentInjector.cbf4 | parentInjector.bf4,
|
|
||||||
cbf5: parentInjector == null ? 0 : parentInjector.cbf5 | parentInjector.bf5,
|
|
||||||
cbf6: parentInjector == null ? 0 : parentInjector.cbf6 | parentInjector.bf6,
|
|
||||||
cbf7: parentInjector == null ? 0 : parentInjector.cbf7 | parentInjector.bf7,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getInjector(tNode: TNode, view: LViewData): LInjector|null {
|
export function getInjectorIndex(tNode: TNode, hostView: LViewData): number {
|
||||||
// If the injector index is the same as its parent's injector index, then the index has been
|
|
||||||
// copied down from the parent node. No injector has been created yet on this node.
|
|
||||||
if (tNode.injectorIndex === -1 ||
|
if (tNode.injectorIndex === -1 ||
|
||||||
tNode.parent && tNode.parent.injectorIndex === tNode.injectorIndex) {
|
// If the injector index is the same as its parent's injector index, then the index has been
|
||||||
return null;
|
// copied down from the parent node. No injector has been created yet on this node.
|
||||||
|
(tNode.parent && tNode.parent.injectorIndex === tNode.injectorIndex) ||
|
||||||
|
// After the first template pass, the injector index might exist but the parent values
|
||||||
|
// might not have been calculated yet for this instance
|
||||||
|
hostView[tNode.injectorIndex + PARENT_INJECTOR] == null) {
|
||||||
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
return view[tNode.injectorIndex];
|
return tNode.injectorIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getParentInjector(tNode: TNode, view: LViewData): LInjector {
|
/**
|
||||||
|
* Finds the index of the parent injector, with a view offset if applicable. Used to set the
|
||||||
|
* parent injector initially.
|
||||||
|
*/
|
||||||
|
export function getParentInjectorLocation(tNode: TNode, view: LViewData): number {
|
||||||
if (tNode.parent && tNode.parent.injectorIndex !== -1) {
|
if (tNode.parent && tNode.parent.injectorIndex !== -1) {
|
||||||
return view[tNode.parent.injectorIndex];
|
return tNode.parent.injectorIndex; // view offset is 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// For most cases, the parent injector index can be found on the host node (e.g. for component
|
// For most cases, the parent injector index can be found on the host node (e.g. for component
|
||||||
// or container), so this loop will be skipped, but we must keep the loop here to support
|
// or container), so this loop will be skipped, but we must keep the loop here to support
|
||||||
// the rarer case of deeply nested <ng-template> tags.
|
// the rarer case of deeply nested <ng-template> tags or inline views.
|
||||||
let hostTNode = view[HOST_NODE];
|
let hostTNode = view[HOST_NODE];
|
||||||
|
let viewOffset = 1;
|
||||||
while (hostTNode && hostTNode.injectorIndex === -1) {
|
while (hostTNode && hostTNode.injectorIndex === -1) {
|
||||||
view = view[DECLARATION_VIEW] !;
|
view = view[DECLARATION_VIEW] !;
|
||||||
hostTNode = view[HOST_NODE] !;
|
hostTNode = view[HOST_NODE] !;
|
||||||
|
viewOffset++;
|
||||||
}
|
}
|
||||||
return hostTNode ? view[DECLARATION_VIEW] ![hostTNode.injectorIndex] : null;
|
return hostTNode ?
|
||||||
|
hostTNode.injectorIndex | (viewOffset << InjectorLocationFlags.ViewOffsetShift) :
|
||||||
|
-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unwraps a parent injector location number to find the view offset from the current injector,
|
||||||
|
* then walks up the declaration view tree until the view is found that contains the parent
|
||||||
|
* injector.
|
||||||
|
*
|
||||||
|
* @param location The location of the parent injector, which contains the view offset
|
||||||
|
* @param startView The LViewData instance from which to start walking up the view tree
|
||||||
|
* @returns The LViewData instance that contains the parent injector
|
||||||
|
*/
|
||||||
|
export function getParentInjectorView(location: number, startView: LViewData): LViewData {
|
||||||
|
let viewOffset = location >> InjectorLocationFlags.ViewOffsetShift;
|
||||||
|
let parentView = startView;
|
||||||
|
// For most cases, the parent injector can be found on the host node (e.g. for component
|
||||||
|
// or container), but we must keep the loop here to support the rarer case of deeply nested
|
||||||
|
// <ng-template> tags or inline views, where the parent injector might live many views
|
||||||
|
// above the child injector.
|
||||||
|
while (viewOffset > 0) {
|
||||||
|
parentView = parentView[DECLARATION_VIEW] !;
|
||||||
|
viewOffset--;
|
||||||
|
}
|
||||||
|
return parentView;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -161,8 +195,9 @@ export function getParentInjector(tNode: TNode, view: LViewData): LInjector {
|
|||||||
* @param di The node injector in which a directive will be added
|
* @param di The node injector in which a directive will be added
|
||||||
* @param def The definition of the directive to be made public
|
* @param def The definition of the directive to be made public
|
||||||
*/
|
*/
|
||||||
export function diPublicInInjector(di: LInjector, def: DirectiveDefInternal<any>): void {
|
export function diPublicInInjector(
|
||||||
bloomAdd(di, def.type);
|
injectorIndex: number, view: LViewData, def: DirectiveDefInternal<any>): void {
|
||||||
|
bloomAdd(injectorIndex, view[TVIEW], def.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -171,7 +206,7 @@ export function diPublicInInjector(di: LInjector, def: DirectiveDefInternal<any>
|
|||||||
* @param def The definition of the directive to be made public
|
* @param def The definition of the directive to be made public
|
||||||
*/
|
*/
|
||||||
export function diPublic(def: DirectiveDefInternal<any>): void {
|
export function diPublic(def: DirectiveDefInternal<any>): void {
|
||||||
diPublicInInjector(getOrCreateNodeInjector(), def);
|
diPublicInInjector(getOrCreateNodeInjector(), _getViewData(), def);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -199,11 +234,11 @@ export function directiveInject<T>(token: Type<T>| InjectionToken<T>): T;
|
|||||||
export function directiveInject<T>(token: Type<T>| InjectionToken<T>, flags: InjectFlags): T;
|
export function directiveInject<T>(token: Type<T>| InjectionToken<T>, flags: InjectFlags): T;
|
||||||
export function directiveInject<T>(
|
export function directiveInject<T>(
|
||||||
token: Type<T>| InjectionToken<T>, flags = InjectFlags.Default): T|null {
|
token: Type<T>| InjectionToken<T>, flags = InjectFlags.Default): T|null {
|
||||||
return getOrCreateInjectable<T>(getOrCreateNodeInjector(), token, flags);
|
return getOrCreateInjectable<T>(getOrCreateNodeInjector(), _getViewData(), token, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function injectRenderer2(): Renderer2 {
|
export function injectRenderer2(): Renderer2 {
|
||||||
return getOrCreateRenderer2(getOrCreateNodeInjector());
|
return getOrCreateRenderer2(_getViewData());
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Inject static attribute value into directive constructor.
|
* Inject static attribute value into directive constructor.
|
||||||
@ -254,8 +289,8 @@ export function injectAttribute(attrNameToInject: string): string|undefined {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOrCreateRenderer2(di: LInjector): Renderer2 {
|
function getOrCreateRenderer2(view: LViewData): Renderer2 {
|
||||||
const renderer = di.view[RENDERER];
|
const renderer = view[RENDERER];
|
||||||
if (isProceduralRenderer(renderer)) {
|
if (isProceduralRenderer(renderer)) {
|
||||||
return renderer as Renderer2;
|
return renderer as Renderer2;
|
||||||
} else {
|
} else {
|
||||||
@ -275,7 +310,7 @@ function getOrCreateRenderer2(di: LInjector): Renderer2 {
|
|||||||
* @returns the value from the injector or `null` when not found
|
* @returns the value from the injector or `null` when not found
|
||||||
*/
|
*/
|
||||||
export function getOrCreateInjectable<T>(
|
export function getOrCreateInjectable<T>(
|
||||||
nodeInjector: LInjector, token: Type<T>| InjectionToken<T>,
|
startInjectorIndex: number, hostView: LViewData, token: Type<T>| InjectionToken<T>,
|
||||||
flags: InjectFlags = InjectFlags.Default): T|null {
|
flags: InjectFlags = InjectFlags.Default): T|null {
|
||||||
const bloomHash = bloomHashBitOrFactory(token);
|
const bloomHash = bloomHashBitOrFactory(token);
|
||||||
// If the ID stored here is a function, this is a special object like ElementRef or TemplateRef
|
// If the ID stored here is a function, this is a special object like ElementRef or TemplateRef
|
||||||
@ -285,60 +320,73 @@ export function getOrCreateInjectable<T>(
|
|||||||
// If the token has a bloom hash, then it is a directive that is public to the injection system
|
// If the token has a bloom hash, then it is a directive that is public to the injection system
|
||||||
// (diPublic) otherwise fall back to the module injector.
|
// (diPublic) otherwise fall back to the module injector.
|
||||||
if (bloomHash != null) {
|
if (bloomHash != null) {
|
||||||
let injector: LInjector|null = nodeInjector;
|
let injectorIndex = startInjectorIndex;
|
||||||
|
let injectorView = hostView;
|
||||||
|
|
||||||
while (injector) {
|
if (flags & InjectFlags.SkipSelf) {
|
||||||
// Get the closest potential matching injector (upwards in the injector tree) that
|
const parentLocation = injectorView[injectorIndex + PARENT_INJECTOR];
|
||||||
// *potentially* has the token.
|
injectorIndex = parentLocation & InjectorLocationFlags.InjectorIndexMask;
|
||||||
injector = bloomFindPossibleInjector(injector, bloomHash, flags);
|
injectorView = getParentInjectorView(parentLocation, injectorView);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (injectorIndex !== -1) {
|
||||||
|
// Traverse up the injector tree until we find a potential match or until we know there
|
||||||
|
// *isn't* a match. Outer loop is necessary in case we get a false positive injector.
|
||||||
|
while (injectorIndex !== -1) {
|
||||||
|
// Check the current injector. If it matches, stop searching for an injector.
|
||||||
|
if (injectorHasToken(bloomHash, injectorIndex, injectorView[TVIEW].data)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & InjectFlags.Self ||
|
||||||
|
flags & InjectFlags.Host &&
|
||||||
|
!sameHostView(injectorView[injectorIndex + PARENT_INJECTOR])) {
|
||||||
|
injectorIndex = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the ancestor bloom filter value has the bit corresponding to the directive, traverse
|
||||||
|
// up to find the specific injector. If the ancestor bloom filter does not have the bit, we
|
||||||
|
// can abort.
|
||||||
|
if (injectorHasToken(bloomHash, injectorIndex, injectorView)) {
|
||||||
|
const parentLocation = injectorView[injectorIndex + PARENT_INJECTOR];
|
||||||
|
injectorIndex = parentLocation & InjectorLocationFlags.InjectorIndexMask;
|
||||||
|
injectorView = getParentInjectorView(parentLocation, injectorView);
|
||||||
|
} else {
|
||||||
|
injectorIndex = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If no injector is found, we *know* that there is no ancestor injector that contains the
|
// If no injector is found, we *know* that there is no ancestor injector that contains the
|
||||||
// token, so we abort.
|
// token, so we abort.
|
||||||
if (!injector) {
|
if (injectorIndex === -1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point, we have an injector which *may* contain the token, so we step through the
|
// At this point, we have an injector which *may* contain the token, so we step through the
|
||||||
// directives associated with the injector's corresponding node to get the directive instance.
|
// directives associated with the injector's corresponding node to get the directive instance.
|
||||||
const tNode = injector.tNode;
|
let instance: T|null;
|
||||||
const injectorView = injector.view;
|
if (instance = searchDirectivesOnInjector<T>(injectorIndex, injectorView, token)) {
|
||||||
const nodeFlags = tNode.flags;
|
return instance;
|
||||||
const count = nodeFlags & TNodeFlags.DirectiveCountMask;
|
|
||||||
|
|
||||||
if (count !== 0) {
|
|
||||||
const start = nodeFlags >> TNodeFlags.DirectiveStartingIndexShift;
|
|
||||||
const end = start + count;
|
|
||||||
const defs = injectorView[TVIEW].directives !;
|
|
||||||
|
|
||||||
for (let i = start; i < end; i++) {
|
|
||||||
// Get the definition for the directive at this index and, if it is injectable (diPublic),
|
|
||||||
// and matches the given token, return the directive instance.
|
|
||||||
const directiveDef = defs[i] as DirectiveDefInternal<any>;
|
|
||||||
if (directiveDef.type === token && directiveDef.diPublic) {
|
|
||||||
return injectorView[DIRECTIVES] ![i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we *didn't* find the directive for the token and we are searching the current node's
|
// If we *didn't* find the directive for the token and we are searching the current node's
|
||||||
// injector, it's possible the directive is on this node and hasn't been created yet.
|
// injector, it's possible the directive is on this node and hasn't been created yet.
|
||||||
let instance: T|null;
|
if (injectorIndex === startInjectorIndex && hostView === injectorView &&
|
||||||
if (injector === nodeInjector &&
|
|
||||||
(instance = searchMatchesQueuedForCreation<T>(token, injectorView[TVIEW]))) {
|
(instance = searchMatchesQueuedForCreation<T>(token, injectorView[TVIEW]))) {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The def wasn't found anywhere on this node, so it was a false positive.
|
// The def wasn't found anywhere on this node, so it was a false positive.
|
||||||
// If flags permit, traverse up the tree and continue searching.
|
// Traverse up the tree and continue searching.
|
||||||
if (flags & InjectFlags.Self || flags & InjectFlags.Host && !sameHostView(injector)) {
|
const parentLocation = injectorView[injectorIndex + PARENT_INJECTOR];
|
||||||
injector = null;
|
injectorIndex = parentLocation & InjectorLocationFlags.InjectorIndexMask;
|
||||||
} else {
|
injectorView = getParentInjectorView(parentLocation, injectorView);
|
||||||
injector = injector.parent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const moduleInjector = nodeInjector.view[INJECTOR];
|
const moduleInjector = hostView[INJECTOR];
|
||||||
const formerInjector = setCurrentInjector(moduleInjector);
|
const formerInjector = setCurrentInjector(moduleInjector);
|
||||||
try {
|
try {
|
||||||
return inject(token, flags);
|
return inject(token, flags);
|
||||||
@ -360,6 +408,29 @@ function searchMatchesQueuedForCreation<T>(token: any, hostTView: TView): T|null
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function searchDirectivesOnInjector<T>(
|
||||||
|
injectorIndex: number, injectorView: LViewData, token: Type<T>| InjectionToken<T>) {
|
||||||
|
const tNode = injectorView[TVIEW].data[injectorIndex + TNODE] as TNode;
|
||||||
|
const nodeFlags = tNode.flags;
|
||||||
|
const count = nodeFlags & TNodeFlags.DirectiveCountMask;
|
||||||
|
|
||||||
|
if (count !== 0) {
|
||||||
|
const start = nodeFlags >> TNodeFlags.DirectiveStartingIndexShift;
|
||||||
|
const end = start + count;
|
||||||
|
const defs = injectorView[TVIEW].directives !;
|
||||||
|
|
||||||
|
for (let i = start; i < end; i++) {
|
||||||
|
// Get the definition for the directive at this index and, if it is injectable (diPublic),
|
||||||
|
// and matches the given token, return the directive instance.
|
||||||
|
const directiveDef = defs[i] as DirectiveDefInternal<any>;
|
||||||
|
if (directiveDef.type === token && directiveDef.diPublic) {
|
||||||
|
return injectorView[DIRECTIVES] ![i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the bit in an injector's bloom filter that should be used to determine whether or not
|
* Returns the bit in an injector's bloom filter that should be used to determine whether or not
|
||||||
* the directive might be provided by the injector.
|
* the directive might be provided by the injector.
|
||||||
@ -371,108 +442,67 @@ function searchMatchesQueuedForCreation<T>(token: any, hostTView: TView): T|null
|
|||||||
* @param token the injection token
|
* @param token the injection token
|
||||||
* @returns the matching bit to check in the bloom filter or `null` if the token is not known.
|
* @returns the matching bit to check in the bloom filter or `null` if the token is not known.
|
||||||
*/
|
*/
|
||||||
function bloomHashBitOrFactory(token: Type<any>| InjectionToken<any>): number|Function|undefined {
|
export function bloomHashBitOrFactory(token: Type<any>| InjectionToken<any>): number|Function|
|
||||||
const tokenId: number|undefined = (token as any)[NG_ELEMENT_ID] || null;
|
undefined {
|
||||||
|
const tokenId: number|undefined = (token as any)[NG_ELEMENT_ID];
|
||||||
return typeof tokenId === 'number' ? tokenId & BLOOM_MASK : tokenId;
|
return typeof tokenId === 'number' ? tokenId & BLOOM_MASK : tokenId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export function injectorHasToken(
|
||||||
* Finds the closest injector that might have a certain directive.
|
bloomHash: number, injectorIndex: number, injectorView: LViewData | TData) {
|
||||||
*
|
|
||||||
* Each directive corresponds to a bit in an injector's bloom filter. Given the bloom bit to
|
|
||||||
* check and a starting injector, this function traverses up injectors until it finds an
|
|
||||||
* injector that contains a 1 for that bit in its bloom filter. A 1 indicates that the
|
|
||||||
* injector may have that directive. It only *may* have the directive because directives begin
|
|
||||||
* to share bloom filter bits after the BLOOM_SIZE is reached, and it could correspond to a
|
|
||||||
* different directive sharing the bit.
|
|
||||||
*
|
|
||||||
* Note: We can skip checking further injectors up the tree if an injector's cbf structure
|
|
||||||
* has a 0 for that bloom bit. Since cbf contains the merged value of all the parent
|
|
||||||
* injectors, a 0 in the bloom bit indicates that the parents definitely do not contain
|
|
||||||
* the directive and do not need to be checked.
|
|
||||||
*
|
|
||||||
* @param injector The starting node injector to check
|
|
||||||
* @param bloomBit The bit to check in each injector's bloom filter
|
|
||||||
* @param flags The injection flags for this injection site (e.g. Optional or SkipSelf)
|
|
||||||
* @returns An injector that might have the directive
|
|
||||||
*/
|
|
||||||
export function bloomFindPossibleInjector(
|
|
||||||
startInjector: LInjector, bloomBit: number, flags: InjectFlags): LInjector|null {
|
|
||||||
// Create a mask that targets the specific bit associated with the directive we're looking for.
|
// Create a mask that targets the specific bit associated with the directive we're looking for.
|
||||||
// JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
|
// JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
|
||||||
// to bit positions 0 - 31 in a 32 bit integer.
|
// to bit positions 0 - 31 in a 32 bit integer.
|
||||||
const mask = 1 << bloomBit;
|
const mask = 1 << bloomHash;
|
||||||
const b7 = bloomBit & 0x80;
|
const b7 = bloomHash & 0x80;
|
||||||
const b6 = bloomBit & 0x40;
|
const b6 = bloomHash & 0x40;
|
||||||
const b5 = bloomBit & 0x20;
|
const b5 = bloomHash & 0x20;
|
||||||
|
|
||||||
// Traverse up the injector tree until we find a potential match or until we know there *isn't* a
|
// Our bloom filter size is 256 bits, which is eight 32-bit bloom filter buckets:
|
||||||
// match.
|
// bf0 = [0 - 31], bf1 = [32 - 63], bf2 = [64 - 95], bf3 = [96 - 127], etc.
|
||||||
let injector: LInjector|null =
|
// Get the bloom filter value from the appropriate bucket based on the directive's bloomBit.
|
||||||
flags & InjectFlags.SkipSelf ? startInjector.parent : startInjector;
|
let value: number;
|
||||||
|
|
||||||
while (injector) {
|
if (b7) {
|
||||||
// Our bloom filter size is 256 bits, which is eight 32-bit bloom filter buckets:
|
value = b6 ? (b5 ? injectorView[injectorIndex + 7] : injectorView[injectorIndex + 6]) :
|
||||||
// bf0 = [0 - 31], bf1 = [32 - 63], bf2 = [64 - 95], bf3 = [96 - 127], etc.
|
(b5 ? injectorView[injectorIndex + 5] : injectorView[injectorIndex + 4]);
|
||||||
// Get the bloom filter value from the appropriate bucket based on the directive's bloomBit.
|
} else {
|
||||||
let value: number;
|
value = b6 ? (b5 ? injectorView[injectorIndex + 3] : injectorView[injectorIndex + 2]) :
|
||||||
|
(b5 ? injectorView[injectorIndex + 1] : injectorView[injectorIndex]);
|
||||||
if (b7) {
|
|
||||||
value = b6 ? (b5 ? injector.bf7 : injector.bf6) : (b5 ? injector.bf5 : injector.bf4);
|
|
||||||
} else {
|
|
||||||
value = b6 ? (b5 ? injector.bf3 : injector.bf2) : (b5 ? injector.bf1 : injector.bf0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the bloom filter value has the bit corresponding to the directive's bloomBit flipped on,
|
|
||||||
// this injector is a potential match.
|
|
||||||
if (value & mask) {
|
|
||||||
return injector;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & InjectFlags.Self || flags & InjectFlags.Host && !sameHostView(injector)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the current injector does not have the directive, check the bloom filters for the ancestor
|
|
||||||
// injectors (cbf0 - cbf7). These filters capture *all* ancestor injectors.
|
|
||||||
if (b7) {
|
|
||||||
value = b6 ? (b5 ? injector.cbf7 : injector.cbf6) : (b5 ? injector.cbf5 : injector.cbf4);
|
|
||||||
} else {
|
|
||||||
value = b6 ? (b5 ? injector.cbf3 : injector.cbf2) : (b5 ? injector.cbf1 : injector.cbf0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the ancestor bloom filter value has the bit corresponding to the directive, traverse up to
|
|
||||||
// find the specific injector. If the ancestor bloom filter does not have the bit, we can abort.
|
|
||||||
if (value & mask) {
|
|
||||||
injector = injector.parent;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
// If the bloom filter value has the bit corresponding to the directive's bloomBit flipped on,
|
||||||
|
// this injector is a potential match.
|
||||||
|
return !!(value & mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the current injector and its parent are in the same host view.
|
* Checks whether the current injector and its parent are in the same host view.
|
||||||
*
|
*
|
||||||
* This is necessary to support @Host() decorators. If @Host() is set, we should stop searching once
|
* This is necessary to support @Host() decorators. If @Host() is set, we should stop searching once
|
||||||
* the injector and its parent view don't match because it means we'd cross the view boundary.
|
* the injector and its parent view don't match because it means we'd cross the view boundary.
|
||||||
*/
|
*/
|
||||||
function sameHostView(injector: LInjector): boolean {
|
function sameHostView(parentLocation: number): boolean {
|
||||||
return !!injector.parent && injector.parent.view === injector.view;
|
return !!parentLocation && (parentLocation >> InjectorLocationFlags.ViewOffsetShift) === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NodeInjector implements Injector {
|
export class NodeInjector implements Injector {
|
||||||
constructor(private _lInjector: LInjector) {}
|
private _injectorIndex: number;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private _tNode: TElementNode|TContainerNode|TElementContainerNode,
|
||||||
|
private _hostView: LViewData) {
|
||||||
|
this._injectorIndex = getOrCreateNodeInjectorForNode(_tNode, _hostView);
|
||||||
|
}
|
||||||
|
|
||||||
get(token: any): any {
|
get(token: any): any {
|
||||||
if (token === Renderer2) {
|
if (token === Renderer2) {
|
||||||
return getOrCreateRenderer2(this._lInjector);
|
return getOrCreateRenderer2(this._hostView);
|
||||||
}
|
}
|
||||||
|
|
||||||
setEnvironment(this._lInjector.tNode, this._lInjector.view);
|
setEnvironment(this._tNode, this._hostView);
|
||||||
return getOrCreateInjectable(this._lInjector, token);
|
return getOrCreateInjectable(this._injectorIndex, this._hostView, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export function getFactoryOf<T>(type: Type<any>): ((type?: Type<T>) => T)|null {
|
export function getFactoryOf<T>(type: Type<any>): ((type?: Type<T>) => T)|null {
|
||||||
|
@ -19,7 +19,6 @@ import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComp
|
|||||||
import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks';
|
import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks';
|
||||||
import {ACTIVE_INDEX, LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
|
import {ACTIVE_INDEX, LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
|
||||||
import {ComponentDefInternal, ComponentQuery, ComponentTemplate, DirectiveDefInternal, DirectiveDefListOrFactory, InitialStylingFlags, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
|
import {ComponentDefInternal, ComponentQuery, ComponentTemplate, DirectiveDefInternal, DirectiveDefListOrFactory, InitialStylingFlags, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
|
||||||
import {LInjector} from './interfaces/injector';
|
|
||||||
import {AttributeMarker, InitialInputData, InitialInputs, LContainerNode, LElementContainerNode, LElementNode, LNode, LProjectionNode, LTextNode, LViewNode, LocalRefExtractor, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TProjectionNode, TViewNode} from './interfaces/node';
|
import {AttributeMarker, InitialInputData, InitialInputs, LContainerNode, LElementContainerNode, LElementNode, LNode, LProjectionNode, LTextNode, LViewNode, LocalRefExtractor, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TProjectionNode, TViewNode} from './interfaces/node';
|
||||||
import {CssSelectorList, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
|
import {CssSelectorList, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
|
||||||
import {LQueries} from './interfaces/query';
|
import {LQueries} from './interfaces/query';
|
||||||
@ -1106,8 +1105,8 @@ export function createTView(
|
|||||||
template: templateFn,
|
template: templateFn,
|
||||||
viewQuery: viewQuery,
|
viewQuery: viewQuery,
|
||||||
node: null !,
|
node: null !,
|
||||||
data: HEADER_FILLER.slice(), // Fill in to match HEADER_OFFSET in LViewData
|
data: blueprint.slice(), // Fill in to match HEADER_OFFSET in LViewData
|
||||||
childIndex: -1, // Children set in addToViewTree(), if any
|
childIndex: -1, // Children set in addToViewTree(), if any
|
||||||
bindingStartIndex: bindingStartIndex,
|
bindingStartIndex: bindingStartIndex,
|
||||||
hostBindingStartIndex: initialViewLength,
|
hostBindingStartIndex: initialViewLength,
|
||||||
directives: null,
|
directives: null,
|
||||||
|
@ -7,71 +7,97 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import {ChangeDetectorRef} from '../../change_detection/change_detector_ref';
|
|
||||||
import {ElementRef} from '../../linker/element_ref';
|
|
||||||
import {TemplateRef} from '../../linker/template_ref';
|
|
||||||
import {ViewContainerRef} from '../../linker/view_container_ref';
|
|
||||||
|
|
||||||
import {TContainerNode, TElementContainerNode, TElementNode,} from './node';
|
import {TContainerNode, TElementContainerNode, TElementNode,} from './node';
|
||||||
import {LViewData} from './view';
|
|
||||||
|
|
||||||
export interface LInjector {
|
export const TNODE = 8;
|
||||||
/**
|
export const PARENT_INJECTOR = 8;
|
||||||
* We need to store a reference to the injector's parent so DI can keep looking up
|
export const INJECTOR_SIZE = 9;
|
||||||
* the injector tree until it finds the dependency it's looking for.
|
|
||||||
*/
|
|
||||||
readonly parent: LInjector|null;
|
|
||||||
|
|
||||||
/** Necessary to find directive indices for a particular node and look up the LNode. */
|
export const enum InjectorLocationFlags {
|
||||||
readonly tNode: TElementNode|TElementContainerNode|TContainerNode;
|
InjectorIndexMask = 0b111111111111111,
|
||||||
|
ViewOffsetShift = 15
|
||||||
/**
|
|
||||||
* The view where the node is stored. Necessary because as we traverse up the injector
|
|
||||||
* tree the view where we search directives may change.
|
|
||||||
*/
|
|
||||||
readonly view: LViewData;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 32-63
|
|
||||||
* - bf2: Check directive IDs 64-95
|
|
||||||
* - bf3: Check directive IDs 96-127
|
|
||||||
* - bf4: Check directive IDs 128-159
|
|
||||||
* - bf5: Check directive IDs 160 - 191
|
|
||||||
* - bf6: Check directive IDs 192 - 223
|
|
||||||
* - bf7: Check directive IDs 224 - 255
|
|
||||||
*
|
|
||||||
* See: https://en.wikipedia.org/wiki/Bloom_filter for more about bloom filters.
|
|
||||||
*/
|
|
||||||
bf0: number;
|
|
||||||
bf1: number;
|
|
||||||
bf2: number;
|
|
||||||
bf3: number;
|
|
||||||
bf4: number;
|
|
||||||
bf5: number;
|
|
||||||
bf6: number;
|
|
||||||
bf7: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* cbf0 - cbf7 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;
|
|
||||||
cbf4: number;
|
|
||||||
cbf5: number;
|
|
||||||
cbf6: number;
|
|
||||||
cbf7: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Each injector is saved in 9 contiguous slots in `LViewData` and 9 contiguous slots in
|
||||||
|
* `TView.data`. This allows us to store information about the current node's tokens (which
|
||||||
|
* can be shared in `TView`) as well as the tokens of its ancestor nodes (which cannot be
|
||||||
|
* shared, so they live in `LViewData`).
|
||||||
|
*
|
||||||
|
* Each of these slots (aside from the last slot) contains a bloom filter. This 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.
|
||||||
|
*
|
||||||
|
* See: https://en.wikipedia.org/wiki/Bloom_filter for more about bloom filters.
|
||||||
|
*
|
||||||
|
* Because all injectors have been flattened into `LViewData` and `TViewData`, they cannot typed
|
||||||
|
* using interfaces as they were previously. The start index of each `LInjector` and `TInjector`
|
||||||
|
* will differ based on where it is flattened into the main array, so it's not possible to know
|
||||||
|
* the indices ahead of time and save their types here. The interfaces are still included here
|
||||||
|
* for documentation purposes.
|
||||||
|
*
|
||||||
|
* export interface LInjector extends Array<any> {
|
||||||
|
*
|
||||||
|
* // Cumulative bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE)
|
||||||
|
* [0]: number;
|
||||||
|
*
|
||||||
|
* // Cumulative bloom for directive IDs 32-63
|
||||||
|
* [1]: number;
|
||||||
|
*
|
||||||
|
* // Cumulative bloom for directive IDs 64-95
|
||||||
|
* [2]: number;
|
||||||
|
*
|
||||||
|
* // Cumulative bloom for directive IDs 96-127
|
||||||
|
* [3]: number;
|
||||||
|
*
|
||||||
|
* // Cumulative bloom for directive IDs 128-159
|
||||||
|
* [4]: number;
|
||||||
|
*
|
||||||
|
* // Cumulative bloom for directive IDs 160 - 191
|
||||||
|
* [5]: number;
|
||||||
|
*
|
||||||
|
* // Cumulative bloom for directive IDs 192 - 223
|
||||||
|
* [6]: number;
|
||||||
|
*
|
||||||
|
* // Cumulative bloom for directive IDs 224 - 255
|
||||||
|
* [7]: number;
|
||||||
|
*
|
||||||
|
* // 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.
|
||||||
|
* [PARENT_INJECTOR]: number;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* export interface TInjector extends Array<any> {
|
||||||
|
*
|
||||||
|
* // Shared node bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE)
|
||||||
|
* [0]: number;
|
||||||
|
*
|
||||||
|
* // Shared node bloom for directive IDs 32-63
|
||||||
|
* [1]: number;
|
||||||
|
*
|
||||||
|
* // Shared node bloom for directive IDs 64-95
|
||||||
|
* [2]: number;
|
||||||
|
*
|
||||||
|
* // Shared node bloom for directive IDs 96-127
|
||||||
|
* [3]: number;
|
||||||
|
*
|
||||||
|
* // Shared node bloom for directive IDs 128-159
|
||||||
|
* [4]: number;
|
||||||
|
*
|
||||||
|
* // Shared node bloom for directive IDs 160 - 191
|
||||||
|
* [5]: number;
|
||||||
|
*
|
||||||
|
* // Shared node bloom for directive IDs 192 - 223
|
||||||
|
* [6]: number;
|
||||||
|
*
|
||||||
|
* // Shared node bloom for directive IDs 224 - 255
|
||||||
|
* [7]: number;
|
||||||
|
*
|
||||||
|
* // Necessary to find directive indices for a particular node.
|
||||||
|
* [TNODE]: TElementNode|TElementContainerNode|TContainerNode;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
// Note: This hack is necessary so we don't erroneously get a circular dependency
|
// Note: This hack is necessary so we don't erroneously get a circular dependency
|
||||||
// failure based on types.
|
// failure based on types.
|
||||||
export const unusedValueExportToPlacateAjd = 1;
|
export const unusedValueExportToPlacateAjd = 1;
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {LContainer} from './container';
|
import {LContainer} from './container';
|
||||||
import {LInjector} from './injector';
|
|
||||||
import {LQueries} from './query';
|
|
||||||
import {RComment, RElement, RText} from './renderer';
|
import {RComment, RElement, RText} from './renderer';
|
||||||
import {StylingContext} from './styling';
|
import {StylingContext} from './styling';
|
||||||
import {LViewData, TView} from './view';
|
import {LViewData, TView} from './view';
|
||||||
|
@ -550,11 +550,15 @@ export type HookData = (number | (() => void))[];
|
|||||||
* Static data that corresponds to the instance-specific data array on an LView.
|
* Static data that corresponds to the instance-specific data array on an LView.
|
||||||
*
|
*
|
||||||
* Each node's static data is stored in tData at the same index that it's stored
|
* Each node's static data is stored in tData at the same index that it's stored
|
||||||
* in the data array. Each pipe's definition is stored here at the same index
|
* in the data array. Any nodes that do not have static data store a null value in
|
||||||
* as its pipe instance in the data array. Any nodes that do not have static
|
* tData to avoid a sparse array.
|
||||||
* data store a null value in tData to avoid a sparse array.
|
*
|
||||||
|
* Each pipe's definition is stored here at the same index as its pipe instance in
|
||||||
|
* the data array.
|
||||||
|
*
|
||||||
|
* Injector bloom filters are also stored here.
|
||||||
*/
|
*/
|
||||||
export type TData = (TNode | PipeDefInternal<any>| null)[];
|
export type TData = (TNode | PipeDefInternal<any>| number | null)[];
|
||||||
|
|
||||||
/** Type for TView.currentMatches */
|
/** Type for TView.currentMatches */
|
||||||
export type CurrentMatchesList = [DirectiveDefInternal<any>, (string | number | null)];
|
export type CurrentMatchesList = [DirectiveDefInternal<any>, (string | number | null)];
|
||||||
|
@ -14,7 +14,6 @@ import {EventEmitter} from '../event_emitter';
|
|||||||
import {ElementRef as ViewEngine_ElementRef} from '../linker/element_ref';
|
import {ElementRef as ViewEngine_ElementRef} from '../linker/element_ref';
|
||||||
import {QueryList as viewEngine_QueryList} from '../linker/query_list';
|
import {QueryList as viewEngine_QueryList} from '../linker/query_list';
|
||||||
import {TemplateRef as ViewEngine_TemplateRef} from '../linker/template_ref';
|
import {TemplateRef as ViewEngine_TemplateRef} from '../linker/template_ref';
|
||||||
import {ViewContainerRef as ViewEngine_ViewContainerRef} from '../linker/view_container_ref';
|
|
||||||
import {Type} from '../type';
|
import {Type} from '../type';
|
||||||
import {getSymbolIterator} from '../util';
|
import {getSymbolIterator} from '../util';
|
||||||
|
|
||||||
@ -485,4 +484,4 @@ export function queryRefresh(queryList: QueryList<any>): boolean {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -16,16 +16,17 @@ import {ViewContainerRef as ViewEngine_ViewContainerRef} from '../linker/view_co
|
|||||||
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_ViewRef} from '../linker/view_ref';
|
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_ViewRef} from '../linker/view_ref';
|
||||||
|
|
||||||
import {assertDefined, assertGreaterThan, assertLessThan} from './assert';
|
import {assertDefined, assertGreaterThan, assertLessThan} from './assert';
|
||||||
import {NodeInjector, getInjector, getOrCreateNodeInjectorForNode, getParentInjector} from './di';
|
import {NodeInjector, getParentInjectorLocation, getParentInjectorView} from './di';
|
||||||
import {_getViewData, addToViewTree, createEmbeddedViewAndNode, createLContainer, createLNodeObject, createTNode, getPreviousOrParentTNode, getRenderer, renderEmbeddedTemplate} from './instructions';
|
import {_getViewData, addToViewTree, createEmbeddedViewAndNode, createLContainer, createLNodeObject, createTNode, getPreviousOrParentTNode, getRenderer, renderEmbeddedTemplate} from './instructions';
|
||||||
import {LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
|
import {LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
|
||||||
import {RenderFlags} from './interfaces/definition';
|
import {RenderFlags} from './interfaces/definition';
|
||||||
|
import {InjectorLocationFlags} from './interfaces/injector';
|
||||||
import {LContainerNode, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TViewNode} from './interfaces/node';
|
import {LContainerNode, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TViewNode} from './interfaces/node';
|
||||||
import {LQueries} from './interfaces/query';
|
import {LQueries} from './interfaces/query';
|
||||||
import {RComment, RElement, Renderer3} from './interfaces/renderer';
|
import {RComment, RElement, Renderer3} from './interfaces/renderer';
|
||||||
import {CONTEXT, HOST_NODE, LViewData, QUERIES, RENDERER, TView} from './interfaces/view';
|
import {CONTEXT, HOST_NODE, LViewData, QUERIES, RENDERER, TVIEW, TView} from './interfaces/view';
|
||||||
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
||||||
import {addRemoveViewFromContainer, appendChild, detachView, findComponentView, getBeforeNodeForView, getParentLNode, getRenderParent, insertView, removeView} from './node_manipulation';
|
import {addRemoveViewFromContainer, appendChild, detachView, findComponentView, getBeforeNodeForView, getRenderParent, insertView, removeView} from './node_manipulation';
|
||||||
import {getLNode, isComponent} from './util';
|
import {getLNode, isComponent} from './util';
|
||||||
import {ViewRef} from './view_ref';
|
import {ViewRef} from './view_ref';
|
||||||
|
|
||||||
@ -180,15 +181,17 @@ export function createContainerRef(
|
|||||||
return createElementRef(ElementRefToken, this._hostTNode, this._hostView);
|
return createElementRef(ElementRefToken, this._hostTNode, this._hostView);
|
||||||
}
|
}
|
||||||
|
|
||||||
get injector(): Injector {
|
get injector(): Injector { return new NodeInjector(this._hostTNode, this._hostView); }
|
||||||
const nodeInjector = getOrCreateNodeInjectorForNode(this._hostTNode, this._hostView);
|
|
||||||
return new NodeInjector(nodeInjector);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated No replacement */
|
/** @deprecated No replacement */
|
||||||
get parentInjector(): Injector {
|
get parentInjector(): Injector {
|
||||||
const parentLInjector = getParentInjector(this._hostTNode, this._hostView);
|
const parentLocation = getParentInjectorLocation(this._hostTNode, this._hostView);
|
||||||
return parentLInjector ? new NodeInjector(parentLInjector) : new NullInjector();
|
const parentView = getParentInjectorView(parentLocation, this._hostView);
|
||||||
|
const parentIndex = parentLocation & InjectorLocationFlags.InjectorIndexMask;
|
||||||
|
const parentTNode = parentView[TVIEW].data[parentIndex] as TElementNode | TContainerNode;
|
||||||
|
|
||||||
|
return parentLocation === -1 ? new NullInjector() :
|
||||||
|
new NodeInjector(parentTNode, parentView);
|
||||||
}
|
}
|
||||||
|
|
||||||
clear(): void {
|
clear(): void {
|
||||||
|
@ -68,9 +68,6 @@
|
|||||||
{
|
{
|
||||||
"name": "FLAGS"
|
"name": "FLAGS"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "HEADER_FILLER"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "HEADER_OFFSET"
|
"name": "HEADER_OFFSET"
|
||||||
},
|
},
|
||||||
@ -80,6 +77,9 @@
|
|||||||
{
|
{
|
||||||
"name": "INJECTOR$1"
|
"name": "INJECTOR$1"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "INJECTOR_SIZE"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "IterableChangeRecord_"
|
"name": "IterableChangeRecord_"
|
||||||
},
|
},
|
||||||
@ -140,6 +140,9 @@
|
|||||||
{
|
{
|
||||||
"name": "PARENT"
|
"name": "PARENT"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "PARENT_INJECTOR"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "PublicFeature"
|
"name": "PublicFeature"
|
||||||
},
|
},
|
||||||
@ -182,6 +185,9 @@
|
|||||||
{
|
{
|
||||||
"name": "TAIL"
|
"name": "TAIL"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "TNODE"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "TVIEW"
|
"name": "TVIEW"
|
||||||
},
|
},
|
||||||
@ -302,9 +308,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bloomAdd"
|
"name": "bloomAdd"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "bloomFindPossibleInjector"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "bloomHashBitOrFactory"
|
"name": "bloomHashBitOrFactory"
|
||||||
},
|
},
|
||||||
@ -582,7 +585,7 @@
|
|||||||
"name": "getInjectableDef"
|
"name": "getInjectableDef"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getInjector$1"
|
"name": "getInjectorIndex"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getLElementFromComponent"
|
"name": "getLElementFromComponent"
|
||||||
@ -621,7 +624,10 @@
|
|||||||
"name": "getOrCreateTView"
|
"name": "getOrCreateTView"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getParentInjector"
|
"name": "getParentInjectorLocation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "getParentInjectorView"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getParentLNode"
|
"name": "getParentLNode"
|
||||||
@ -707,6 +713,9 @@
|
|||||||
{
|
{
|
||||||
"name": "injectViewContainerRef"
|
"name": "injectViewContainerRef"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "injectorHasToken"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "insertNewMultiProperty"
|
"name": "insertNewMultiProperty"
|
||||||
},
|
},
|
||||||
@ -911,6 +920,9 @@
|
|||||||
{
|
{
|
||||||
"name": "scheduleTick"
|
"name": "scheduleTick"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "searchDirectivesOnInjector"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "searchMatchesQueuedForCreation"
|
"name": "searchMatchesQueuedForCreation"
|
||||||
},
|
},
|
||||||
|
@ -38,9 +38,6 @@
|
|||||||
{
|
{
|
||||||
"name": "FLAGS"
|
"name": "FLAGS"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "HEADER_FILLER"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "HEADER_OFFSET"
|
"name": "HEADER_OFFSET"
|
||||||
},
|
},
|
||||||
@ -50,6 +47,9 @@
|
|||||||
{
|
{
|
||||||
"name": "INJECTOR$1"
|
"name": "INJECTOR$1"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "INJECTOR_SIZE"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "MONKEY_PATCH_KEY_NAME"
|
"name": "MONKEY_PATCH_KEY_NAME"
|
||||||
},
|
},
|
||||||
@ -80,6 +80,9 @@
|
|||||||
{
|
{
|
||||||
"name": "PARENT"
|
"name": "PARENT"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "PARENT_INJECTOR"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "PublicFeature"
|
"name": "PublicFeature"
|
||||||
},
|
},
|
||||||
@ -107,9 +110,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ViewEncapsulation$1"
|
"name": "ViewEncapsulation$1"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "_CLEAN_PROMISE"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "_getViewData"
|
"name": "_getViewData"
|
||||||
},
|
},
|
||||||
@ -240,7 +240,7 @@
|
|||||||
"name": "getHostElementNode"
|
"name": "getHostElementNode"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getInjector$1"
|
"name": "getInjectorIndex"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getLNode"
|
"name": "getLNode"
|
||||||
@ -258,7 +258,10 @@
|
|||||||
"name": "getOrCreateTView"
|
"name": "getOrCreateTView"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getParentInjector"
|
"name": "getParentInjectorLocation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "getParentInjectorView"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getParentLNode"
|
"name": "getParentLNode"
|
||||||
|
@ -53,9 +53,6 @@
|
|||||||
{
|
{
|
||||||
"name": "FLAGS"
|
"name": "FLAGS"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "HEADER_FILLER"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "HEADER_OFFSET"
|
"name": "HEADER_OFFSET"
|
||||||
},
|
},
|
||||||
@ -65,6 +62,9 @@
|
|||||||
{
|
{
|
||||||
"name": "INJECTOR$1"
|
"name": "INJECTOR$1"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "INJECTOR_SIZE"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "IterableChangeRecord_"
|
"name": "IterableChangeRecord_"
|
||||||
},
|
},
|
||||||
@ -131,6 +131,9 @@
|
|||||||
{
|
{
|
||||||
"name": "PARENT"
|
"name": "PARENT"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "PARENT_INJECTOR"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "PublicFeature"
|
"name": "PublicFeature"
|
||||||
},
|
},
|
||||||
@ -170,6 +173,9 @@
|
|||||||
{
|
{
|
||||||
"name": "TAIL"
|
"name": "TAIL"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "TNODE"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "TVIEW"
|
"name": "TVIEW"
|
||||||
},
|
},
|
||||||
@ -368,9 +374,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bloomAdd"
|
"name": "bloomAdd"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "bloomFindPossibleInjector"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "bloomHashBitOrFactory"
|
"name": "bloomHashBitOrFactory"
|
||||||
},
|
},
|
||||||
@ -624,7 +627,7 @@
|
|||||||
"name": "getInjectableDef"
|
"name": "getInjectableDef"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getInjector$1"
|
"name": "getInjectorIndex"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getLElementFromComponent"
|
"name": "getLElementFromComponent"
|
||||||
@ -657,7 +660,10 @@
|
|||||||
"name": "getOrCreateTView"
|
"name": "getOrCreateTView"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getParentInjector"
|
"name": "getParentInjectorLocation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "getParentInjectorView"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getParentLNode"
|
"name": "getParentLNode"
|
||||||
@ -737,6 +743,9 @@
|
|||||||
{
|
{
|
||||||
"name": "injectViewContainerRef"
|
"name": "injectViewContainerRef"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "injectorHasToken"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "insertView"
|
"name": "insertView"
|
||||||
},
|
},
|
||||||
@ -935,6 +944,9 @@
|
|||||||
{
|
{
|
||||||
"name": "scheduleTick"
|
"name": "scheduleTick"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "searchDirectivesOnInjector"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "searchMatchesQueuedForCreation"
|
"name": "searchMatchesQueuedForCreation"
|
||||||
},
|
},
|
||||||
|
@ -320,9 +320,6 @@
|
|||||||
{
|
{
|
||||||
"name": "HAMMER_LOADER"
|
"name": "HAMMER_LOADER"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "HEADER_FILLER"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "HEADER_OFFSET"
|
"name": "HEADER_OFFSET"
|
||||||
},
|
},
|
||||||
@ -353,6 +350,9 @@
|
|||||||
{
|
{
|
||||||
"name": "INJECTOR$1"
|
"name": "INJECTOR$1"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "INJECTOR_SIZE"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "INSPECT_GLOBAL_NAME"
|
"name": "INSPECT_GLOBAL_NAME"
|
||||||
},
|
},
|
||||||
@ -623,6 +623,9 @@
|
|||||||
{
|
{
|
||||||
"name": "PARENT"
|
"name": "PARENT"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "PARENT_INJECTOR"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "PATTERN_SEP"
|
"name": "PATTERN_SEP"
|
||||||
},
|
},
|
||||||
@ -815,6 +818,9 @@
|
|||||||
{
|
{
|
||||||
"name": "THURSDAY"
|
"name": "THURSDAY"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "TNODE"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "TRANSITION_ID"
|
"name": "TRANSITION_ID"
|
||||||
},
|
},
|
||||||
@ -1202,9 +1208,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bloomAdd"
|
"name": "bloomAdd"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "bloomFindPossibleInjector"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "bloomHashBitOrFactory"
|
"name": "bloomHashBitOrFactory"
|
||||||
},
|
},
|
||||||
@ -1653,10 +1656,10 @@
|
|||||||
"name": "getInjectableDef"
|
"name": "getInjectableDef"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getInjector$1"
|
"name": "getInjectorDef"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getInjectorDef"
|
"name": "getInjectorIndex"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getLElementFromComponent"
|
"name": "getLElementFromComponent"
|
||||||
@ -1752,7 +1755,10 @@
|
|||||||
"name": "getOriginalError"
|
"name": "getOriginalError"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getParentInjector"
|
"name": "getParentInjectorLocation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "getParentInjectorView"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getParentLNode"
|
"name": "getParentLNode"
|
||||||
@ -1886,6 +1892,9 @@
|
|||||||
{
|
{
|
||||||
"name": "injectableDefRecord"
|
"name": "injectableDefRecord"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "injectorHasToken"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "insertView"
|
"name": "insertView"
|
||||||
},
|
},
|
||||||
@ -2282,6 +2291,9 @@
|
|||||||
{
|
{
|
||||||
"name": "scheduleTick"
|
"name": "scheduleTick"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "searchDirectivesOnInjector"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "searchMatchesQueuedForCreation"
|
"name": "searchMatchesQueuedForCreation"
|
||||||
},
|
},
|
||||||
|
@ -10,20 +10,20 @@ import {Attribute, ChangeDetectorRef, ElementRef, Host, InjectFlags, Injector, O
|
|||||||
import {RenderFlags} from '@angular/core/src/render3/interfaces/definition';
|
import {RenderFlags} from '@angular/core/src/render3/interfaces/definition';
|
||||||
|
|
||||||
import {defineComponent} from '../../src/render3/definition';
|
import {defineComponent} from '../../src/render3/definition';
|
||||||
import {bloomAdd, bloomFindPossibleInjector, getInjector, getOrCreateNodeInjector, injectAttribute} from '../../src/render3/di';
|
import {bloomAdd, bloomHashBitOrFactory as bloomHash, getOrCreateInjectable, getOrCreateNodeInjector, injectAttribute, injectorHasToken} from '../../src/render3/di';
|
||||||
import {PublicFeature, defineDirective, directiveInject, elementProperty, getCurrentView, getRenderedText, injectRenderer2, load, templateRefExtractor} from '../../src/render3/index';
|
import {PublicFeature, defineDirective, directiveInject, elementProperty, injectRenderer2, load, templateRefExtractor} from '../../src/render3/index';
|
||||||
|
|
||||||
import {bind, container, containerRefreshEnd, containerRefreshStart, createNodeAtIndex, createLViewData, createTView, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, projection, projectionDef, reference, template, text, textBinding, loadDirective, elementContainerStart, elementContainerEnd, _getViewData, getTNode} from '../../src/render3/instructions';
|
import {bind, container, containerRefreshEnd, containerRefreshStart, createNodeAtIndex, createLViewData, createTView, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, projection, projectionDef, reference, template, text, textBinding, loadDirective, elementContainerStart, elementContainerEnd, _getViewData, getTNode} from '../../src/render3/instructions';
|
||||||
import {LInjector} from '../../src/render3/interfaces/injector';
|
|
||||||
import {isProceduralRenderer} from '../../src/render3/interfaces/renderer';
|
import {isProceduralRenderer} from '../../src/render3/interfaces/renderer';
|
||||||
import {AttributeMarker, LContainerNode, LElementNode, TNodeType} from '../../src/render3/interfaces/node';
|
import {AttributeMarker, LContainerNode, LElementNode, TNodeType} from '../../src/render3/interfaces/node';
|
||||||
|
|
||||||
import {HEADER_OFFSET, LViewData, LViewFlags, TVIEW, TView} from '../../src/render3/interfaces/view';
|
import {LViewFlags} from '../../src/render3/interfaces/view';
|
||||||
import {ViewRef} from '../../src/render3/view_ref';
|
import {ViewRef} from '../../src/render3/view_ref';
|
||||||
|
|
||||||
import {getRendererFactory2} from './imported_renderer2';
|
import {getRendererFactory2} from './imported_renderer2';
|
||||||
import {ComponentFixture, createComponent, createDirective, renderComponent, toHtml} from './render_util';
|
import {ComponentFixture, createComponent, createDirective, renderComponent, toHtml} from './render_util';
|
||||||
import {NgIf} from './common_with_def';
|
import {NgIf} from './common_with_def';
|
||||||
|
import {TNODE} from '../../src/render3/interfaces/injector';
|
||||||
|
|
||||||
describe('di', () => {
|
describe('di', () => {
|
||||||
describe('no dependencies', () => {
|
describe('no dependencies', () => {
|
||||||
@ -1680,72 +1680,79 @@ describe('di', () => {
|
|||||||
|
|
||||||
describe('inject', () => {
|
describe('inject', () => {
|
||||||
describe('bloom filter', () => {
|
describe('bloom filter', () => {
|
||||||
let di: LInjector;
|
let mockTView: any;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
di = {} as any;
|
mockTView = {data: [0, 0, 0, 0, 0, 0, 0, 0, null], firstTemplatePass: true};
|
||||||
di.bf0 = 0;
|
|
||||||
di.bf1 = 0;
|
|
||||||
di.bf2 = 0;
|
|
||||||
di.bf3 = 0;
|
|
||||||
di.bf4 = 0;
|
|
||||||
di.bf5 = 0;
|
|
||||||
di.bf6 = 0;
|
|
||||||
di.bf7 = 0;
|
|
||||||
di.bf3 = 0;
|
|
||||||
di.cbf0 = 0;
|
|
||||||
di.cbf1 = 0;
|
|
||||||
di.cbf2 = 0;
|
|
||||||
di.cbf3 = 0;
|
|
||||||
di.cbf4 = 0;
|
|
||||||
di.cbf5 = 0;
|
|
||||||
di.cbf6 = 0;
|
|
||||||
di.cbf7 = 0;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function bloomState() {
|
function bloomState() { return mockTView.data.slice(0, TNODE).reverse(); }
|
||||||
return [di.bf7, di.bf6, di.bf5, di.bf4, di.bf3, di.bf2, di.bf1, di.bf0];
|
|
||||||
|
class Dir0 {
|
||||||
|
/** @internal */ static __NG_ELEMENT_ID__ = 0;
|
||||||
|
}
|
||||||
|
class Dir1 {
|
||||||
|
/** @internal */ static __NG_ELEMENT_ID__ = 1;
|
||||||
|
}
|
||||||
|
class Dir33 {
|
||||||
|
/** @internal */ static __NG_ELEMENT_ID__ = 33;
|
||||||
|
}
|
||||||
|
class Dir66 {
|
||||||
|
/** @internal */ static __NG_ELEMENT_ID__ = 66;
|
||||||
|
}
|
||||||
|
class Dir99 {
|
||||||
|
/** @internal */ static __NG_ELEMENT_ID__ = 99;
|
||||||
|
}
|
||||||
|
class Dir132 {
|
||||||
|
/** @internal */ static __NG_ELEMENT_ID__ = 132;
|
||||||
|
}
|
||||||
|
class Dir165 {
|
||||||
|
/** @internal */ static __NG_ELEMENT_ID__ = 165;
|
||||||
|
}
|
||||||
|
class Dir198 {
|
||||||
|
/** @internal */ static __NG_ELEMENT_ID__ = 198;
|
||||||
|
}
|
||||||
|
class Dir231 {
|
||||||
|
/** @internal */ static __NG_ELEMENT_ID__ = 231;
|
||||||
}
|
}
|
||||||
|
|
||||||
it('should add values', () => {
|
it('should add values', () => {
|
||||||
bloomAdd(di, { __NG_ELEMENT_ID__: 0 } as any);
|
bloomAdd(0, mockTView, Dir0);
|
||||||
expect(bloomState()).toEqual([0, 0, 0, 0, 0, 0, 0, 1]);
|
expect(bloomState()).toEqual([0, 0, 0, 0, 0, 0, 0, 1]);
|
||||||
bloomAdd(di, { __NG_ELEMENT_ID__: 32 + 1 } as any);
|
bloomAdd(0, mockTView, Dir33);
|
||||||
expect(bloomState()).toEqual([0, 0, 0, 0, 0, 0, 2, 1]);
|
expect(bloomState()).toEqual([0, 0, 0, 0, 0, 0, 2, 1]);
|
||||||
bloomAdd(di, { __NG_ELEMENT_ID__: 64 + 2 } as any);
|
bloomAdd(0, mockTView, Dir66);
|
||||||
expect(bloomState()).toEqual([0, 0, 0, 0, 0, 4, 2, 1]);
|
expect(bloomState()).toEqual([0, 0, 0, 0, 0, 4, 2, 1]);
|
||||||
bloomAdd(di, { __NG_ELEMENT_ID__: 96 + 3 } as any);
|
bloomAdd(0, mockTView, Dir99);
|
||||||
expect(bloomState()).toEqual([0, 0, 0, 0, 8, 4, 2, 1]);
|
expect(bloomState()).toEqual([0, 0, 0, 0, 8, 4, 2, 1]);
|
||||||
bloomAdd(di, { __NG_ELEMENT_ID__: 128 + 4 } as any);
|
bloomAdd(0, mockTView, Dir132);
|
||||||
expect(bloomState()).toEqual([0, 0, 0, 16, 8, 4, 2, 1]);
|
expect(bloomState()).toEqual([0, 0, 0, 16, 8, 4, 2, 1]);
|
||||||
bloomAdd(di, { __NG_ELEMENT_ID__: 160 + 5 } as any);
|
bloomAdd(0, mockTView, Dir165);
|
||||||
expect(bloomState()).toEqual([0, 0, 32, 16, 8, 4, 2, 1]);
|
expect(bloomState()).toEqual([0, 0, 32, 16, 8, 4, 2, 1]);
|
||||||
bloomAdd(di, { __NG_ELEMENT_ID__: 192 + 6 } as any);
|
bloomAdd(0, mockTView, Dir198);
|
||||||
expect(bloomState()).toEqual([0, 64, 32, 16, 8, 4, 2, 1]);
|
expect(bloomState()).toEqual([0, 64, 32, 16, 8, 4, 2, 1]);
|
||||||
bloomAdd(di, { __NG_ELEMENT_ID__: 224 + 7 } as any);
|
bloomAdd(0, mockTView, Dir231);
|
||||||
expect(bloomState()).toEqual([128, 64, 32, 16, 8, 4, 2, 1]);
|
expect(bloomState()).toEqual([128, 64, 32, 16, 8, 4, 2, 1]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should query values', () => {
|
it('should query values', () => {
|
||||||
bloomAdd(di, { __NG_ELEMENT_ID__: 0 } as any);
|
bloomAdd(0, mockTView, Dir0);
|
||||||
bloomAdd(di, { __NG_ELEMENT_ID__: 32 } as any);
|
bloomAdd(0, mockTView, Dir33);
|
||||||
bloomAdd(di, { __NG_ELEMENT_ID__: 64 } as any);
|
bloomAdd(0, mockTView, Dir66);
|
||||||
bloomAdd(di, { __NG_ELEMENT_ID__: 96 } as any);
|
bloomAdd(0, mockTView, Dir99);
|
||||||
bloomAdd(di, { __NG_ELEMENT_ID__: 127 } as any);
|
bloomAdd(0, mockTView, Dir132);
|
||||||
bloomAdd(di, { __NG_ELEMENT_ID__: 161 } as any);
|
bloomAdd(0, mockTView, Dir165);
|
||||||
bloomAdd(di, { __NG_ELEMENT_ID__: 188 } as any);
|
bloomAdd(0, mockTView, Dir198);
|
||||||
bloomAdd(di, { __NG_ELEMENT_ID__: 223 } as any);
|
bloomAdd(0, mockTView, Dir231);
|
||||||
bloomAdd(di, { __NG_ELEMENT_ID__: 255 } as any);
|
|
||||||
|
|
||||||
expect(bloomFindPossibleInjector(di, 0, InjectFlags.Default)).toEqual(di);
|
expect(injectorHasToken(bloomHash(Dir0) as number, 0, mockTView.data)).toEqual(true);
|
||||||
expect(bloomFindPossibleInjector(di, 1, InjectFlags.Default)).toEqual(null);
|
expect(injectorHasToken(bloomHash(Dir1) as number, 0, mockTView.data)).toEqual(false);
|
||||||
expect(bloomFindPossibleInjector(di, 32, InjectFlags.Default)).toEqual(di);
|
expect(injectorHasToken(bloomHash(Dir33) as number, 0, mockTView.data)).toEqual(true);
|
||||||
expect(bloomFindPossibleInjector(di, 64, InjectFlags.Default)).toEqual(di);
|
expect(injectorHasToken(bloomHash(Dir66) as number, 0, mockTView.data)).toEqual(true);
|
||||||
expect(bloomFindPossibleInjector(di, 96, InjectFlags.Default)).toEqual(di);
|
expect(injectorHasToken(bloomHash(Dir99) as number, 0, mockTView.data)).toEqual(true);
|
||||||
expect(bloomFindPossibleInjector(di, 127, InjectFlags.Default)).toEqual(di);
|
expect(injectorHasToken(bloomHash(Dir132) as number, 0, mockTView.data)).toEqual(true);
|
||||||
expect(bloomFindPossibleInjector(di, 161, InjectFlags.Default)).toEqual(di);
|
expect(injectorHasToken(bloomHash(Dir165) as number, 0, mockTView.data)).toEqual(true);
|
||||||
expect(bloomFindPossibleInjector(di, 188, InjectFlags.Default)).toEqual(di);
|
expect(injectorHasToken(bloomHash(Dir198) as number, 0, mockTView.data)).toEqual(true);
|
||||||
expect(bloomFindPossibleInjector(di, 223, InjectFlags.Default)).toEqual(di);
|
expect(injectorHasToken(bloomHash(Dir231) as number, 0, mockTView.data)).toEqual(true);
|
||||||
expect(bloomFindPossibleInjector(di, 255, InjectFlags.Default)).toEqual(di);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1778,9 +1785,11 @@ describe('di', () => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <div parentDir>
|
* <div parentDir>
|
||||||
|
* % if (...) {
|
||||||
* <span childDir child2Dir #child1="childDir" #child2="child2Dir">
|
* <span childDir child2Dir #child1="childDir" #child2="child2Dir">
|
||||||
* {{ child1.value }} - {{ child2.value }}
|
* {{ child1.value }} - {{ child2.value }}
|
||||||
* </span>
|
* </span>
|
||||||
|
* % }
|
||||||
* </div>
|
* </div>
|
||||||
*/
|
*/
|
||||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user