6
6
* found in the LICENSE file at https://angular.io/license
7
7
*/
8
8
9
- import { Injector , SchemaMetadata } from '../../core' ;
9
+ import { Injector , SchemaMetadata , Type } from '../../core' ;
10
10
import { Sanitizer } from '../../sanitization/sanitizer' ;
11
11
import { KeyValueArray } from '../../util/array_utils' ;
12
12
import { assertDefined } from '../../util/assert' ;
13
13
import { createNamedArrayType } from '../../util/named_array_type' ;
14
14
import { initNgDevMode } from '../../util/ng_dev_mode' ;
15
+ import { assertNodeInjector } from '../assert' ;
16
+ import { getInjectorIndex } from '../di' ;
15
17
import { CONTAINER_HEADER_OFFSET , HAS_TRANSPLANTED_VIEWS , LContainer , MOVED_VIEWS , NATIVE } from '../interfaces/container' ;
16
- import { ComponentTemplate , DirectiveDefList , PipeDefList , ViewQueriesFunction } from '../interfaces/definition' ;
18
+ import { ComponentTemplate , DirectiveDef , DirectiveDefList , PipeDefList , ViewQueriesFunction } from '../interfaces/definition' ;
19
+ import { NO_PARENT_INJECTOR , PARENT_INJECTOR , TNODE } from '../interfaces/injector' ;
17
20
import { AttributeMarker , PropertyAliases , TConstants , TContainerNode , TElementNode , TNode as ITNode , TNodeFlags , TNodeProviderIndexes , TNodeType , TNodeTypeAsString , TViewNode } from '../interfaces/node' ;
18
21
import { SelectorFlags } from '../interfaces/projection' ;
19
22
import { LQueries , TQueries } from '../interfaces/query' ;
20
23
import { RComment , RElement , Renderer3 , RendererFactory3 , RNode } from '../interfaces/renderer' ;
21
24
import { getTStylingRangeNext , getTStylingRangeNextDuplicate , getTStylingRangePrev , getTStylingRangePrevDuplicate , TStylingKey , TStylingRange } from '../interfaces/styling' ;
22
- import { CHILD_HEAD , CHILD_TAIL , CLEANUP , CONTEXT , DebugNode , DECLARATION_VIEW , DestroyHookData , ExpandoInstructions , FLAGS , HEADER_OFFSET , HookData , HOST , INJECTOR , LContainerDebug as ILContainerDebug , LView , LViewDebug as ILViewDebug , LViewDebugRange , LViewDebugRangeContent , LViewFlags , NEXT , PARENT , QUERIES , RENDERER , RENDERER_FACTORY , SANITIZER , T_HOST , TData , TView as ITView , TVIEW , TView , TViewType } from '../interfaces/view' ;
25
+ import { CHILD_HEAD , CHILD_TAIL , CLEANUP , CONTEXT , DebugNode , DECLARATION_VIEW , DestroyHookData , ExpandoInstructions , FLAGS , HEADER_OFFSET , HookData , HOST , INJECTOR , LContainerDebug as ILContainerDebug , LView , LViewDebug as ILViewDebug , LViewDebugRange , LViewDebugRangeContent , LViewFlags , NEXT , PARENT , QUERIES , RENDERER , RENDERER_FACTORY , SANITIZER , T_HOST , TData , TView as ITView , TVIEW , TView , TViewType , TViewTypeAsString } from '../interfaces/view' ;
23
26
import { attachDebugObject } from '../util/debug_utils' ;
27
+ import { getParentInjectorIndex , getParentInjectorView } from '../util/injector_utils' ;
24
28
import { unwrapRNode } from '../util/view_utils' ;
25
29
26
30
const NG_DEV_MODE = ( ( typeof ngDevMode === 'undefined' || ! ! ngDevMode ) && initNgDevMode ( ) ) ;
@@ -152,6 +156,14 @@ export const TViewConstructor = class TView implements ITView {
152
156
processTNodeChildren ( this . firstChild , buf ) ;
153
157
return buf . join ( '' ) ;
154
158
}
159
+
160
+ get type_ ( ) : string {
161
+ return TViewTypeAsString [ this . type ] || `TViewType.?${ this . type } ?` ;
162
+ }
163
+
164
+ get i18nStartIndex ( ) : number {
165
+ return HEADER_OFFSET + this . _decls + this . _vars ;
166
+ }
155
167
} ;
156
168
157
169
class TNode implements ITNode {
@@ -189,23 +201,39 @@ class TNode implements ITNode {
189
201
public styleBindings : TStylingRange , //
190
202
) { }
191
203
192
- get type_ ( ) : string {
193
- switch ( this . type ) {
194
- case TNodeType . Container :
195
- return 'TNodeType.Container' ;
196
- case TNodeType . Element :
197
- return 'TNodeType.Element' ;
198
- case TNodeType . ElementContainer :
199
- return 'TNodeType.ElementContainer' ;
200
- case TNodeType . IcuContainer :
201
- return 'TNodeType.IcuContainer' ;
202
- case TNodeType . Projection :
203
- return 'TNodeType.Projection' ;
204
- case TNodeType . View :
205
- return 'TNodeType.View' ;
206
- default :
207
- return 'TNodeType.???' ;
204
+ /**
205
+ * Return a human debug version of the set of `NodeInjector`s which will be consulted when
206
+ * resolving tokens from this `TNode`.
207
+ *
208
+ * When debugging applications, it is often difficult to determine which `NodeInjector`s will be
209
+ * consulted. This method shows a list of `DebugNode`s representing the `TNode`s which will be
210
+ * consulted in order when resolving a token starting at this `TNode`.
211
+ *
212
+ * The original data is stored in `LView` and `TView` with a lot of offset indexes, and so it is
213
+ * difficult to reason about.
214
+ *
215
+ * @param lView The `LView` instance for this `TNode`.
216
+ */
217
+ debugNodeInjectorPath ( lView : LView ) : DebugNode [ ] {
218
+ const path : DebugNode [ ] = [ ] ;
219
+ let injectorIndex = getInjectorIndex ( this , lView ) ;
220
+ ngDevMode && assertNodeInjector ( lView , injectorIndex ) ;
221
+ while ( injectorIndex !== - 1 ) {
222
+ const tNode = lView [ TVIEW ] . data [ injectorIndex + TNODE ] as TNode ;
223
+ path . push ( buildDebugNode ( tNode , lView ) ) ;
224
+ const parentLocation = lView [ injectorIndex + PARENT_INJECTOR ] ;
225
+ if ( parentLocation === NO_PARENT_INJECTOR ) {
226
+ injectorIndex = - 1 ;
227
+ } else {
228
+ injectorIndex = getParentInjectorIndex ( parentLocation ) ;
229
+ lView = getParentInjectorView ( parentLocation , lView ) ;
230
+ }
208
231
}
232
+ return path ;
233
+ }
234
+
235
+ get type_ ( ) : string {
236
+ return TNodeTypeAsString [ this . type ] || `TNodeType.?${ this . type } ?` ;
209
237
}
210
238
211
239
get flags_ ( ) : string {
@@ -246,6 +274,14 @@ class TNode implements ITNode {
246
274
get classBindings_ ( ) : DebugStyleBindings {
247
275
return toDebugStyleBinding ( this , true ) ;
248
276
}
277
+
278
+ get providerIndexStart_ ( ) : number {
279
+ return this . providerIndexes & TNodeProviderIndexes . ProvidersStartIndexMask ;
280
+ }
281
+ get providerIndexEnd_ ( ) : number {
282
+ return this . providerIndexStart_ +
283
+ ( this . providerIndexes >>> TNodeProviderIndexes . CptViewProvidersCountShift ) ;
284
+ }
249
285
}
250
286
export const TNodeDebug = TNode ;
251
287
export type TNodeDebug = TNode ;
@@ -462,21 +498,21 @@ export class LViewDebug implements ILViewDebug {
462
498
}
463
499
464
500
get decls ( ) : LViewDebugRange {
465
- const tView = this . tView as any as { _decls : number , _vars : number } ;
466
- const start = HEADER_OFFSET ;
467
- return toLViewRange ( this . tView , this . _raw_lView , start , start + tView . _decls ) ;
501
+ return toLViewRange ( this . tView , this . _raw_lView , HEADER_OFFSET , this . tView . bindingStartIndex ) ;
468
502
}
469
503
470
504
get vars ( ) : LViewDebugRange {
471
- const tView = this . tView as any as { _decls : number , _vars : number } ;
472
- const start = HEADER_OFFSET + tView . _decls ;
473
- return toLViewRange ( this . tView , this . _raw_lView , start , start + tView . _vars ) ;
505
+ const tView = this . tView ;
506
+ return toLViewRange (
507
+ tView , this . _raw_lView , tView . bindingStartIndex ,
508
+ ( tView as any as { i18nStartIndex : number } ) . i18nStartIndex ) ;
474
509
}
475
510
476
511
get i18n ( ) : LViewDebugRange {
477
- const tView = this . tView as any as { _decls : number , _vars : number } ;
478
- const start = HEADER_OFFSET + tView . _decls + tView . _vars ;
479
- return toLViewRange ( this . tView , this . _raw_lView , start , this . tView . expandoStartIndex ) ;
512
+ const tView = this . tView ;
513
+ return toLViewRange (
514
+ tView , this . _raw_lView , ( tView as any as { i18nStartIndex : number } ) . i18nStartIndex ,
515
+ tView . expandoStartIndex ) ;
480
516
}
481
517
482
518
get expando ( ) : LViewDebugRange {
@@ -518,7 +554,7 @@ export function toDebugNodes(tNode: ITNode|null, lView: LView): DebugNode[] {
518
554
const debugNodes : DebugNode [ ] = [ ] ;
519
555
let tNodeCursor : ITNode | null = tNode ;
520
556
while ( tNodeCursor ) {
521
- debugNodes . push ( buildDebugNode ( tNodeCursor , lView , tNodeCursor . index ) ) ;
557
+ debugNodes . push ( buildDebugNode ( tNodeCursor , lView ) ) ;
522
558
tNodeCursor = tNodeCursor . next ;
523
559
}
524
560
return debugNodes ;
@@ -527,17 +563,75 @@ export function toDebugNodes(tNode: ITNode|null, lView: LView): DebugNode[] {
527
563
}
528
564
}
529
565
530
- export function buildDebugNode ( tNode : ITNode , lView : LView, nodeIndex : number ) : DebugNode {
531
- const rawValue = lView [ nodeIndex ] ;
566
+ export function buildDebugNode ( tNode : ITNode , lView : LView ) : DebugNode {
567
+ const rawValue = lView [ tNode . index ] ;
532
568
const native = unwrapRNode ( rawValue ) ;
569
+ const factories : Type < any > [ ] = [ ] ;
570
+ const instances : any [ ] = [ ] ;
571
+ const tView = lView [ TVIEW ] ;
572
+ for ( let i = tNode . directiveStart ; i < tNode . directiveEnd ; i ++ ) {
573
+ const def = tView . data [ i ] as DirectiveDef < any > ;
574
+ factories . push ( def . type ) ;
575
+ instances . push ( lView [ i ] ) ;
576
+ }
533
577
return {
534
578
html : toHtml ( native ) ,
535
579
type : TNodeTypeAsString [ tNode . type ] ,
536
580
native : native as any ,
537
581
children : toDebugNodes ( tNode . child , lView ) ,
582
+ factories,
583
+ instances,
584
+ injector : buildNodeInjectorDebug ( tNode , tView , lView )
538
585
} ;
539
586
}
540
587
588
+ function buildNodeInjectorDebug ( tNode : ITNode , tView : ITView , lView : LView ) {
589
+ const viewProviders : Type < any > [ ] = [ ] ;
590
+ for ( let i = ( tNode as TNode ) . providerIndexStart_ ; i < ( tNode as TNode ) . providerIndexEnd_ ; i ++ ) {
591
+ viewProviders . push ( tView . data [ i ] as Type < any > ) ;
592
+ }
593
+ const providers : Type < any > [ ] = [ ] ;
594
+ for ( let i = ( tNode as TNode ) . providerIndexEnd_ ; i < ( tNode as TNode ) . directiveEnd ; i ++ ) {
595
+ providers . push ( tView . data [ i ] as Type < any > ) ;
596
+ }
597
+ const nodeInjectorDebug = {
598
+ bloom : toBloom ( lView , tNode . injectorIndex ) ,
599
+ cumulativeBloom : toBloom ( tView . data , tNode . injectorIndex ) ,
600
+ providers,
601
+ viewProviders,
602
+ parentInjectorIndex : lView [ ( tNode as TNode ) . providerIndexStart_ - 1 ] ,
603
+ } ;
604
+ return nodeInjectorDebug ;
605
+ }
606
+
607
+ /**
608
+ * Convert a number at `idx` location in `array` into binary representation.
609
+ *
610
+ * @param array
611
+ * @param idx
612
+ */
613
+ function binary ( array : any [ ] , idx : number ) : string {
614
+ const value = array [ idx ] ;
615
+ // If not a number we print 8 `?` to retain alignment but let user know that it was called on
616
+ // wrong type.
617
+ if ( typeof value !== 'number' ) return '????????' ;
618
+ // We prefix 0s so that we have constant length number
619
+ const text = '00000000' + value . toString ( 2 ) ;
620
+ return text . substring ( text . length - 8 ) ;
621
+ }
622
+
623
+ /**
624
+ * Convert a bloom filter at location `idx` in `array` into binary representation.
625
+ *
626
+ * @param array
627
+ * @param idx
628
+ */
629
+ function toBloom ( array : any [ ] , idx : number ) : string {
630
+ return `${ binary ( array , idx + 7 ) } _${ binary ( array , idx + 6 ) } _${ binary ( array , idx + 5 ) } _${
631
+ binary ( array , idx + 4 ) } _${ binary ( array , idx + 3 ) } _${ binary ( array , idx + 2 ) } _${
632
+ binary ( array , idx + 1 ) } _${ binary ( array , idx + 0 ) } `;
633
+ }
634
+
541
635
export class LContainerDebug implements ILContainerDebug {
542
636
constructor ( private readonly _raw_lContainer : LContainer ) { }
543
637
0 commit comments