mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
refactor(devtools): use internal ivy data structures for extracting component tree
This commit is contained in:
parent
87aaa4933c
commit
c2dfa86702
4 changed files with 68 additions and 55 deletions
|
|
@ -84,7 +84,7 @@
|
|||
"ts-node": "~8.3.0",
|
||||
"tsickle": "^0.35.0",
|
||||
"tslint": "~5.18.0",
|
||||
"typescript": "~3.6.4",
|
||||
"typescript": "~3.7.0",
|
||||
"wait-on": "^4.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
import { getComponentName } from './highlighter';
|
||||
import { DebuggingAPI } from './interfaces';
|
||||
import { IndexedNode } from './observer/identity-tracker';
|
||||
import { buildDirectiveTree } from './lview-transform';
|
||||
|
||||
const ngDebug = (window as any).ng;
|
||||
|
||||
|
|
@ -63,56 +64,9 @@ export const getLatestComponentState = (query: ComponentExplorerViewQuery): Dire
|
|||
return result;
|
||||
};
|
||||
|
||||
export const getDirectiveForest = (root: HTMLElement, ngd: DebuggingAPI): ComponentTreeNode[] =>
|
||||
buildDirectiveForest(root, { element: '__ROOT__', component: null, directives: [], children: [] }, ngd);
|
||||
|
||||
const buildDirectiveForest = (
|
||||
node: Node,
|
||||
tree: ComponentTreeNode | undefined,
|
||||
ngd: DebuggingAPI
|
||||
): ComponentTreeNode[] => {
|
||||
if (!node) {
|
||||
return [tree];
|
||||
}
|
||||
let dirs = [];
|
||||
if (tree.element !== '__ROOT__') {
|
||||
// Need to make sure we're in a component tree
|
||||
// otherwise, ngd.getDirectives will throw without
|
||||
// a root node.
|
||||
try {
|
||||
dirs = ngd.getDirectives(node) || [];
|
||||
} catch (e) {}
|
||||
}
|
||||
const cmp = node instanceof HTMLElement && ngd.getComponent(node);
|
||||
if (!cmp && !dirs.length) {
|
||||
Array.from(node.childNodes).forEach(c => buildDirectiveForest(c, tree, ngd));
|
||||
return tree.children;
|
||||
}
|
||||
const current: ComponentTreeNode = {
|
||||
element: node.constructor.name,
|
||||
directives: dirs.map(dir => {
|
||||
return {
|
||||
instance: dir,
|
||||
name: getComponentName(dir),
|
||||
} as DirectiveInstanceType;
|
||||
}),
|
||||
component: null,
|
||||
children: [],
|
||||
nativeElement: node,
|
||||
};
|
||||
|
||||
const name = node instanceof HTMLElement ? node.tagName.toLowerCase() : node.nodeName.toLowerCase();
|
||||
if (cmp) {
|
||||
current.component = {
|
||||
instance: cmp,
|
||||
name,
|
||||
};
|
||||
} else {
|
||||
current.element = name;
|
||||
}
|
||||
tree.children.push(current);
|
||||
Array.from(node.childNodes).forEach(c => buildDirectiveForest(c, current, ngd));
|
||||
return tree.children;
|
||||
export const getDirectiveForest = (root: HTMLElement, ngd: DebuggingAPI): ComponentTreeNode[] => {
|
||||
const roots = Array.from(root.querySelectorAll('[ng-version]')).map(el => ngd.getComponent(el).__ngContext__);
|
||||
return Array.prototype.concat.apply([], roots.map(buildDirectiveTree));
|
||||
};
|
||||
|
||||
// Based on an ElementID we return a specific component node.
|
||||
|
|
|
|||
59
projects/ng-devtools-backend/src/lib/lview-transform.ts
Normal file
59
projects/ng-devtools-backend/src/lib/lview-transform.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import { ComponentTreeNode } from './component-tree';
|
||||
|
||||
const HEADER_OFFSET = 19;
|
||||
const TYPE = 1;
|
||||
const ELEMENT = 0;
|
||||
const LVIEW_TVIEW = 1;
|
||||
|
||||
export function isLContainer(value: any) {
|
||||
return Array.isArray(value) && value[TYPE] === true;
|
||||
}
|
||||
|
||||
const getNode = (lView: any, data: any, idx: number): ComponentTreeNode => {
|
||||
const directives = [];
|
||||
let component = null;
|
||||
const tNode = data[idx];
|
||||
for (let i = tNode.directiveStart; i < tNode.directiveEnd; i++) {
|
||||
const dir = lView[i];
|
||||
const dirMeta = data[i];
|
||||
if (dirMeta && dirMeta.template) {
|
||||
component = {
|
||||
name: dir.constructor.name,
|
||||
instance: dir,
|
||||
};
|
||||
} else if (dirMeta) {
|
||||
directives.push({
|
||||
name: dir.constructor.name,
|
||||
instance: dir,
|
||||
});
|
||||
}
|
||||
}
|
||||
return {
|
||||
element: (lView[idx][ELEMENT].tagName || lView[idx][ELEMENT].nodeName).toLowerCase(),
|
||||
nativeElement: lView[idx][ELEMENT],
|
||||
directives,
|
||||
component,
|
||||
children: [],
|
||||
};
|
||||
};
|
||||
|
||||
const extractNodes = (lViewOrLContainer: any, nodes = []): ComponentTreeNode[] => {
|
||||
if (isLContainer(lViewOrLContainer)) {
|
||||
for (let i = 9; i < lViewOrLContainer.length; i++) {
|
||||
extractNodes(lViewOrLContainer[i], nodes);
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
const lView = lViewOrLContainer;
|
||||
const tView = lView[LVIEW_TVIEW];
|
||||
for (let i = HEADER_OFFSET; i < lView.length; i++) {
|
||||
if (lView[i] && lView[i][ELEMENT] instanceof Node) {
|
||||
const node = getNode(lView, tView.data, i);
|
||||
nodes.push(node);
|
||||
extractNodes(lView[i], node.children);
|
||||
}
|
||||
}
|
||||
return nodes;
|
||||
};
|
||||
|
||||
export const buildDirectiveTree = (lView: any) => extractNodes(lView);
|
||||
|
|
@ -10122,10 +10122,10 @@ typescript@3.6.4:
|
|||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.4.tgz#b18752bb3792bc1a0281335f7f6ebf1bbfc5b91d"
|
||||
integrity sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==
|
||||
|
||||
typescript@~3.6.4:
|
||||
version "3.6.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.5.tgz#dae20114a7b4ff4bd642db9c8c699f2953e8bbdb"
|
||||
integrity sha512-BEjlc0Z06ORZKbtcxGrIvvwYs5hAnuo6TKdNFL55frVDlB+na3z5bsLhFaIxmT+dPWgBIjMo6aNnTOgHHmHgiQ==
|
||||
typescript@~3.7.0:
|
||||
version "3.7.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae"
|
||||
integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==
|
||||
|
||||
ultron@~1.1.0:
|
||||
version "1.1.1"
|
||||
|
|
|
|||
Loading…
Reference in a new issue