| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							|  |  |  |  * Copyright Google Inc. All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-29 16:34:44 -07:00
										 |  |  | import {getInjectableDef, getInjectorDef} from '../di/defs'; | 
					
						
							| 
									
										
										
										
											2018-07-27 09:56:35 -07:00
										 |  |  | import {InjectionToken} from '../di/injection_token'; | 
					
						
							| 
									
										
										
										
											2018-10-23 14:28:15 -07:00
										 |  |  | import {Injector} from '../di/injector'; | 
					
						
							|  |  |  | import {InjectFlags, injectRootLimpMode, setInjectImplementation} from '../di/injector_compatibility'; | 
					
						
							| 
									
										
										
										
											2017-12-20 10:47:22 -08:00
										 |  |  | import {Type} from '../type'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | import {assertDefined, assertEqual} from './assert'; | 
					
						
							| 
									
										
										
										
											2018-08-29 16:34:44 -07:00
										 |  |  | import {getComponentDef, getDirectiveDef, getPipeDef} from './definition'; | 
					
						
							| 
									
										
										
										
											2018-09-21 18:38:13 -07:00
										 |  |  | import {NG_ELEMENT_ID} from './fields'; | 
					
						
							| 
									
										
										
										
											2018-09-21 12:12:06 -07:00
										 |  |  | import {DirectiveDef} from './interfaces/definition'; | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | import {NO_PARENT_INJECTOR, NodeInjectorFactory, PARENT_INJECTOR, RelativeInjectorLocation, RelativeInjectorLocationFlags, TNODE, isFactory} from './interfaces/injector'; | 
					
						
							|  |  |  | import {AttributeMarker, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType} from './interfaces/node'; | 
					
						
							| 
									
										
										
										
											2018-10-12 18:49:00 -07:00
										 |  |  | import {DECLARATION_VIEW, HOST_NODE, INJECTOR, LViewData, TData, TVIEW, TView} from './interfaces/view'; | 
					
						
							| 
									
										
										
										
											2018-09-28 21:26:45 -07:00
										 |  |  | import {assertNodeOfPossibleTypes} from './node_assert'; | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | import {getPreviousOrParentTNode, getViewData, setTNodeAndViewData} from './state'; | 
					
						
							| 
									
										
										
										
											2018-10-26 19:12:24 -07:00
										 |  |  | import {getParentInjectorIndex, getParentInjectorView, hasParentInjector, isComponent, stringify} from './util'; | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * 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 = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function setIncludeViewProviders(v: boolean): boolean { | 
					
						
							|  |  |  |   const oldValue = includeViewProviders; | 
					
						
							|  |  |  |   includeViewProviders = v; | 
					
						
							|  |  |  |   return oldValue; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-12-15 14:59:17 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-03-14 13:29:48 -07:00
										 |  |  | const BLOOM_SIZE = 256; | 
					
						
							| 
									
										
										
										
											2018-07-27 12:44:58 -07:00
										 |  |  | const BLOOM_MASK = BLOOM_SIZE - 1; | 
					
						
							| 
									
										
										
										
											2017-12-15 14:59:17 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** Counter used to generate unique IDs for directives. */ | 
					
						
							|  |  |  | let nextNgElementId = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Registers this directive as present in its node's injector by flipping the directive's | 
					
						
							|  |  |  |  * corresponding bit in the injector's bloom filter. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |  * @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 | 
					
						
							| 
									
										
										
										
											2017-12-15 14:59:17 +01:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | export function bloomAdd( | 
					
						
							|  |  |  |     injectorIndex: number, tView: TView, type: Type<any>| InjectionToken<any>): void { | 
					
						
							|  |  |  |   ngDevMode && assertEqual(tView.firstTemplatePass, true, 'expected firstTemplatePass to be true'); | 
					
						
							|  |  |  |   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,
 | 
					
						
							|  |  |  |   // we can easily retrieve the ID and hash it into the bloom bit that should be checked.
 | 
					
						
							|  |  |  |   if (id == null) { | 
					
						
							|  |  |  |     id = (type as any)[NG_ELEMENT_ID] = nextNgElementId++; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-12-15 14:59:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |   // 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 bloomBit = id & BLOOM_MASK; | 
					
						
							| 
									
										
										
										
											2017-12-15 14:59:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |   // 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 << bloomBit; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // 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
 | 
					
						
							|  |  |  |   const b7 = bloomBit & 0x80; | 
					
						
							|  |  |  |   const b6 = bloomBit & 0x40; | 
					
						
							|  |  |  |   const b5 = bloomBit & 0x20; | 
					
						
							|  |  |  |   const tData = tView.data as number[]; | 
					
						
							| 
									
										
										
										
											2017-12-15 14:59:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |   if (b7) { | 
					
						
							|  |  |  |     b6 ? (b5 ? (tData[injectorIndex + 7] |= mask) : (tData[injectorIndex + 6] |= mask)) : | 
					
						
							|  |  |  |          (b5 ? (tData[injectorIndex + 5] |= mask) : (tData[injectorIndex + 4] |= mask)); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     b6 ? (b5 ? (tData[injectorIndex + 3] |= mask) : (tData[injectorIndex + 2] |= mask)) : | 
					
						
							|  |  |  |          (b5 ? (tData[injectorIndex + 1] |= mask) : (tData[injectorIndex] |= mask)); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-01-17 09:45:40 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-15 14:59:17 +01:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Creates (or gets an existing) injector for a given element or container. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-09-17 14:32:45 -07:00
										 |  |  |  * @param tNode for which an injector should be retrieved / created. | 
					
						
							|  |  |  |  * @param hostView View where the node is stored | 
					
						
							| 
									
										
										
										
											2017-12-19 15:01:05 -08:00
										 |  |  |  * @returns Node injector | 
					
						
							| 
									
										
										
										
											2017-12-15 14:59:17 +01:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-07-26 17:22:41 +02:00
										 |  |  | export function getOrCreateNodeInjectorForNode( | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |     tNode: TElementNode | TContainerNode | TElementContainerNode, hostView: LViewData): number { | 
					
						
							|  |  |  |   const existingInjectorIndex = getInjectorIndex(tNode, hostView); | 
					
						
							|  |  |  |   if (existingInjectorIndex !== -1) { | 
					
						
							|  |  |  |     return existingInjectorIndex; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-09-28 21:26:45 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const tView = hostView[TVIEW]; | 
					
						
							|  |  |  |   if (tView.firstTemplatePass) { | 
					
						
							|  |  |  |     tNode.injectorIndex = hostView.length; | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |     insertBloom(tView.data, tNode);  // foundation for node bloom
 | 
					
						
							|  |  |  |     insertBloom(hostView, null);     // foundation for cumulative bloom
 | 
					
						
							|  |  |  |     insertBloom(tView.blueprint, null); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ngDevMode && assertEqual( | 
					
						
							|  |  |  |                      tNode.flags === 0 || tNode.flags === TNodeFlags.isComponent, true, | 
					
						
							|  |  |  |                      'expected tNode.flags to not be initialized'); | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const parentLoc = getParentInjectorLocation(tNode, hostView); | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |   const parentIndex = getParentInjectorIndex(parentLoc); | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |   const parentView: LViewData = getParentInjectorView(parentLoc, hostView); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const injectorIndex = tNode.injectorIndex; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-04 13:28:39 -07:00
										 |  |  |   // 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
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |   if (hasParentInjector(parentLoc)) { | 
					
						
							|  |  |  |     const parentData = parentView[TVIEW].data as any; | 
					
						
							|  |  |  |     // 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; i++) { | 
					
						
							|  |  |  |       hostView[injectorIndex + i] = parentView[parentIndex + i] | parentData[parentIndex + i]; | 
					
						
							| 
									
										
										
										
											2018-10-04 13:28:39 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-12-15 14:59:17 +01:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-09-28 21:26:45 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |   hostView[injectorIndex + PARENT_INJECTOR] = parentLoc; | 
					
						
							|  |  |  |   return injectorIndex; | 
					
						
							| 
									
										
										
										
											2017-12-15 14:59:17 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | function insertBloom(arr: any[], footer: TNode | null): void { | 
					
						
							| 
									
										
										
										
											2018-10-04 13:28:39 -07:00
										 |  |  |   arr.push(0, 0, 0, 0, 0, 0, 0, 0, footer); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  | export function getInjectorIndex(tNode: TNode, hostView: LViewData): number { | 
					
						
							| 
									
										
										
										
											2018-09-28 21:26:45 -07:00
										 |  |  |   if (tNode.injectorIndex === -1 || | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |       // 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
 | 
					
						
							|  |  |  |       hostView[tNode.injectorIndex + PARENT_INJECTOR] == null) { | 
					
						
							|  |  |  |     return -1; | 
					
						
							| 
									
										
										
										
											2018-09-28 21:26:45 -07:00
										 |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |     return tNode.injectorIndex; | 
					
						
							| 
									
										
										
										
											2018-09-28 21:26:45 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Finds the index of the parent injector, with a view offset if applicable. Used to set the | 
					
						
							|  |  |  |  * parent injector initially. | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Returns a combination of number of `ViewData` we have to go up and index in that `Viewdata` | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | export function getParentInjectorLocation(tNode: TNode, view: LViewData): RelativeInjectorLocation { | 
					
						
							| 
									
										
										
										
											2018-09-28 21:26:45 -07:00
										 |  |  |   if (tNode.parent && tNode.parent.injectorIndex !== -1) { | 
					
						
							| 
									
										
										
										
											2018-10-26 19:12:24 -07:00
										 |  |  |     return tNode.parent.injectorIndex as any;  // ViewOffset is 0, AcrossHostBoundary is 0
 | 
					
						
							| 
									
										
										
										
											2018-09-28 21:26:45 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // 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
 | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |   // the rarer case of deeply nested <ng-template> tags or inline views.
 | 
					
						
							| 
									
										
										
										
											2018-09-28 21:26:45 -07:00
										 |  |  |   let hostTNode = view[HOST_NODE]; | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |   let viewOffset = 1; | 
					
						
							| 
									
										
										
										
											2018-09-28 21:26:45 -07:00
										 |  |  |   while (hostTNode && hostTNode.injectorIndex === -1) { | 
					
						
							|  |  |  |     view = view[DECLARATION_VIEW] !; | 
					
						
							|  |  |  |     hostTNode = view[HOST_NODE] !; | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |     viewOffset++; | 
					
						
							| 
									
										
										
										
											2018-09-28 21:26:45 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-26 19:12:24 -07:00
										 |  |  |   const acrossHostBoundary = hostTNode && hostTNode.type === TNodeType.Element ? | 
					
						
							|  |  |  |       RelativeInjectorLocationFlags.AcrossHostBoundary : | 
					
						
							|  |  |  |       0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |   return hostTNode ? | 
					
						
							| 
									
										
										
										
											2018-10-26 19:12:24 -07:00
										 |  |  |       hostTNode.injectorIndex | (viewOffset << RelativeInjectorLocationFlags.ViewOffsetShift) | | 
					
						
							|  |  |  |           acrossHostBoundary : | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |       -1 as any; | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |  * Makes a type or an injection token public to the DI system by adding it to an | 
					
						
							|  |  |  |  * injector's bloom filter. | 
					
						
							| 
									
										
										
										
											2017-12-15 14:59:17 +01:00
										 |  |  |  * | 
					
						
							|  |  |  |  * @param di The node injector in which a directive will be added | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |  * @param token The type or the injection token to be made public | 
					
						
							| 
									
										
										
										
											2017-12-15 14:59:17 +01:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  | export function diPublicInInjector( | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |     injectorIndex: number, view: LViewData, token: InjectionToken<any>| Type<any>): void { | 
					
						
							|  |  |  |   bloomAdd(injectorIndex, view[TVIEW], token); | 
					
						
							| 
									
										
										
										
											2018-01-17 09:45:40 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-28 22:18:34 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * 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.ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |  *   factory: () => new MyComponent(injectAttribute('title')) | 
					
						
							|  |  |  |  *   ... | 
					
						
							|  |  |  |  * }) | 
					
						
							|  |  |  |  * ```
 | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-10-19 12:12:20 +01:00
										 |  |  |  * @publicApi | 
					
						
							| 
									
										
										
										
											2018-02-28 22:18:34 -08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | export function injectAttributeImpl(tNode: TNode, attrNameToInject: string): string|undefined { | 
					
						
							| 
									
										
										
										
											2018-08-28 14:13:32 +02:00
										 |  |  |   ngDevMode && assertNodeOfPossibleTypes( | 
					
						
							| 
									
										
										
										
											2018-09-05 16:15:37 -07:00
										 |  |  |                    tNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer); | 
					
						
							| 
									
										
										
										
											2018-08-28 14:13:32 +02:00
										 |  |  |   ngDevMode && assertDefined(tNode, 'expecting tNode'); | 
					
						
							|  |  |  |   const attrs = tNode.attrs; | 
					
						
							| 
									
										
										
										
											2018-02-28 22:18:34 -08:00
										 |  |  |   if (attrs) { | 
					
						
							|  |  |  |     for (let i = 0; i < attrs.length; i = i + 2) { | 
					
						
							| 
									
										
										
										
											2018-06-06 13:38:20 -07:00
										 |  |  |       const attrName = attrs[i]; | 
					
						
							| 
									
										
										
										
											2018-06-08 15:25:39 -07:00
										 |  |  |       if (attrName === AttributeMarker.SelectOnly) break; | 
					
						
							| 
									
										
										
										
											2018-05-04 15:58:42 +02:00
										 |  |  |       if (attrName == attrNameToInject) { | 
					
						
							|  |  |  |         return attrs[i + 1] as string; | 
					
						
							| 
									
										
										
										
											2018-02-28 22:18:34 -08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return undefined; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 17:43:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-13 14:28:36 -08:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |  * Returns the value associated to the given token from the NodeInjectors => ModuleInjector. | 
					
						
							| 
									
										
										
										
											2017-12-13 14:28:36 -08:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-07-27 09:47:34 -07:00
										 |  |  |  * Look for the injector providing the token by walking up the node injector tree and then | 
					
						
							|  |  |  |  * the module injector tree. | 
					
						
							| 
									
										
										
										
											2017-12-13 14:28:36 -08:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-07-27 09:47:34 -07:00
										 |  |  |  * @param nodeInjector Node injector where the search should start | 
					
						
							|  |  |  |  * @param token The token to look for | 
					
						
							|  |  |  |  * @param flags Injection flags | 
					
						
							|  |  |  |  * @returns the value from the injector or `null` when not found | 
					
						
							| 
									
										
										
										
											2017-12-13 14:28:36 -08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-04-23 18:24:40 -07:00
										 |  |  | export function getOrCreateInjectable<T>( | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |     tNode: TElementNode | TContainerNode | TElementContainerNode, lViewData: LViewData, | 
					
						
							|  |  |  |     token: Type<T>| InjectionToken<T>, flags: InjectFlags = InjectFlags.Default, | 
					
						
							|  |  |  |     notFoundValue?: any): T|null { | 
					
						
							| 
									
										
										
										
											2018-09-21 18:38:13 -07:00
										 |  |  |   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.
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |   if (typeof bloomHash === 'function') { | 
					
						
							|  |  |  |     const savePreviousOrParentTNode = getPreviousOrParentTNode(); | 
					
						
							|  |  |  |     const saveViewData = getViewData(); | 
					
						
							|  |  |  |     setTNodeAndViewData(tNode, lViewData); | 
					
						
							|  |  |  |     try { | 
					
						
							| 
									
										
										
										
											2018-10-25 11:18:49 -07:00
										 |  |  |       const value = bloomHash(); | 
					
						
							|  |  |  |       if (value == null && !(flags & InjectFlags.Optional)) { | 
					
						
							|  |  |  |         throw new Error(`No provider for ${stringify(token)}`); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         return value; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |     } finally { | 
					
						
							|  |  |  |       setTNodeAndViewData(savePreviousOrParentTNode, saveViewData); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } else if (typeof bloomHash == 'number') { | 
					
						
							|  |  |  |     // If the token has a bloom hash, then it is a token which could be in NodeInjector.
 | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |     // 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: TView|null = null; | 
					
						
							|  |  |  |     let injectorIndex = getInjectorIndex(tNode, lViewData); | 
					
						
							|  |  |  |     let parentLocation: RelativeInjectorLocation = NO_PARENT_INJECTOR; | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |     // If we should skip this injector, start by searching the parent injector.
 | 
					
						
							|  |  |  |     if (flags & InjectFlags.SkipSelf) { | 
					
						
							|  |  |  |       parentLocation = injectorIndex === -1 ? getParentInjectorLocation(tNode, lViewData) : | 
					
						
							|  |  |  |                                               lViewData[injectorIndex + PARENT_INJECTOR]; | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |       if (!shouldSearchParent(flags, parentLocation)) { | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  |         injectorIndex = -1; | 
					
						
							|  |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |         previousTView = lViewData[TVIEW]; | 
					
						
							|  |  |  |         injectorIndex = getParentInjectorIndex(parentLocation); | 
					
						
							|  |  |  |         lViewData = getParentInjectorView(parentLocation, lViewData); | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |     // Traverse up the injector tree until we find a potential match or until we know there
 | 
					
						
							|  |  |  |     // *isn't* a match.
 | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |     while (injectorIndex !== -1) { | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |       parentLocation = lViewData[injectorIndex + PARENT_INJECTOR]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Check the current injector. If it matches, see if it contains token.
 | 
					
						
							|  |  |  |       const tView = lViewData[TVIEW]; | 
					
						
							|  |  |  |       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: T|null = | 
					
						
							|  |  |  |             searchTokensOnInjector<T>(injectorIndex, lViewData, token, previousTView); | 
					
						
							|  |  |  |         if (instance !== NOT_FOUND) { | 
					
						
							|  |  |  |           return instance; | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |       if (shouldSearchParent(flags, parentLocation) && | 
					
						
							|  |  |  |           bloomHasToken(bloomHash, injectorIndex, lViewData)) { | 
					
						
							|  |  |  |         // 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); | 
					
						
							|  |  |  |         lViewData = getParentInjectorView(parentLocation, lViewData); | 
					
						
							|  |  |  |       } 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; | 
					
						
							| 
									
										
										
										
											2018-04-04 21:21:12 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-12-13 16:32:21 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-25 11:35:51 -07:00
										 |  |  |   if (flags & InjectFlags.Optional && notFoundValue === undefined) { | 
					
						
							|  |  |  |     // This must be set or the NullInjector will throw for optional deps
 | 
					
						
							|  |  |  |     notFoundValue = null; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |   if ((flags & (InjectFlags.Self | InjectFlags.Host)) === 0) { | 
					
						
							|  |  |  |     const moduleInjector = lViewData[INJECTOR]; | 
					
						
							|  |  |  |     if (moduleInjector) { | 
					
						
							|  |  |  |       return moduleInjector.get(token, notFoundValue, flags & InjectFlags.Optional); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return injectRootLimpMode(token, notFoundValue, flags & InjectFlags.Optional); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (flags & InjectFlags.Optional) { | 
					
						
							|  |  |  |     return notFoundValue; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     throw new Error(`NodeInjector: NOT_FOUND [${stringify(token)}]`); | 
					
						
							| 
									
										
										
										
											2018-07-27 09:56:35 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | const NOT_FOUND = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function searchTokensOnInjector<T>( | 
					
						
							|  |  |  |     injectorIndex: number, injectorView: LViewData, token: Type<T>| InjectionToken<T>, | 
					
						
							|  |  |  |     previousTView: TView | null) { | 
					
						
							|  |  |  |   const currentTView = injectorView[TVIEW]; | 
					
						
							|  |  |  |   const tNode = currentTView.data[injectorIndex + TNODE] as TNode; | 
					
						
							|  |  |  |   const nodeFlags = tNode.flags; | 
					
						
							|  |  |  |   const nodeProviderIndexes = tNode.providerIndexes; | 
					
						
							|  |  |  |   const tInjectables = currentTView.data; | 
					
						
							|  |  |  |   // First, we step through providers
 | 
					
						
							|  |  |  |   let canAccessViewProviders = false; | 
					
						
							|  |  |  |   // We need to determine if view providers can be accessed by the starting element.
 | 
					
						
							|  |  |  |   // It happens in 2 cases:
 | 
					
						
							|  |  |  |   // 1) On the initial element injector , if we are instantiating a token which can see the
 | 
					
						
							|  |  |  |   // viewProviders of the component of that element. Such token are:
 | 
					
						
							|  |  |  |   // - the component itself (but not other directives)
 | 
					
						
							|  |  |  |   // - viewProviders tokens of the component (but not providers tokens)
 | 
					
						
							|  |  |  |   // 2) Upper in the element injector tree, if the starting element is actually in the view of
 | 
					
						
							|  |  |  |   // the current element. To determine this, we track the transition of view during the climb,
 | 
					
						
							|  |  |  |   // and check the host node of the current view to identify component views.
 | 
					
						
							|  |  |  |   if (previousTView == null && isComponent(tNode) && includeViewProviders || | 
					
						
							|  |  |  |       previousTView != null && previousTView != currentTView && | 
					
						
							|  |  |  |           (currentTView.node == null || currentTView.node !.type === TNodeType.Element)) { | 
					
						
							|  |  |  |     canAccessViewProviders = true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   const startInjectables = nodeProviderIndexes & TNodeProviderIndexes.ProvidersStartIndexMask; | 
					
						
							|  |  |  |   const startDirectives = nodeFlags >> TNodeFlags.DirectiveStartingIndexShift; | 
					
						
							|  |  |  |   const cptViewProvidersCount = | 
					
						
							|  |  |  |       nodeProviderIndexes >> TNodeProviderIndexes.CptViewProvidersCountShift; | 
					
						
							|  |  |  |   const startingIndex = | 
					
						
							|  |  |  |       canAccessViewProviders ? startInjectables : startInjectables + cptViewProvidersCount; | 
					
						
							|  |  |  |   const directiveCount = nodeFlags & TNodeFlags.DirectiveCountMask; | 
					
						
							|  |  |  |   for (let i = startingIndex; i < startDirectives + directiveCount; i++) { | 
					
						
							|  |  |  |     const providerTokenOrDef = tInjectables[i] as InjectionToken<any>| Type<any>| DirectiveDef<any>; | 
					
						
							|  |  |  |     if (i < startDirectives && token === providerTokenOrDef || | 
					
						
							|  |  |  |         i >= startDirectives && (providerTokenOrDef as DirectiveDef<any>).type === token) { | 
					
						
							|  |  |  |       return getNodeInjectable(tInjectables, injectorView, i, tNode as TElementNode); | 
					
						
							| 
									
										
										
										
											2018-04-04 21:21:12 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |   return NOT_FOUND; | 
					
						
							| 
									
										
										
										
											2018-04-04 21:21:12 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | /** | 
					
						
							|  |  |  | * Retrieve or instantiate the injectable from the `lData` 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( | 
					
						
							|  |  |  |     tData: TData, lData: LViewData, index: number, tNode: TElementNode): any { | 
					
						
							|  |  |  |   let value = lData[index]; | 
					
						
							|  |  |  |   if (isFactory(value)) { | 
					
						
							|  |  |  |     const factory: NodeInjectorFactory = value; | 
					
						
							|  |  |  |     if (factory.resolving) { | 
					
						
							|  |  |  |       throw new Error(`Circular dep for ${stringify(tData[index])}`); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const previousIncludeViewProviders = setIncludeViewProviders(factory.canSeeViewProviders); | 
					
						
							|  |  |  |     factory.resolving = true; | 
					
						
							|  |  |  |     let previousInjectImplementation; | 
					
						
							|  |  |  |     if (factory.injectImpl) { | 
					
						
							|  |  |  |       previousInjectImplementation = setInjectImplementation(factory.injectImpl); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const savePreviousOrParentTNode = getPreviousOrParentTNode(); | 
					
						
							|  |  |  |     const saveViewData = getViewData(); | 
					
						
							|  |  |  |     setTNodeAndViewData(tNode, lData); | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       value = lData[index] = factory.factory(null, tData, lData, tNode); | 
					
						
							|  |  |  |     } finally { | 
					
						
							|  |  |  |       if (factory.injectImpl) setInjectImplementation(previousInjectImplementation); | 
					
						
							|  |  |  |       setIncludeViewProviders(previousIncludeViewProviders); | 
					
						
							|  |  |  |       factory.resolving = false; | 
					
						
							|  |  |  |       setTNodeAndViewData(savePreviousOrParentTNode, saveViewData); | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |   return value; | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-13 14:28:36 -08:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2018-07-27 09:47:34 -07:00
										 |  |  |  * 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. | 
					
						
							| 
									
										
										
										
											2017-12-13 14:28:36 -08:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-07-27 09:47:34 -07:00
										 |  |  |  * 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. | 
					
						
							| 
									
										
										
										
											2017-12-13 14:28:36 -08:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-07-27 09:47:34 -07:00
										 |  |  |  * @param token the injection token | 
					
						
							|  |  |  |  * @returns the matching bit to check in the bloom filter or `null` if the token is not known. | 
					
						
							| 
									
										
										
										
											2017-12-13 14:28:36 -08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  | export function bloomHashBitOrFactory(token: Type<any>| InjectionToken<any>): number|Function| | 
					
						
							|  |  |  |     undefined { | 
					
						
							|  |  |  |   const tokenId: number|undefined = (token as any)[NG_ELEMENT_ID]; | 
					
						
							| 
									
										
										
										
											2018-09-21 18:38:13 -07:00
										 |  |  |   return typeof tokenId === 'number' ? tokenId & BLOOM_MASK : tokenId; | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | export function bloomHasToken( | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |     bloomHash: number, injectorIndex: number, injectorView: LViewData | TData) { | 
					
						
							| 
									
										
										
										
											2017-12-13 16:32:21 -08:00
										 |  |  |   // Create a mask that targets the specific bit associated with the directive we're looking for.
 | 
					
						
							| 
									
										
										
										
											2017-12-14 15:50:01 -08:00
										 |  |  |   // 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.
 | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |   const mask = 1 << bloomHash; | 
					
						
							|  |  |  |   const b7 = bloomHash & 0x80; | 
					
						
							|  |  |  |   const b6 = bloomHash & 0x40; | 
					
						
							|  |  |  |   const b5 = bloomHash & 0x20; | 
					
						
							| 
									
										
										
										
											2018-07-27 12:44:58 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |   // Our bloom filter size is 256 bits, which is eight 32-bit bloom filter buckets:
 | 
					
						
							|  |  |  |   // bf0 = [0 - 31], bf1 = [32 - 63], bf2 = [64 - 95], bf3 = [96 - 127], etc.
 | 
					
						
							|  |  |  |   // Get the bloom filter value from the appropriate bucket based on the directive's bloomBit.
 | 
					
						
							|  |  |  |   let value: number; | 
					
						
							| 
									
										
										
										
											2017-12-13 16:32:21 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |   if (b7) { | 
					
						
							|  |  |  |     value = b6 ? (b5 ? injectorView[injectorIndex + 7] : injectorView[injectorIndex + 6]) : | 
					
						
							|  |  |  |                  (b5 ? injectorView[injectorIndex + 5] : injectorView[injectorIndex + 4]); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     value = b6 ? (b5 ? injectorView[injectorIndex + 3] : injectorView[injectorIndex + 2]) : | 
					
						
							|  |  |  |                  (b5 ? injectorView[injectorIndex + 1] : injectorView[injectorIndex]); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-07-27 12:44:58 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |   // 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); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  | /** Returns true if flags prevent parent injector from being searched for tokens */ | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | function shouldSearchParent(flags: InjectFlags, parentLocation: RelativeInjectorLocation): boolean| | 
					
						
							|  |  |  |     number { | 
					
						
							|  |  |  |   return !( | 
					
						
							|  |  |  |       flags & InjectFlags.Self || | 
					
						
							| 
									
										
										
										
											2018-10-26 19:12:24 -07:00
										 |  |  |       (flags & InjectFlags.Host && | 
					
						
							|  |  |  |        ((parentLocation as any as number) & RelativeInjectorLocationFlags.AcrossHostBoundary))); | 
					
						
							| 
									
										
										
										
											2018-04-23 18:24:40 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-23 14:28:15 -07:00
										 |  |  | export function injectInjector() { | 
					
						
							|  |  |  |   const tNode = getPreviousOrParentTNode() as TElementNode | TContainerNode | TElementContainerNode; | 
					
						
							|  |  |  |   return new NodeInjector(tNode, getViewData()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class NodeInjector implements Injector { | 
					
						
							|  |  |  |   private _injectorIndex: number; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   constructor( | 
					
						
							|  |  |  |       private _tNode: TElementNode|TContainerNode|TElementContainerNode, | 
					
						
							|  |  |  |       private _hostView: LViewData) { | 
					
						
							|  |  |  |     this._injectorIndex = getOrCreateNodeInjectorForNode(_tNode, _hostView); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   get(token: any): any { | 
					
						
							|  |  |  |     setTNodeAndViewData(this._tNode, this._hostView); | 
					
						
							|  |  |  |     return getOrCreateInjectable(this._tNode, this._hostView, token); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | export function getFactoryOf<T>(type: Type<any>): ((type: Type<T>| null) => T)|null { | 
					
						
							| 
									
										
										
										
											2018-07-16 16:36:31 -07:00
										 |  |  |   const typeAny = type as any; | 
					
						
							| 
									
										
										
										
											2018-08-29 16:34:44 -07:00
										 |  |  |   const def = getComponentDef<T>(typeAny) || getDirectiveDef<T>(typeAny) || | 
					
						
							|  |  |  |       getPipeDef<T>(typeAny) || getInjectableDef<T>(typeAny) || getInjectorDef<T>(typeAny); | 
					
						
							|  |  |  |   if (!def || def.factory === undefined) { | 
					
						
							| 
									
										
										
										
											2018-07-16 16:36:31 -07:00
										 |  |  |     return null; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return def.factory; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function getInheritedFactory<T>(type: Type<any>): (type: Type<T>) => T { | 
					
						
							|  |  |  |   const proto = Object.getPrototypeOf(type.prototype).constructor as Type<any>; | 
					
						
							|  |  |  |   const factory = getFactoryOf<T>(proto); | 
					
						
							| 
									
										
										
										
											2018-08-10 11:15:59 +01:00
										 |  |  |   if (factory !== null) { | 
					
						
							|  |  |  |     return factory; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     // 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(); | 
					
						
							| 
									
										
										
										
											2018-07-16 16:36:31 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | } |