| 
									
										
										
										
											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
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-10 23:45:02 -08:00
										 |  |  | import {InjectFlags, InjectionToken} from '../di'; | 
					
						
							| 
									
										
										
										
											2018-10-23 14:28:15 -07:00
										 |  |  | import {Injector} from '../di/injector'; | 
					
						
							| 
									
										
										
										
											2019-01-10 23:45:02 -08:00
										 |  |  | import {injectRootLimpMode, setInjectImplementation} from '../di/injector_compatibility'; | 
					
						
							| 
									
										
										
										
											2019-01-09 13:49:16 -08:00
										 |  |  | import {getInjectableDef, getInjectorDef} from '../di/interface/defs'; | 
					
						
							|  |  |  | import {Type} from '../interface/type'; | 
					
						
							|  |  |  | import {assertDefined, assertEqual} from '../util/assert'; | 
					
						
							| 
									
										
										
										
											2019-01-10 23:45:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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'; | 
					
						
							| 
									
										
										
										
											2019-01-30 23:42:26 +00:00
										 |  |  | import {DECLARATION_VIEW, INJECTOR, LView, TData, TVIEW, TView, T_HOST} from './interfaces/view'; | 
					
						
							| 
									
										
										
										
											2018-09-28 21:26:45 -07:00
										 |  |  | import {assertNodeOfPossibleTypes} from './node_assert'; | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  | import {getLView, getPreviousOrParentTNode, setTNodeAndViewData} from './state'; | 
					
						
							| 
									
										
										
										
											2019-02-20 14:21:20 -08:00
										 |  |  | import {getParentInjectorIndex, getParentInjectorView, hasParentInjector} from './util/injector_utils'; | 
					
						
							|  |  |  | import {renderStringify} from './util/misc_utils'; | 
					
						
							|  |  |  | import {findComponentView} from './util/view_traversal_utils'; | 
					
						
							|  |  |  | import {isComponent, isComponentDef} from './util/view_utils'; | 
					
						
							| 
									
										
										
										
											2018-12-13 11:14:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-09 13:49:16 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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'); | 
					
						
							|  |  |  |  *   } | 
					
						
							|  |  |  |  * } | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * ```
 | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2019-01-04 15:38:40 +01:00
										 |  |  | let includeViewProviders = true; | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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( | 
					
						
							| 
									
										
										
										
											2018-11-28 12:51:00 -08:00
										 |  |  |     injectorIndex: number, tView: TView, type: Type<any>| InjectionToken<any>| string): void { | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |   ngDevMode && assertEqual(tView.firstTemplatePass, true, 'expected firstTemplatePass to be true'); | 
					
						
							| 
									
										
										
										
											2018-11-28 12:51:00 -08:00
										 |  |  |   let id: number|undefined = | 
					
						
							|  |  |  |       typeof type !== 'string' ? (type as any)[NG_ELEMENT_ID] : type.charCodeAt(0) || 0; | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // 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-11-21 21:14:06 -08:00
										 |  |  |     tNode: TElementNode | TContainerNode | TElementContainerNode, hostView: LView): number { | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |   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-11-21 21:14:06 -08:00
										 |  |  |   const parentLView = getParentInjectorView(parentLoc, hostView); | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   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)) { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |     const parentData = parentLView[TVIEW].data as any; | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |     // 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++) { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |       hostView[injectorIndex + i] = parentLView[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-11-21 21:14:06 -08:00
										 |  |  | export function getInjectorIndex(tNode: TNode, hostView: LView): 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-11-21 21:14:06 -08:00
										 |  |  | export function getParentInjectorLocation(tNode: TNode, view: LView): RelativeInjectorLocation { | 
					
						
							| 
									
										
										
										
											2018-09-28 21:26:45 -07:00
										 |  |  |   if (tNode.parent && tNode.parent.injectorIndex !== -1) { | 
					
						
							| 
									
										
										
										
											2018-12-13 11:14:33 +01:00
										 |  |  |     return tNode.parent.injectorIndex as any;  // ViewOffset 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.
 | 
					
						
							| 
									
										
										
										
											2019-01-30 23:42:26 +00:00
										 |  |  |   let hostTNode = view[T_HOST]; | 
					
						
							| 
									
										
										
										
											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] !; | 
					
						
							| 
									
										
										
										
											2019-01-30 23:42:26 +00:00
										 |  |  |     hostTNode = view ? view[T_HOST] : null; | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |   return hostTNode ? | 
					
						
							| 
									
										
										
										
											2018-12-13 11:14:33 +01:00
										 |  |  |       hostTNode.injectorIndex | (viewOffset << RelativeInjectorLocationFlags.ViewOffsetShift) : | 
					
						
							| 
									
										
										
										
											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-11-21 21:14:06 -08:00
										 |  |  |     injectorIndex: number, view: LView, token: InjectionToken<any>| Type<any>): void { | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |   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-11-22 16:03:26 +01:00
										 |  |  | export function injectAttributeImpl(tNode: TNode, attrNameToInject: string): string|null { | 
					
						
							| 
									
										
										
										
											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]; | 
					
						
							| 
									
										
										
										
											2019-03-07 08:31:31 +00:00
										 |  |  |       if (attrName === AttributeMarker.Bindings) break; | 
					
						
							|  |  |  |       // TODO: What happens here if an attribute has a namespace?
 | 
					
						
							|  |  |  |       // TODO: What happens here if the attribute name happens to match a CSS class or style?
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-11-22 16:03:26 +01:00
										 |  |  |   return null; | 
					
						
							| 
									
										
										
										
											2018-02-28 22:18:34 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2019-01-10 23:45:02 -08:00
										 |  |  |  * This function patches `token` with `__NG_ELEMENT_ID__` which contains the id for the bloom | 
					
						
							|  |  |  |  * filter. Negative values are reserved for special objects. | 
					
						
							|  |  |  |  *   - `-1` is reserved for injecting `Injector` (implemented by `NodeInjector`) | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-12-07 10:56:51 +01:00
										 |  |  |  * @param tNode The Node where the search for the injector should start | 
					
						
							|  |  |  |  * @param lView The `LView` that contains the `tNode` | 
					
						
							| 
									
										
										
										
											2018-07-27 09:47:34 -07:00
										 |  |  |  * @param token The token to look for | 
					
						
							|  |  |  |  * @param flags Injection flags | 
					
						
							| 
									
										
										
										
											2018-12-07 10:56:51 +01:00
										 |  |  |  * @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 | 
					
						
							| 
									
										
										
										
											2017-12-13 14:28:36 -08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-04-23 18:24:40 -07:00
										 |  |  | export function getOrCreateInjectable<T>( | 
					
						
							| 
									
										
										
										
											2019-01-03 14:43:06 +01:00
										 |  |  |     tNode: TElementNode | TContainerNode | TElementContainerNode | null, lView: LView, | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |     token: Type<T>| InjectionToken<T>, flags: InjectFlags = InjectFlags.Default, | 
					
						
							|  |  |  |     notFoundValue?: any): T|null { | 
					
						
							| 
									
										
										
										
											2019-01-03 14:43:06 +01:00
										 |  |  |   if (tNode) { | 
					
						
							|  |  |  |     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') { | 
					
						
							|  |  |  |       const savePreviousOrParentTNode = getPreviousOrParentTNode(); | 
					
						
							|  |  |  |       const saveLView = getLView(); | 
					
						
							|  |  |  |       setTNodeAndViewData(tNode, lView); | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         const value = bloomHash(); | 
					
						
							|  |  |  |         if (value == null && !(flags & InjectFlags.Optional)) { | 
					
						
							| 
									
										
										
										
											2019-01-12 00:59:48 -08:00
										 |  |  |           throw new Error(`No provider for ${renderStringify(token)}!`); | 
					
						
							| 
									
										
										
										
											2019-01-03 14:43:06 +01:00
										 |  |  |         } else { | 
					
						
							|  |  |  |           return value; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } finally { | 
					
						
							|  |  |  |         setTNodeAndViewData(savePreviousOrParentTNode, saveLView); | 
					
						
							| 
									
										
										
										
											2018-10-25 11:18:49 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-01-03 14:43:06 +01:00
										 |  |  |     } else if (typeof bloomHash == 'number') { | 
					
						
							| 
									
										
										
										
											2019-01-10 23:45:02 -08:00
										 |  |  |       if (bloomHash === -1) { | 
					
						
							|  |  |  |         // `-1` is a special value used to identify `Injector` types.
 | 
					
						
							|  |  |  |         return new NodeInjector(tNode, lView) as any; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-01-03 14:43:06 +01:00
										 |  |  |       // If the token has a bloom hash, then it is a token which could be in NodeInjector.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // 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, lView); | 
					
						
							|  |  |  |       let parentLocation: RelativeInjectorLocation = NO_PARENT_INJECTOR; | 
					
						
							|  |  |  |       let hostTElementNode: TNode|null = | 
					
						
							| 
									
										
										
										
											2019-01-30 23:42:26 +00:00
										 |  |  |           flags & InjectFlags.Host ? findComponentView(lView)[T_HOST] : null; | 
					
						
							| 
									
										
										
										
											2019-01-03 14:43:06 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       // 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 + PARENT_INJECTOR]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!shouldSearchParent(flags, false)) { | 
					
						
							|  |  |  |           injectorIndex = -1; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           previousTView = lView[TVIEW]; | 
					
						
							|  |  |  |           injectorIndex = getParentInjectorIndex(parentLocation); | 
					
						
							|  |  |  |           lView = getParentInjectorView(parentLocation, lView); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-03 14:43:06 +01:00
										 |  |  |       // Traverse up the injector tree until we find a potential match or until we know there
 | 
					
						
							|  |  |  |       // *isn't* a match.
 | 
					
						
							|  |  |  |       while (injectorIndex !== -1) { | 
					
						
							|  |  |  |         parentLocation = lView[injectorIndex + PARENT_INJECTOR]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Check the current injector. If it matches, see if it contains token.
 | 
					
						
							|  |  |  |         const tView = lView[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, lView, token, previousTView, flags, hostTElementNode); | 
					
						
							|  |  |  |           if (instance !== NOT_FOUND) { | 
					
						
							|  |  |  |             return instance; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (shouldSearchParent( | 
					
						
							|  |  |  |                 flags, lView[TVIEW].data[injectorIndex + 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; | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |     const moduleInjector = lView[INJECTOR]; | 
					
						
							| 
									
										
										
										
											2019-02-12 09:46:39 -08:00
										 |  |  |     // 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); | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (flags & InjectFlags.Optional) { | 
					
						
							|  |  |  |     return notFoundValue; | 
					
						
							|  |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2019-01-12 00:59:48 -08:00
										 |  |  |     throw new Error(`NodeInjector: NOT_FOUND [${renderStringify(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>( | 
					
						
							| 
									
										
										
										
											2018-11-28 15:54:38 -08:00
										 |  |  |     injectorIndex: number, lView: LView, token: Type<T>| InjectionToken<T>, | 
					
						
							| 
									
										
										
										
											2018-12-13 11:14:33 +01:00
										 |  |  |     previousTView: TView | null, flags: InjectFlags, hostTElementNode: TNode | null) { | 
					
						
							| 
									
										
										
										
											2018-11-28 15:54:38 -08:00
										 |  |  |   const currentTView = lView[TVIEW]; | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |   const tNode = currentTView.data[injectorIndex + TNODE] as TNode; | 
					
						
							| 
									
										
										
										
											2018-11-28 15:54:38 -08:00
										 |  |  |   // First, we need to determine if view providers can be accessed by the starting element.
 | 
					
						
							|  |  |  |   // There are two possibities
 | 
					
						
							|  |  |  |   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)
 | 
					
						
							|  |  |  |       (isComponent(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 === TNodeType.Element)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-13 11:14:33 +01:00
										 |  |  |   // 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, lView, token, canAccessViewProviders, isHostSpecialCase); | 
					
						
							| 
									
										
										
										
											2018-11-18 21:04:05 +01:00
										 |  |  |   if (injectableIdx !== null) { | 
					
						
							| 
									
										
										
										
											2018-11-28 15:54:38 -08:00
										 |  |  |     return getNodeInjectable(currentTView.data, lView, injectableIdx, tNode as TElementNode); | 
					
						
							| 
									
										
										
										
											2018-11-18 21:04:05 +01:00
										 |  |  |   } else { | 
					
						
							|  |  |  |     return NOT_FOUND; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Searches for the given token among the node's directives and providers. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @param tNode TNode on which directives are present. | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |  * @param lView The view we are currently processing | 
					
						
							| 
									
										
										
										
											2018-11-18 21:04:05 +01:00
										 |  |  |  * @param token Provider token or type of a directive to look for. | 
					
						
							|  |  |  |  * @param canAccessViewProviders Whether view providers should be considered. | 
					
						
							| 
									
										
										
										
											2018-12-13 11:14:33 +01:00
										 |  |  |  * @param isHostSpecialCase Whether the host special case applies. | 
					
						
							| 
									
										
										
										
											2018-11-18 21:04:05 +01:00
										 |  |  |  * @returns Index of a found directive or provider, or null when none found. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export function locateDirectiveOrProvider<T>( | 
					
						
							| 
									
										
										
										
											2018-12-13 11:14:33 +01:00
										 |  |  |     tNode: TNode, lView: LView, token: Type<T>| InjectionToken<T>, canAccessViewProviders: boolean, | 
					
						
							|  |  |  |     isHostSpecialCase: boolean | number): number|null { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |   const tView = lView[TVIEW]; | 
					
						
							| 
									
										
										
										
											2018-11-18 21:04:05 +01:00
										 |  |  |   const nodeProviderIndexes = tNode.providerIndexes; | 
					
						
							|  |  |  |   const tInjectables = tView.data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-28 15:54:38 -08:00
										 |  |  |   const injectablesStart = nodeProviderIndexes & TNodeProviderIndexes.ProvidersStartIndexMask; | 
					
						
							|  |  |  |   const directivesStart = tNode.directiveStart; | 
					
						
							|  |  |  |   const directiveEnd = tNode.directiveEnd; | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |   const cptViewProvidersCount = | 
					
						
							|  |  |  |       nodeProviderIndexes >> TNodeProviderIndexes.CptViewProvidersCountShift; | 
					
						
							|  |  |  |   const startingIndex = | 
					
						
							| 
									
										
										
										
											2018-11-28 15:54:38 -08:00
										 |  |  |       canAccessViewProviders ? injectablesStart : injectablesStart + cptViewProvidersCount; | 
					
						
							| 
									
										
										
										
											2018-12-13 11:14:33 +01:00
										 |  |  |   // 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++) { | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |     const providerTokenOrDef = tInjectables[i] as InjectionToken<any>| Type<any>| DirectiveDef<any>; | 
					
						
							| 
									
										
										
										
											2018-11-28 15:54:38 -08:00
										 |  |  |     if (i < directivesStart && token === providerTokenOrDef || | 
					
						
							|  |  |  |         i >= directivesStart && (providerTokenOrDef as DirectiveDef<any>).type === token) { | 
					
						
							| 
									
										
										
										
											2018-11-18 21:04:05 +01:00
										 |  |  |       return i; | 
					
						
							| 
									
										
										
										
											2018-04-04 21:21:12 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-12-13 11:14:33 +01:00
										 |  |  |   if (isHostSpecialCase) { | 
					
						
							|  |  |  |     const dirDef = tInjectables[directivesStart] as DirectiveDef<any>; | 
					
						
							|  |  |  |     if (dirDef && isComponentDef(dirDef) && dirDef.type === token) { | 
					
						
							|  |  |  |       return directivesStart; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-11-18 21:04:05 +01:00
										 |  |  |   return null; | 
					
						
							| 
									
										
										
										
											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( | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |     tData: TData, lData: LView, index: number, tNode: TElementNode): any { | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |   let value = lData[index]; | 
					
						
							|  |  |  |   if (isFactory(value)) { | 
					
						
							|  |  |  |     const factory: NodeInjectorFactory = value; | 
					
						
							|  |  |  |     if (factory.resolving) { | 
					
						
							| 
									
										
										
										
											2019-01-12 00:59:48 -08:00
										 |  |  |       throw new Error(`Circular dep for ${renderStringify(tData[index])}`); | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     const previousIncludeViewProviders = setIncludeViewProviders(factory.canSeeViewProviders); | 
					
						
							|  |  |  |     factory.resolving = true; | 
					
						
							|  |  |  |     let previousInjectImplementation; | 
					
						
							|  |  |  |     if (factory.injectImpl) { | 
					
						
							|  |  |  |       previousInjectImplementation = setInjectImplementation(factory.injectImpl); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const savePreviousOrParentTNode = getPreviousOrParentTNode(); | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |     const saveLView = getLView(); | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  |     setTNodeAndViewData(tNode, lData); | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       value = lData[index] = factory.factory(null, tData, lData, tNode); | 
					
						
							|  |  |  |     } finally { | 
					
						
							|  |  |  |       if (factory.injectImpl) setInjectImplementation(previousInjectImplementation); | 
					
						
							|  |  |  |       setIncludeViewProviders(previousIncludeViewProviders); | 
					
						
							|  |  |  |       factory.resolving = false; | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |       setTNodeAndViewData(savePreviousOrParentTNode, saveLView); | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							| 
									
										
										
										
											2019-01-10 23:45:02 -08:00
										 |  |  |  *   When the returned value is negative then it represents special values such as `Injector`. | 
					
						
							| 
									
										
										
										
											2017-12-13 14:28:36 -08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-11-28 12:51:00 -08:00
										 |  |  | export function bloomHashBitOrFactory(token: Type<any>| InjectionToken<any>| string): number| | 
					
						
							|  |  |  |     Function|undefined { | 
					
						
							| 
									
										
										
										
											2018-10-24 16:02:25 -07:00
										 |  |  |   ngDevMode && assertDefined(token, 'token must be defined'); | 
					
						
							| 
									
										
										
										
											2018-11-28 12:51:00 -08:00
										 |  |  |   if (typeof token === 'string') { | 
					
						
							|  |  |  |     return token.charCodeAt(0) || 0; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-02 21:12:26 -07:00
										 |  |  |   const tokenId: number|undefined = (token as any)[NG_ELEMENT_ID]; | 
					
						
							| 
									
										
										
										
											2019-01-10 23:45:02 -08:00
										 |  |  |   // Negative token IDs are used for special objects such as `Injector`
 | 
					
						
							|  |  |  |   return (typeof tokenId === 'number' && tokenId > 0) ? tokenId & BLOOM_MASK : tokenId; | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | export function bloomHasToken( | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |     bloomHash: number, injectorIndex: number, injectorView: LView | 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-12-13 11:14:33 +01:00
										 |  |  | function shouldSearchParent(flags: InjectFlags, isFirstHostTNode: boolean): boolean|number { | 
					
						
							|  |  |  |   return !(flags & InjectFlags.Self) && !(flags & InjectFlags.Host && isFirstHostTNode); | 
					
						
							| 
									
										
										
										
											2018-04-23 18:24:40 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-23 14:28:15 -07:00
										 |  |  | export class NodeInjector implements Injector { | 
					
						
							|  |  |  |   constructor( | 
					
						
							| 
									
										
										
										
											2019-01-03 14:43:06 +01:00
										 |  |  |       private _tNode: TElementNode|TContainerNode|TElementContainerNode|null, | 
					
						
							|  |  |  |       private _lView: LView) {} | 
					
						
							| 
									
										
										
										
											2018-10-23 14:28:15 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-07 10:56:51 +01:00
										 |  |  |   get(token: any, notFoundValue?: any): any { | 
					
						
							|  |  |  |     return getOrCreateInjectable(this._tNode, this._lView, token, undefined, notFoundValue); | 
					
						
							| 
									
										
										
										
											2018-10-23 14:28:15 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  |   } | 
					
						
							|  |  |  | } |