UNPKG

@angular/core

Version:

Angular - the core framework

750 lines 108 kB
/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import { isForwardRef, resolveForwardRef } from '../di/forward_ref'; import { injectRootLimpMode, setInjectImplementation } from '../di/inject_switch'; import { convertToBitFlags } from '../di/injector_compatibility'; import { InjectFlags } from '../di/interface/injector'; import { assertDefined, assertEqual, assertIndexInRange } from '../util/assert'; import { noSideEffects } from '../util/closure'; import { assertDirectiveDef, assertNodeInjector, assertTNodeForLView } from './assert'; import { getFactoryDef } from './definition_factory'; import { throwCyclicDependencyError, throwProviderNotFoundError } from './errors_di'; import { NG_ELEMENT_ID, NG_FACTORY_DEF } from './fields'; import { registerPreOrderHooks } from './hooks'; import { isFactory, NO_PARENT_INJECTOR } from './interfaces/injector'; import { isComponentDef, isComponentHost } from './interfaces/type_checks'; import { DECLARATION_COMPONENT_VIEW, DECLARATION_VIEW, EMBEDDED_VIEW_INJECTOR, FLAGS, INJECTOR, T_HOST, TVIEW } from './interfaces/view'; import { assertTNodeType } from './node_assert'; import { enterDI, getCurrentTNode, getLView, leaveDI } from './state'; import { isNameOnlyAttributeMarker } from './util/attrs_utils'; import { getParentInjectorIndex, getParentInjectorView, hasParentInjector } from './util/injector_utils'; import { stringifyForError } from './util/stringify_utils'; /** * Defines if the call to `inject` should include `viewProviders` in its resolution. * * This is set to true when we try to instantiate a component. This value is reset in * `getNodeInjectable` to a value which matches the declaration location of the token about to be * instantiated. This is done so that if we are injecting a token which was declared outside of * `viewProviders` we don't accidentally pull `viewProviders` in. * * Example: * * ``` * @Injectable() * class MyService { * constructor(public value: String) {} * } * * @Component({ * providers: [ * MyService, * {provide: String, value: 'providers' } * ] * viewProviders: [ * {provide: String, value: 'viewProviders'} * ] * }) * class MyComponent { * constructor(myService: MyService, value: String) { * // We expect that Component can see into `viewProviders`. * expect(value).toEqual('viewProviders'); * // `MyService` was not declared in `viewProviders` hence it can't see it. * expect(myService.value).toEqual('providers'); * } * } * * ``` */ let includeViewProviders = true; export function setIncludeViewProviders(v) { const oldValue = includeViewProviders; includeViewProviders = v; return oldValue; } /** * The number of slots in each bloom filter (used by DI). The larger this number, the fewer * directives that will share slots, and thus, the fewer false positives when checking for * the existence of a directive. */ const BLOOM_SIZE = 256; const BLOOM_MASK = BLOOM_SIZE - 1; /** * The number of bits that is represented by a single bloom bucket. JS bit operations are 32 bits, * so each bucket represents 32 distinct tokens which accounts for log2(32) = 5 bits of a bloom hash * number. */ const BLOOM_BUCKET_BITS = 5; /** Counter used to generate unique IDs for directives. */ let nextNgElementId = 0; /** Value used when something wasn't found by an injector. */ const NOT_FOUND = {}; /** * Registers this directive as present in its node's injector by flipping the directive's * corresponding bit in the injector's bloom filter. * * @param injectorIndex The index of the node injector where this token should be registered * @param tView The TView for the injector's bloom filters * @param type The directive token to register */ export function bloomAdd(injectorIndex, tView, type) { ngDevMode && assertEqual(tView.firstCreatePass, true, 'expected firstCreatePass to be true'); let id; if (typeof type === 'string') { id = type.charCodeAt(0) || 0; } else if (type.hasOwnProperty(NG_ELEMENT_ID)) { id = type[NG_ELEMENT_ID]; } // 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. if (id == null) { id = type[NG_ELEMENT_ID] = nextNgElementId++; } // 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. const bloomHash = id & BLOOM_MASK; // 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 // to bit positions 0 - 31 in a 32 bit integer. const mask = 1 << bloomHash; // Each bloom bucket in `tData` represents `BLOOM_BUCKET_BITS` number of bits of `bloomHash`. // Any bits in `bloomHash` beyond `BLOOM_BUCKET_BITS` indicate the bucket offset that the mask // should be written to. tView.data[injectorIndex + (bloomHash >> BLOOM_BUCKET_BITS)] |= mask; } /** * Creates (or gets an existing) injector for a given element or container. * * @param tNode for which an injector should be retrieved / created. * @param lView View where the node is stored * @returns Node injector */ export function getOrCreateNodeInjectorForNode(tNode, lView) { const existingInjectorIndex = getInjectorIndex(tNode, lView); if (existingInjectorIndex !== -1) { return existingInjectorIndex; } const tView = lView[TVIEW]; if (tView.firstCreatePass) { tNode.injectorIndex = lView.length; insertBloom(tView.data, tNode); // foundation for node bloom insertBloom(lView, null); // foundation for cumulative bloom insertBloom(tView.blueprint, null); } const parentLoc = getParentInjectorLocation(tNode, lView); const injectorIndex = tNode.injectorIndex; // If a parent injector can't be found, its location is set to -1. // In that case, we don't need to set up a cumulative bloom if (hasParentInjector(parentLoc)) { const parentIndex = getParentInjectorIndex(parentLoc); const parentLView = getParentInjectorView(parentLoc, lView); const parentData = parentLView[TVIEW].data; // Creates a cumulative bloom filter that merges the parent's bloom filter // and its own cumulative bloom (which contains tokens for all ancestors) for (let i = 0; i < 8 /* NodeInjectorOffset.BLOOM_SIZE */; i++) { lView[injectorIndex + i] = parentLView[parentIndex + i] | parentData[parentIndex + i]; } } lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */] = parentLoc; return injectorIndex; } function insertBloom(arr, footer) { arr.push(0, 0, 0, 0, 0, 0, 0, 0, footer); } export function getInjectorIndex(tNode, lView) { if (tNode.injectorIndex === -1 || // 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. (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 lView[tNode.injectorIndex + 8 /* NodeInjectorOffset.PARENT */] === null) { return -1; } else { ngDevMode && assertIndexInRange(lView, tNode.injectorIndex); return tNode.injectorIndex; } } /** * Finds the index of the parent injector, with a view offset if applicable. Used to set the * parent injector initially. * * @returns Returns a number that is the combination of the number of LViews that we have to go up * to find the LView containing the parent inject AND the index of the injector within that LView. */ export function getParentInjectorLocation(tNode, lView) { if (tNode.parent && tNode.parent.injectorIndex !== -1) { // If we have a parent `TNode` and there is an injector associated with it we are done, because // the parent injector is within the current `LView`. return tNode.parent.injectorIndex; // ViewOffset is 0 } // When parent injector location is computed it may be outside of the current view. (ie it could // be pointing to a declared parent location). This variable stores number of declaration parents // we need to walk up in order to find the parent injector location. let declarationViewOffset = 0; let parentTNode = null; let lViewCursor = lView; // The parent injector is not in the current `LView`. We will have to walk the declared parent // `LView` hierarchy and look for it. If we walk of the top, that means that there is no parent // `NodeInjector`. while (lViewCursor !== null) { parentTNode = getTNodeFromLView(lViewCursor); if (parentTNode === null) { // If we have no parent, than we are done. return NO_PARENT_INJECTOR; } ngDevMode && parentTNode && assertTNodeForLView(parentTNode, lViewCursor[DECLARATION_VIEW]); // Every iteration of the loop requires that we go to the declared parent. declarationViewOffset++; lViewCursor = lViewCursor[DECLARATION_VIEW]; if (parentTNode.injectorIndex !== -1) { // We found a NodeInjector which points to something. return (parentTNode.injectorIndex | (declarationViewOffset << 16 /* RelativeInjectorLocationFlags.ViewOffsetShift */)); } } return NO_PARENT_INJECTOR; } /** * Makes a type or an injection token public to the DI system by adding it to an * injector's bloom filter. * * @param di The node injector in which a directive will be added * @param token The type or the injection token to be made public */ export function diPublicInInjector(injectorIndex, tView, token) { bloomAdd(injectorIndex, tView, token); } /** * Inject static attribute value into directive constructor. * * This method is used with `factory` functions which are generated as part of * `defineDirective` or `defineComponent`. The method retrieves the static value * of an attribute. (Dynamic attributes are not supported since they are not resolved * at the time of injection and can change over time.) * * # Example * Given: * ``` * @Component(...) * class MyComponent { * constructor(@Attribute('title') title: string) { ... } * } * ``` * When instantiated with * ``` * <my-component title="Hello"></my-component> * ``` * * Then factory method generated is: * ``` * MyComponent.ɵcmp = defineComponent({ * factory: () => new MyComponent(injectAttribute('title')) * ... * }) * ``` * * @publicApi */ export function injectAttributeImpl(tNode, attrNameToInject) { ngDevMode && assertTNodeType(tNode, 12 /* TNodeType.AnyContainer */ | 3 /* TNodeType.AnyRNode */); ngDevMode && assertDefined(tNode, 'expecting tNode'); if (attrNameToInject === 'class') { return tNode.classes; } if (attrNameToInject === 'style') { return tNode.styles; } const attrs = tNode.attrs; if (attrs) { const attrsLength = attrs.length; let i = 0; while (i < attrsLength) { const value = attrs[i]; // If we hit a `Bindings` or `Template` marker then we are done. if (isNameOnlyAttributeMarker(value)) break; // Skip namespaced attributes if (value === 0 /* AttributeMarker.NamespaceURI */) { // we skip the next two values // as namespaced attributes looks like // [..., AttributeMarker.NamespaceURI, 'http://someuri.com/test', 'test:exist', // 'existValue', ...] i = i + 2; } else if (typeof value === 'number') { // Skip to the first value of the marked attribute. i++; while (i < attrsLength && typeof attrs[i] === 'string') { i++; } } else if (value === attrNameToInject) { return attrs[i + 1]; } else { i = i + 2; } } } return null; } function notFoundValueOrThrow(notFoundValue, token, flags) { if ((flags & InjectFlags.Optional) || notFoundValue !== undefined) { return notFoundValue; } else { throwProviderNotFoundError(token, 'NodeInjector'); } } /** * Returns the value associated to the given token from the ModuleInjector or throws exception * * @param lView The `LView` that contains the `tNode` * @param token The token to look for * @param flags Injection flags * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional` * @returns the value from the injector or throws an exception */ function lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue) { if ((flags & InjectFlags.Optional) && notFoundValue === undefined) { // This must be set or the NullInjector will throw for optional deps notFoundValue = null; } if ((flags & (InjectFlags.Self | InjectFlags.Host)) === 0) { const moduleInjector = lView[INJECTOR]; // switch to `injectInjectorOnly` implementation for module injector, since module injector // should not have access to Component/Directive DI scope (that may happen through // `directiveInject` implementation) const previousInjectImplementation = setInjectImplementation(undefined); try { if (moduleInjector) { return moduleInjector.get(token, notFoundValue, flags & InjectFlags.Optional); } else { return injectRootLimpMode(token, notFoundValue, flags & InjectFlags.Optional); } } finally { setInjectImplementation(previousInjectImplementation); } } return notFoundValueOrThrow(notFoundValue, token, flags); } /** * Returns the value associated to the given token from the NodeInjectors => ModuleInjector. * * Look for the injector providing the token by walking up the node injector tree and then * the module injector tree. * * This function patches `token` with `__NG_ELEMENT_ID__` which contains the id for the bloom * filter. `-1` is reserved for injecting `Injector` (implemented by `NodeInjector`) * * @param tNode The Node where the search for the injector should start * @param lView The `LView` that contains the `tNode` * @param token The token to look for * @param flags Injection flags * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional` * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided */ export function getOrCreateInjectable(tNode, lView, token, flags = InjectFlags.Default, notFoundValue) { if (tNode !== null) { // If the view or any of its ancestors have an embedded // view injector, we have to look it up there first. if (lView[FLAGS] & 1024 /* LViewFlags.HasEmbeddedViewInjector */) { const embeddedInjectorValue = lookupTokenUsingEmbeddedInjector(tNode, lView, token, flags, NOT_FOUND); if (embeddedInjectorValue !== NOT_FOUND) { return embeddedInjectorValue; } } // Otherwise try the node injector. const value = lookupTokenUsingNodeInjector(tNode, lView, token, flags, NOT_FOUND); if (value !== NOT_FOUND) { return value; } } // Finally, fall back to the module injector. return lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue); } /** * Returns the value associated to the given token from the node injector. * * @param tNode The Node where the search for the injector should start * @param lView The `LView` that contains the `tNode` * @param token The token to look for * @param flags Injection flags * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional` * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided */ function lookupTokenUsingNodeInjector(tNode, lView, token, flags, notFoundValue) { const bloomHash = bloomHashBitOrFactory(token); // If the ID stored here is a function, this is a special object like ElementRef or TemplateRef // so just call the factory function to create it. if (typeof bloomHash === 'function') { if (!enterDI(lView, tNode, flags)) { // Failed to enter DI, try module injector instead. If a token is injected with the @Host // flag, the module injector is not searched for that token in Ivy. return (flags & InjectFlags.Host) ? notFoundValueOrThrow(notFoundValue, token, flags) : lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue); } try { const value = bloomHash(flags); if (value == null && !(flags & InjectFlags.Optional)) { throwProviderNotFoundError(token); } else { return value; } } finally { leaveDI(); } } else if (typeof bloomHash === 'number') { // A reference to the previous injector TView that was found while climbing the element // injector tree. This is used to know if viewProviders can be accessed on the current // injector. let previousTView = null; let injectorIndex = getInjectorIndex(tNode, lView); let parentLocation = NO_PARENT_INJECTOR; let hostTElementNode = flags & InjectFlags.Host ? lView[DECLARATION_COMPONENT_VIEW][T_HOST] : null; // If we should skip this injector, or if there is no injector on this node, start by // searching the parent injector. if (injectorIndex === -1 || flags & InjectFlags.SkipSelf) { parentLocation = injectorIndex === -1 ? getParentInjectorLocation(tNode, lView) : lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */]; if (parentLocation === NO_PARENT_INJECTOR || !shouldSearchParent(flags, false)) { injectorIndex = -1; } else { previousTView = lView[TVIEW]; injectorIndex = getParentInjectorIndex(parentLocation); lView = getParentInjectorView(parentLocation, lView); } } // Traverse up the injector tree until we find a potential match or until we know there // *isn't* a match. while (injectorIndex !== -1) { ngDevMode && assertNodeInjector(lView, injectorIndex); // Check the current injector. If it matches, see if it contains token. const tView = lView[TVIEW]; ngDevMode && assertTNodeForLView(tView.data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */], lView); if (bloomHasToken(bloomHash, injectorIndex, tView.data)) { // At this point, we have an injector which *may* contain the token, so we step through // the providers and directives associated with the injector's corresponding node to get // the instance. const instance = searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode); if (instance !== NOT_FOUND) { return instance; } } parentLocation = lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */]; if (parentLocation !== NO_PARENT_INJECTOR && shouldSearchParent(flags, lView[TVIEW].data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */] === hostTElementNode) && bloomHasToken(bloomHash, injectorIndex, lView)) { // The def wasn't found anywhere on this node, so it was a false positive. // Traverse up the tree and continue searching. previousTView = tView; injectorIndex = getParentInjectorIndex(parentLocation); lView = getParentInjectorView(parentLocation, lView); } else { // If we should not search parent OR If the ancestor bloom filter value does not have the // bit corresponding to the directive we can give up on traversing up to find the specific // injector. injectorIndex = -1; } } } return notFoundValue; } function searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode) { const currentTView = lView[TVIEW]; const tNode = currentTView.data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */]; // First, we need to determine if view providers can be accessed by the starting element. // There are two possibilities const canAccessViewProviders = previousTView == null ? // 1) This is the first invocation `previousTView == null` which means that we are at the // `TNode` of where injector is starting to look. In such a case the only time we are allowed // to look into the ViewProviders is if: // - we are on a component // - AND the injector set `includeViewProviders` to true (implying that the token can see // ViewProviders because it is the Component or a Service which itself was declared in // ViewProviders) (isComponentHost(tNode) && includeViewProviders) : // 2) `previousTView != null` which means that we are now walking across the parent nodes. // In such a case we are only allowed to look into the ViewProviders if: // - We just crossed from child View to Parent View `previousTView != currentTView` // - AND the parent TNode is an Element. // This means that we just came from the Component's View and therefore are allowed to see // into the ViewProviders. (previousTView != currentTView && ((tNode.type & 3 /* TNodeType.AnyRNode */) !== 0)); // This special case happens when there is a @host on the inject and when we are searching // on the host element node. const isHostSpecialCase = (flags & InjectFlags.Host) && hostTElementNode === tNode; const injectableIdx = locateDirectiveOrProvider(tNode, currentTView, token, canAccessViewProviders, isHostSpecialCase); if (injectableIdx !== null) { return getNodeInjectable(lView, currentTView, injectableIdx, tNode); } else { return NOT_FOUND; } } /** * Searches for the given token among the node's directives and providers. * * @param tNode TNode on which directives are present. * @param tView The tView we are currently processing * @param token Provider token or type of a directive to look for. * @param canAccessViewProviders Whether view providers should be considered. * @param isHostSpecialCase Whether the host special case applies. * @returns Index of a found directive or provider, or null when none found. */ export function locateDirectiveOrProvider(tNode, tView, token, canAccessViewProviders, isHostSpecialCase) { const nodeProviderIndexes = tNode.providerIndexes; const tInjectables = tView.data; const injectablesStart = nodeProviderIndexes & 1048575 /* TNodeProviderIndexes.ProvidersStartIndexMask */; const directivesStart = tNode.directiveStart; const directiveEnd = tNode.directiveEnd; const cptViewProvidersCount = nodeProviderIndexes >> 20 /* TNodeProviderIndexes.CptViewProvidersCountShift */; const startingIndex = canAccessViewProviders ? injectablesStart : injectablesStart + cptViewProvidersCount; // When the host special case applies, only the viewProviders and the component are visible const endIndex = isHostSpecialCase ? injectablesStart + cptViewProvidersCount : directiveEnd; for (let i = startingIndex; i < endIndex; i++) { const providerTokenOrDef = tInjectables[i]; if (i < directivesStart && token === providerTokenOrDef || i >= directivesStart && providerTokenOrDef.type === token) { return i; } } if (isHostSpecialCase) { const dirDef = tInjectables[directivesStart]; if (dirDef && isComponentDef(dirDef) && dirDef.type === token) { return directivesStart; } } return null; } /** * Retrieve or instantiate the injectable from the `LView` at particular `index`. * * This function checks to see if the value has already been instantiated and if so returns the * cached `injectable`. Otherwise if it detects that the value is still a factory it * instantiates the `injectable` and caches the value. */ export function getNodeInjectable(lView, tView, index, tNode) { let value = lView[index]; const tData = tView.data; if (isFactory(value)) { const factory = value; if (factory.resolving) { throwCyclicDependencyError(stringifyForError(tData[index])); } const previousIncludeViewProviders = setIncludeViewProviders(factory.canSeeViewProviders); factory.resolving = true; const previousInjectImplementation = factory.injectImpl ? setInjectImplementation(factory.injectImpl) : null; const success = enterDI(lView, tNode, InjectFlags.Default); ngDevMode && assertEqual(success, true, 'Because flags do not contain \`SkipSelf\' we expect this to always succeed.'); try { value = lView[index] = factory.factory(undefined, tData, lView, tNode); // This code path is hit for both directives and providers. // For perf reasons, we want to avoid searching for hooks on providers. // It does no harm to try (the hooks just won't exist), but the extra // checks are unnecessary and this is a hot path. So we check to see // if the index of the dependency is in the directive range for this // tNode. If it's not, we know it's a provider and skip hook registration. if (tView.firstCreatePass && index >= tNode.directiveStart) { ngDevMode && assertDirectiveDef(tData[index]); registerPreOrderHooks(index, tData[index], tView); } } finally { previousInjectImplementation !== null && setInjectImplementation(previousInjectImplementation); setIncludeViewProviders(previousIncludeViewProviders); factory.resolving = false; leaveDI(); } } return value; } /** * 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. * * When a directive is public, it is added to the bloom filter and given a unique ID that can be * retrieved on the Type. When the directive isn't public or the token is not a directive `null` * is returned as the node injector can not possibly provide that token. * * @param token the injection token * @returns the matching bit to check in the bloom filter or `null` if the token is not known. * When the returned value is negative then it represents special values such as `Injector`. */ export function bloomHashBitOrFactory(token) { ngDevMode && assertDefined(token, 'token must be defined'); if (typeof token === 'string') { return token.charCodeAt(0) || 0; } const tokenId = // First check with `hasOwnProperty` so we don't get an inherited ID. token.hasOwnProperty(NG_ELEMENT_ID) ? token[NG_ELEMENT_ID] : undefined; // Negative token IDs are used for special objects such as `Injector` if (typeof tokenId === 'number') { if (tokenId >= 0) { return tokenId & BLOOM_MASK; } else { ngDevMode && assertEqual(tokenId, -1 /* InjectorMarkers.Injector */, 'Expecting to get Special Injector Id'); return createNodeInjector; } } else { return tokenId; } } export function bloomHasToken(bloomHash, injectorIndex, injectorView) { // 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 // to bit positions 0 - 31 in a 32 bit integer. const mask = 1 << bloomHash; // Each bloom bucket in `injectorView` represents `BLOOM_BUCKET_BITS` number of bits of // `bloomHash`. Any bits in `bloomHash` beyond `BLOOM_BUCKET_BITS` indicate the bucket offset // that should be used. const value = injectorView[injectorIndex + (bloomHash >> BLOOM_BUCKET_BITS)]; // 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); } /** Returns true if flags prevent parent injector from being searched for tokens */ function shouldSearchParent(flags, isFirstHostTNode) { return !(flags & InjectFlags.Self) && !(flags & InjectFlags.Host && isFirstHostTNode); } export class NodeInjector { constructor(_tNode, _lView) { this._tNode = _tNode; this._lView = _lView; } get(token, notFoundValue, flags) { return getOrCreateInjectable(this._tNode, this._lView, token, convertToBitFlags(flags), notFoundValue); } } /** Creates a `NodeInjector` for the current node. */ export function createNodeInjector() { return new NodeInjector(getCurrentTNode(), getLView()); } /** * @codeGenApi */ export function ɵɵgetInheritedFactory(type) { return noSideEffects(() => { const ownConstructor = type.prototype.constructor; const ownFactory = ownConstructor[NG_FACTORY_DEF] || getFactoryOf(ownConstructor); const objectPrototype = Object.prototype; let parent = Object.getPrototypeOf(type.prototype).constructor; // Go up the prototype until we hit `Object`. while (parent && parent !== objectPrototype) { const factory = parent[NG_FACTORY_DEF] || getFactoryOf(parent); // If we hit something that has a factory and the factory isn't the same as the type, // we've found the inherited factory. Note the check that the factory isn't the type's // own factory is redundant in most cases, but if the user has custom decorators on the // class, this lookup will start one level down in the prototype chain, causing us to // find the own factory first and potentially triggering an infinite loop downstream. if (factory && factory !== ownFactory) { return factory; } parent = Object.getPrototypeOf(parent); } // There is no factory defined. Either this was improper usage of inheritance // (no Angular decorator on the superclass) or there is no constructor at all // in the inheritance chain. Since the two cases cannot be distinguished, the // latter has to be assumed. return t => new t(); }); } function getFactoryOf(type) { if (isForwardRef(type)) { return () => { const factory = getFactoryOf(resolveForwardRef(type)); return factory && factory(); }; } return getFactoryDef(type); } /** * Returns a value from the closest embedded or node injector. * * @param tNode The Node where the search for the injector should start * @param lView The `LView` that contains the `tNode` * @param token The token to look for * @param flags Injection flags * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional` * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided */ function lookupTokenUsingEmbeddedInjector(tNode, lView, token, flags, notFoundValue) { let currentTNode = tNode; let currentLView = lView; // When an LView with an embedded view injector is inserted, it'll likely be interlaced with // nodes who may have injectors (e.g. node injector -> embedded view injector -> node injector). // Since the bloom filters for the node injectors have already been constructed and we don't // have a way of extracting the records from an injector, the only way to maintain the correct // hierarchy when resolving the value is to walk it node-by-node while attempting to resolve // the token at each level. while (currentTNode !== null && currentLView !== null && (currentLView[FLAGS] & 1024 /* LViewFlags.HasEmbeddedViewInjector */) && !(currentLView[FLAGS] & 256 /* LViewFlags.IsRoot */)) { ngDevMode && assertTNodeForLView(currentTNode, currentLView); // Note that this lookup on the node injector is using the `Self` flag, because // we don't want the node injector to look at any parent injectors since we // may hit the embedded view injector first. const nodeInjectorValue = lookupTokenUsingNodeInjector(currentTNode, currentLView, token, flags | InjectFlags.Self, NOT_FOUND); if (nodeInjectorValue !== NOT_FOUND) { return nodeInjectorValue; } // Has an explicit type due to a TS bug: https://github.com/microsoft/TypeScript/issues/33191 let parentTNode = currentTNode.parent; // `TNode.parent` includes the parent within the current view only. If it doesn't exist, // it means that we've hit the view boundary and we need to go up to the next view. if (!parentTNode) { // Before we go to the next LView, check if the token exists on the current embedded injector. const embeddedViewInjector = currentLView[EMBEDDED_VIEW_INJECTOR]; if (embeddedViewInjector) { const embeddedViewInjectorValue = embeddedViewInjector.get(token, NOT_FOUND, flags); if (embeddedViewInjectorValue !== NOT_FOUND) { return embeddedViewInjectorValue; } } // Otherwise keep going up the tree. parentTNode = getTNodeFromLView(currentLView); currentLView = currentLView[DECLARATION_VIEW]; } currentTNode = parentTNode; } return notFoundValue; } /** Gets the TNode associated with an LView inside of the declaration view. */ function getTNodeFromLView(lView) { const tView = lView[TVIEW]; const tViewType = tView.type; // The parent pointer differs based on `TView.type`. if (tViewType === 2 /* TViewType.Embedded */) { ngDevMode && assertDefined(tView.declTNode, 'Embedded TNodes should have declaration parents.'); return tView.declTNode; } else if (tViewType === 1 /* TViewType.Component */) { // Components don't have `TView.declTNode` because each instance of component could be // inserted in different location, hence `TView.declTNode` is meaningless. return lView[T_HOST]; } return null; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9jb3JlL3NyYy9yZW5kZXIzL2RpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQUVILE9BQU8sRUFBQyxZQUFZLEVBQUUsaUJBQWlCLEVBQUMsTUFBTSxtQkFBbUIsQ0FBQztBQUNsRSxPQUFPLEVBQUMsa0JBQWtCLEVBQUUsdUJBQXVCLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQztBQUVoRixPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSw4QkFBOEIsQ0FBQztBQUUvRCxPQUFPLEVBQUMsV0FBVyxFQUFnQixNQUFNLDBCQUEwQixDQUFDO0FBR3BFLE9BQU8sRUFBQyxhQUFhLEVBQUUsV0FBVyxFQUFFLGtCQUFrQixFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDOUUsT0FBTyxFQUFDLGFBQWEsRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBRTlDLE9BQU8sRUFBQyxrQkFBa0IsRUFBRSxrQkFBa0IsRUFBRSxtQkFBbUIsRUFBQyxNQUFNLFVBQVUsQ0FBQztBQUNyRixPQUFPLEVBQVksYUFBYSxFQUFDLE1BQU0sc0JBQXNCLENBQUM7QUFDOUQsT0FBTyxFQUFDLDBCQUEwQixFQUFFLDBCQUEwQixFQUFDLE1BQU0sYUFBYSxDQUFDO0FBQ25GLE9BQU8sRUFBQyxhQUFhLEVBQUUsY0FBYyxFQUFDLE1BQU0sVUFBVSxDQUFDO0FBQ3ZELE9BQU8sRUFBQyxxQkFBcUIsRUFBQyxNQUFNLFNBQVMsQ0FBQztBQUU5QyxPQUFPLEVBQUMsU0FBUyxFQUFFLGtCQUFrQixFQUFtRyxNQUFNLHVCQUF1QixDQUFDO0FBRXRLLE9BQU8sRUFBQyxjQUFjLEVBQUUsZUFBZSxFQUFDLE1BQU0sMEJBQTBCLENBQUM7QUFDekUsT0FBTyxFQUFDLDBCQUEwQixFQUFFLGdCQUFnQixFQUFFLHNCQUFzQixFQUFFLEtBQUssRUFBRSxRQUFRLEVBQXFCLE1B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