Skip to content

Commit ef7b70a

Browse files
mheveryAndrewKushnir
authored andcommitted
refactor(core): add debug ranges to LViewDebug with matchers (angular#38359)
This change provides better typing for the `LView.debug` property which is intended to be used by humans while debugging the application with `ngDevMode` turned on. In addition this chang also adds jasmine matchers for better asserting that `LView` is in the correct state. PR Close angular#38359
1 parent deb290b commit ef7b70a

File tree

15 files changed

+929
-69
lines changed

15 files changed

+929
-69
lines changed

goldens/circular-deps/packages.json

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -223,15 +223,7 @@
223223
"packages/core/src/render3/assert.ts",
224224
"packages/core/src/render3/interfaces/container.ts",
225225
"packages/core/src/render3/interfaces/node.ts",
226-
"packages/core/src/render3/interfaces/definition.ts",
227-
"packages/core/src/core.ts",
228-
"packages/core/src/metadata.ts",
229-
"packages/core/src/di.ts",
230-
"packages/core/src/di/index.ts",
231-
"packages/core/src/di/injectable.ts",
232-
"packages/core/src/di/jit/injectable.ts",
233-
"packages/core/src/di/jit/environment.ts",
234-
"packages/core/src/di/injector_compatibility.ts",
226+
"packages/core/src/render3/interfaces/view.ts",
235227
"packages/core/src/di/injector.ts",
236228
"packages/core/src/di/r3_injector.ts",
237229
"packages/core/src/render3/definition.ts",
@@ -247,8 +239,14 @@
247239
"packages/core/src/render3/assert.ts",
248240
"packages/core/src/render3/interfaces/container.ts",
249241
"packages/core/src/render3/interfaces/node.ts",
250-
"packages/core/src/render3/interfaces/definition.ts",
251242
"packages/core/src/render3/interfaces/view.ts",
243+
"packages/core/src/metadata.ts",
244+
"packages/core/src/di.ts",
245+
"packages/core/src/di/index.ts",
246+
"packages/core/src/di/injectable.ts",
247+
"packages/core/src/di/jit/injectable.ts",
248+
"packages/core/src/di/jit/environment.ts",
249+
"packages/core/src/di/injector_compatibility.ts",
252250
"packages/core/src/di/injector.ts",
253251
"packages/core/src/di/r3_injector.ts",
254252
"packages/core/src/render3/definition.ts",
@@ -264,8 +262,9 @@
264262
"packages/core/src/render3/assert.ts",
265263
"packages/core/src/render3/interfaces/container.ts",
266264
"packages/core/src/render3/interfaces/node.ts",
267-
"packages/core/src/render3/interfaces/definition.ts",
268265
"packages/core/src/render3/interfaces/view.ts",
266+
"packages/core/src/render3/interfaces/definition.ts",
267+
"packages/core/src/core.ts",
269268
"packages/core/src/metadata.ts",
270269
"packages/core/src/di.ts",
271270
"packages/core/src/di/index.ts",
@@ -1766,27 +1765,25 @@
17661765
[
17671766
"packages/core/src/render3/interfaces/container.ts",
17681767
"packages/core/src/render3/interfaces/node.ts",
1769-
"packages/core/src/render3/interfaces/definition.ts",
17701768
"packages/core/src/render3/interfaces/view.ts"
17711769
],
17721770
[
17731771
"packages/core/src/render3/interfaces/definition.ts",
1774-
"packages/core/src/render3/interfaces/node.ts"
1772+
"packages/core/src/render3/interfaces/node.ts",
1773+
"packages/core/src/render3/interfaces/view.ts"
17751774
],
17761775
[
17771776
"packages/core/src/render3/interfaces/definition.ts",
17781777
"packages/core/src/render3/interfaces/view.ts"
17791778
],
17801779
[
1781-
"packages/core/src/render3/interfaces/definition.ts",
1782-
"packages/core/src/render3/interfaces/view.ts",
1783-
"packages/core/src/render3/interfaces/node.ts"
1780+
"packages/core/src/render3/interfaces/node.ts",
1781+
"packages/core/src/render3/interfaces/view.ts"
17841782
],
17851783
[
1786-
"packages/core/src/render3/interfaces/definition.ts",
1784+
"packages/core/src/render3/interfaces/node.ts",
17871785
"packages/core/src/render3/interfaces/view.ts",
1788-
"packages/core/src/render3/interfaces/query.ts",
1789-
"packages/core/src/render3/interfaces/node.ts"
1786+
"packages/core/src/render3/interfaces/query.ts"
17901787
],
17911788
[
17921789
"packages/core/src/render3/interfaces/query.ts",

goldens/size-tracking/integration-payloads.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
"bundle": "TODO(i): we should define ngDevMode to false in Closure, but --define only works in the global scope.",
6363
"bundle": "TODO(i): (FW-2164) TS 3.9 new class shape seems to have broken Closure in big ways. The size went from 169991 to 252338",
6464
"bundle": "TODO(i): after removal of tsickle from ngc-wrapped / ng_package, we had to switch to SIMPLE optimizations which increased the size from 252338 to 1198917, see PR#37221 and PR#37317 for more info",
65-
"bundle": 1212027
65+
"bundle": 1213130
6666
}
6767
}
6868
}

packages/core/src/render3/instructions/lview_debug.ts

Lines changed: 59 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,14 @@ import {createNamedArrayType} from '../../util/named_array_type';
1515
import {initNgDevMode} from '../../util/ng_dev_mode';
1616
import {CONTAINER_HEADER_OFFSET, HAS_TRANSPLANTED_VIEWS, LContainer, MOVED_VIEWS, NATIVE} from '../interfaces/container';
1717
import {DirectiveDefList, PipeDefList, ViewQueriesFunction} from '../interfaces/definition';
18-
import {COMMENT_MARKER, ELEMENT_MARKER, I18nMutateOpCode, I18nMutateOpCodes, I18nUpdateOpCode, I18nUpdateOpCodes, TIcu} from '../interfaces/i18n';
19-
import {PropertyAliases, TConstants, TContainerNode, TElementNode, TNode as ITNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TViewNode} from '../interfaces/node';
18+
import {PropertyAliases, TConstants, TContainerNode, TElementNode, TNode as ITNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TNodeTypeAsString, TViewNode} from '../interfaces/node';
2019
import {SelectorFlags} from '../interfaces/projection';
2120
import {LQueries, TQueries} from '../interfaces/query';
2221
import {RComment, RElement, Renderer3, RendererFactory3, RNode} from '../interfaces/renderer';
2322
import {getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate, TStylingKey, TStylingRange} from '../interfaces/styling';
24-
import {CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DECLARATION_VIEW, DestroyHookData, ExpandoInstructions, FLAGS, HEADER_OFFSET, HookData, HOST, INJECTOR, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, SANITIZER, T_HOST, TData, TVIEW, TView as ITView, TView, TViewType} from '../interfaces/view';
23+
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';
2524
import {attachDebugObject} from '../util/debug_utils';
26-
import {getTNode, unwrapRNode} from '../util/view_utils';
25+
import {unwrapRNode} from '../util/view_utils';
2726

2827
const NG_DEV_MODE = ((typeof ngDevMode === 'undefined' || !!ngDevMode) && initNgDevMode());
2928

@@ -143,7 +142,10 @@ export const TViewConstructor = class TView implements ITView {
143142
public firstChild: ITNode|null, //
144143
public schemas: SchemaMetadata[]|null, //
145144
public consts: TConstants|null, //
146-
public incompleteFirstPass: boolean //
145+
public incompleteFirstPass: boolean, //
146+
public _decls: number, //
147+
public _vars: number, //
148+
147149
) {}
148150

149151
get template_(): string {
@@ -335,9 +337,9 @@ export function attachLContainerDebug(lContainer: LContainer) {
335337
attachDebugObject(lContainer, new LContainerDebug(lContainer));
336338
}
337339

338-
export function toDebug(obj: LView): LViewDebug;
339-
export function toDebug(obj: LView|null): LViewDebug|null;
340-
export function toDebug(obj: LView|LContainer|null): LViewDebug|LContainerDebug|null;
340+
export function toDebug(obj: LView): ILViewDebug;
341+
export function toDebug(obj: LView|null): ILViewDebug|null;
342+
export function toDebug(obj: LView|LContainer|null): ILViewDebug|ILContainerDebug|null;
341343
export function toDebug(obj: any): any {
342344
if (obj) {
343345
const debug = (obj as any).debug;
@@ -375,7 +377,7 @@ function toHtml(value: any, includeChildren: boolean = false): string|null {
375377
}
376378
}
377379

378-
export class LViewDebug {
380+
export class LViewDebug implements ILViewDebug {
379381
constructor(private readonly _raw_lView: LView) {}
380382

381383
/**
@@ -396,10 +398,10 @@ export class LViewDebug {
396398
indexWithinInitPhase: flags >> LViewFlags.IndexWithinInitPhaseShift,
397399
};
398400
}
399-
get parent(): LViewDebug|LContainerDebug|null {
401+
get parent(): ILViewDebug|ILContainerDebug|null {
400402
return toDebug(this._raw_lView[PARENT]);
401403
}
402-
get host(): string|null {
404+
get hostHTML(): string|null {
403405
return toHtml(this._raw_lView[HOST], true);
404406
}
405407
get html(): string {
@@ -410,10 +412,9 @@ export class LViewDebug {
410412
}
411413
/**
412414
* The tree of nodes associated with the current `LView`. The nodes have been normalized into
413-
* a
414-
* tree structure with relevant details pulled out for readability.
415+
* a tree structure with relevant details pulled out for readability.
415416
*/
416-
get nodes(): DebugNode[]|null {
417+
get nodes(): DebugNode[] {
417418
const lView = this._raw_lView;
418419
const tNode = lView[TVIEW].firstChild;
419420
return toDebugNodes(tNode, lView);
@@ -437,16 +438,16 @@ export class LViewDebug {
437438
get sanitizer(): Sanitizer|null {
438439
return this._raw_lView[SANITIZER];
439440
}
440-
get childHead(): LViewDebug|LContainerDebug|null {
441+
get childHead(): ILViewDebug|ILContainerDebug|null {
441442
return toDebug(this._raw_lView[CHILD_HEAD]);
442443
}
443-
get next(): LViewDebug|LContainerDebug|null {
444+
get next(): ILViewDebug|ILContainerDebug|null {
444445
return toDebug(this._raw_lView[NEXT]);
445446
}
446-
get childTail(): LViewDebug|LContainerDebug|null {
447+
get childTail(): ILViewDebug|ILContainerDebug|null {
447448
return toDebug(this._raw_lView[CHILD_TAIL]);
448449
}
449-
get declarationView(): LViewDebug|null {
450+
get declarationView(): ILViewDebug|null {
450451
return toDebug(this._raw_lView[DECLARATION_VIEW]);
451452
}
452453
get queries(): LQueries|null {
@@ -456,11 +457,35 @@ export class LViewDebug {
456457
return this._raw_lView[T_HOST];
457458
}
458459

460+
get decls(): LViewDebugRange {
461+
const tView = this.tView as any as {_decls: number, _vars: number};
462+
const start = HEADER_OFFSET;
463+
return toLViewRange(this.tView, this._raw_lView, start, start + tView._decls);
464+
}
465+
466+
get vars(): LViewDebugRange {
467+
const tView = this.tView as any as {_decls: number, _vars: number};
468+
const start = HEADER_OFFSET + tView._decls;
469+
return toLViewRange(this.tView, this._raw_lView, start, start + tView._vars);
470+
}
471+
472+
get i18n(): LViewDebugRange {
473+
const tView = this.tView as any as {_decls: number, _vars: number};
474+
const start = HEADER_OFFSET + tView._decls + tView._vars;
475+
return toLViewRange(this.tView, this._raw_lView, start, this.tView.expandoStartIndex);
476+
}
477+
478+
get expando(): LViewDebugRange {
479+
const tView = this.tView as any as {_decls: number, _vars: number};
480+
return toLViewRange(
481+
this.tView, this._raw_lView, this.tView.expandoStartIndex, this._raw_lView.length);
482+
}
483+
459484
/**
460485
* Normalized view of child views (and containers) attached at this location.
461486
*/
462-
get childViews(): Array<LViewDebug|LContainerDebug> {
463-
const childViews: Array<LViewDebug|LContainerDebug> = [];
487+
get childViews(): Array<ILViewDebug|ILContainerDebug> {
488+
const childViews: Array<ILViewDebug|ILContainerDebug> = [];
464489
let child = this.childHead;
465490
while (child) {
466491
childViews.push(child);
@@ -470,11 +495,12 @@ export class LViewDebug {
470495
}
471496
}
472497

473-
export interface DebugNode {
474-
html: string|null;
475-
native: Node;
476-
nodes: DebugNode[]|null;
477-
component: LViewDebug|null;
498+
function toLViewRange(tView: TView, lView: LView, start: number, end: number): LViewDebugRange {
499+
let content: LViewDebugRangeContent[] = [];
500+
for (let index = start; index < end; index++) {
501+
content.push({index: index, t: tView.data[index], l: lView[index]});
502+
}
503+
return {start: start, end: end, length: end - start, content: content};
478504
}
479505

480506
/**
@@ -483,7 +509,7 @@ export interface DebugNode {
483509
* @param tNode
484510
* @param lView
485511
*/
486-
export function toDebugNodes(tNode: ITNode|null, lView: LView): DebugNode[]|null {
512+
export function toDebugNodes(tNode: ITNode|null, lView: LView): DebugNode[] {
487513
if (tNode) {
488514
const debugNodes: DebugNode[] = [];
489515
let tNodeCursor: ITNode|null = tNode;
@@ -493,33 +519,32 @@ export function toDebugNodes(tNode: ITNode|null, lView: LView): DebugNode[]|null
493519
}
494520
return debugNodes;
495521
} else {
496-
return null;
522+
return [];
497523
}
498524
}
499525

500526
export function buildDebugNode(tNode: ITNode, lView: LView, nodeIndex: number): DebugNode {
501527
const rawValue = lView[nodeIndex];
502528
const native = unwrapRNode(rawValue);
503-
const componentLViewDebug = toDebug(readLViewValue(rawValue));
504529
return {
505530
html: toHtml(native),
531+
type: TNodeTypeAsString[tNode.type],
506532
native: native as any,
507-
nodes: toDebugNodes(tNode.child, lView),
508-
component: componentLViewDebug,
533+
children: toDebugNodes(tNode.child, lView),
509534
};
510535
}
511536

512-
export class LContainerDebug {
537+
export class LContainerDebug implements ILContainerDebug {
513538
constructor(private readonly _raw_lContainer: LContainer) {}
514539

515540
get hasTransplantedViews(): boolean {
516541
return this._raw_lContainer[HAS_TRANSPLANTED_VIEWS];
517542
}
518-
get views(): LViewDebug[] {
543+
get views(): ILViewDebug[] {
519544
return this._raw_lContainer.slice(CONTAINER_HEADER_OFFSET)
520-
.map(toDebug as (l: LView) => LViewDebug);
545+
.map(toDebug as (l: LView) => ILViewDebug);
521546
}
522-
get parent(): LViewDebug|LContainerDebug|null {
547+
get parent(): ILViewDebug|null {
523548
return toDebug(this._raw_lContainer[PARENT]);
524549
}
525550
get movedViews(): LView[]|null {

packages/core/src/render3/instructions/shared.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,9 @@ export function createTView(
699699
null, // firstChild: TNode|null,
700700
schemas, // schemas: SchemaMetadata[]|null,
701701
consts, // consts: TConstants|null
702-
false // incompleteFirstPass: boolean
702+
false, // incompleteFirstPass: boolean
703+
decls, // ngDevMode only: decls
704+
vars, // ngDevMode only: vars
703705
) :
704706
{
705707
type: type,

packages/core/src/render3/interfaces/node.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,11 @@
77
*/
88
import {KeyValueArray} from '../../util/array_utils';
99
import {TStylingRange} from '../interfaces/styling';
10-
11-
import {DirectiveDef} from './definition';
1210
import {CssSelector} from './projection';
1311
import {RNode} from './renderer';
1412
import {LView, TView} from './view';
1513

1614

17-
1815
/**
1916
* TNodeType corresponds to the {@link TNode} `type` property.
2017
*/
@@ -45,6 +42,20 @@ export const enum TNodeType {
4542
IcuContainer = 5,
4643
}
4744

45+
/**
46+
* Converts `TNodeType` into human readable text.
47+
* Make sure this matches with `TNodeType`
48+
*/
49+
export const TNodeTypeAsString = [
50+
'Container', // 0
51+
'Projection', // 1
52+
'View', // 2
53+
'Element', // 3
54+
'ElementContainer', // 4
55+
'IcuContainer' // 5
56+
] as const;
57+
58+
4859
/**
4960
* Corresponds to the TNode.flags property.
5061
*/

0 commit comments

Comments
 (0)