feat(ivy): expose a series of helpful application inspection tools (#25919)
PR Close #25919
This commit is contained in:

committed by
Kara Erickson

parent
cf095d982d
commit
0c344715e5
143
packages/core/src/render3/discovery_utils.ts
Normal file
143
packages/core/src/render3/discovery_utils.ts
Normal file
@ -0,0 +1,143 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
import {Injector} from '../di/injector';
|
||||
|
||||
import {assertDefined} from './assert';
|
||||
import {LContext, discoverDirectiveIndices, discoverDirectives, getContext, isComponentInstance, readPatchedLViewData} from './context_discovery';
|
||||
import {LElementNode, TNode, TNodeFlags} from './interfaces/node';
|
||||
import {CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, PARENT, RootContext, TVIEW} from './interfaces/view';
|
||||
|
||||
|
||||
/**
|
||||
* NOTE: The following functions might not be ideal for core usage in Angular...
|
||||
*
|
||||
* Each function below is designed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the component instance associated with the target.
|
||||
*
|
||||
* If a DOM is used then it will return the component that
|
||||
* owns the view where the element is situated.
|
||||
* If a component instance is used then it will return the
|
||||
* instance of the parent component depending on where
|
||||
* the component instance is exists in a template.
|
||||
* If a directive instance is used then it will return the
|
||||
* component that contains that directive in it's template.
|
||||
*/
|
||||
export function getComponent<T = {}>(target: {}): T|null {
|
||||
const context = loadContext(target) !;
|
||||
|
||||
if (context.component === undefined) {
|
||||
let lViewData = context.lViewData;
|
||||
while (lViewData) {
|
||||
const ctx = lViewData ![CONTEXT] !as{};
|
||||
if (ctx && isComponentInstance(ctx)) {
|
||||
context.component = ctx;
|
||||
break;
|
||||
}
|
||||
lViewData = lViewData ![PARENT] !;
|
||||
}
|
||||
if (context.component === undefined) {
|
||||
context.component = null;
|
||||
}
|
||||
}
|
||||
|
||||
return context.component as T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the host component instance associated with the target.
|
||||
*
|
||||
* This will only return a component instance of the DOM node
|
||||
* contains an instance of a component on it.
|
||||
*/
|
||||
export function getHostComponent<T = {}>(target: {}): T|null {
|
||||
const context = loadContext(target);
|
||||
const tNode = context.lViewData[TVIEW].data[context.lNodeIndex] as TNode;
|
||||
if (tNode.flags & TNodeFlags.isComponent) {
|
||||
const lNode = context.lViewData[context.lNodeIndex] as LElementNode;
|
||||
return lNode.data ![CONTEXT] as any as T;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the `RootContext` instance that is associated with
|
||||
* the application where the target is situated.
|
||||
*/
|
||||
export function getRootContext(target: {}): RootContext {
|
||||
const context = loadContext(target) !;
|
||||
const rootLViewData = getRootView(context.lViewData);
|
||||
return rootLViewData[CONTEXT] as RootContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all the components in the application
|
||||
* that are have been bootstrapped.
|
||||
*/
|
||||
export function getRootComponents(target: {}): any[] {
|
||||
return [...getRootContext(target).components];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the injector instance that is associated with
|
||||
* the element, component or directive.
|
||||
*/
|
||||
export function getInjector(target: {}): Injector|null {
|
||||
const context = loadContext(target) !;
|
||||
return context.lViewData[INJECTOR] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all the directives that are associated
|
||||
* with the underlying target element.
|
||||
*/
|
||||
export function getDirectives(target: {}): Array<{}> {
|
||||
const context = loadContext(target) !;
|
||||
|
||||
if (context.directives === undefined) {
|
||||
context.directiveIndices = discoverDirectiveIndices(context.lViewData, context.lNodeIndex);
|
||||
context.directives = context.directiveIndices ?
|
||||
discoverDirectives(context.lViewData, context.directiveIndices) :
|
||||
null;
|
||||
}
|
||||
|
||||
return context.directives || [];
|
||||
}
|
||||
|
||||
function loadContext(target: {}): LContext {
|
||||
const context = getContext(target);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
ngDevMode ? 'Unable to find the given context data for the given target' :
|
||||
'Invalid ng target');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the root view from any component by walking the parent `LViewData` until
|
||||
* reaching the root `LViewData`.
|
||||
*
|
||||
* @param componentOrView any component or view
|
||||
*/
|
||||
export function getRootView(componentOrView: LViewData | {}): LViewData {
|
||||
let lViewData: LViewData;
|
||||
if (Array.isArray(componentOrView)) {
|
||||
ngDevMode && assertDefined(componentOrView, 'lViewData');
|
||||
lViewData = componentOrView as LViewData;
|
||||
} else {
|
||||
ngDevMode && assertDefined(componentOrView, 'component');
|
||||
lViewData = readPatchedLViewData(componentOrView) !;
|
||||
}
|
||||
while (lViewData && !(lViewData[FLAGS] & LViewFlags.IsRoot)) {
|
||||
lViewData = lViewData[PARENT] !;
|
||||
}
|
||||
return lViewData;
|
||||
}
|
Reference in New Issue
Block a user