Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 3 additions & 31 deletions devtools/projects/ng-devtools-backend/src/lib/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ ts_project(
name = "property_mutation",
srcs = ["property-mutation.ts"],
deps = [
":utils",
"//:node_modules/@angular/core",
"//devtools/projects/ng-devtools-backend/src/lib/utils",
],
)

Expand Down Expand Up @@ -111,35 +111,6 @@ ts_project(
],
)

ts_project(
name = "utils",
srcs = [
"serialization-utils.ts",
"utils.ts",
],
deps = [
"//:node_modules/@angular/core",
"//devtools/projects/ng-devtools-backend/src/lib/ng-debug-api",
],
)

zoneless_web_test_suite(
name = "utils_test",
deps = [
":utils_test_lib",
],
)

ts_test_library(
name = "utils_test_lib",
srcs = [
"serialization-utils.spec.ts",
],
deps = [
":utils",
],
)

ts_project(
name = "version",
srcs = ["version.ts"],
Expand Down Expand Up @@ -174,13 +145,14 @@ ts_project(
":interfaces",
":router_tree",
":set_console_reference",
":utils",
"//:node_modules/@angular/core",
"//:node_modules/rxjs",
"//devtools/projects/ng-devtools-backend/src/lib/component-inspector",
"//devtools/projects/ng-devtools-backend/src/lib/component-tree",
"//devtools/projects/ng-devtools-backend/src/lib/hooks",
"//devtools/projects/ng-devtools-backend/src/lib/ng-debug-api",
"//devtools/projects/ng-devtools-backend/src/lib/state-serializer",
"//devtools/projects/ng-devtools-backend/src/lib/utils",
"//devtools/projects/protocol",
"//devtools/projects/shared-utils",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {ɵDebugSignalGraph} from '@angular/core';
import {
ComponentExplorerViewQuery,
ComponentType,
Expand Down Expand Up @@ -57,10 +58,11 @@ import {getRouterCallableConstructRef, parseRoutes, RoutePropertyType} from './r
import {ngDebugClient, ngDebugDependencyInjectionApiIsSupported} from './ng-debug-api/ng-debug-api';
import {setConsoleReference} from './set-console-reference';
import {serializeDirectiveState, serializeValue} from './state-serializer/state-serializer';
import {runOutsideAngular, unwrapSignal} from './utils';
import {runOutsideAngular, unwrapSignal} from './utils/general';
import {DirectiveForestHooks} from './hooks/hooks';
import {getSupportedApis} from './ng-debug-api/supported-apis';
import {sanitizeObject} from './serialization-utils';
import {sanitizeObject} from './utils/serialization';
import {SignalGraphRef} from './utils/signal-graph-ref';

type InspectorRef = {ref: ComponentInspector | null};

Expand Down Expand Up @@ -262,7 +264,21 @@ const getSignalNestedPropertiesCallback =

const ng = ngDebugClient();

const signalGraph = ng.ɵgetSignalGraph?.(injector);
let signalGraph: ɵDebugSignalGraph | undefined;

// Considering that the inspection of signal value nested properties
// usually involves multiple requests, we store the signal graph
// during the first call. We keep only the last requested signal graph
// to avoid filling the heap with graphs that may not be needed.
if (componentSignalGraphRef.exists(node.nativeElement!)) {
signalGraph = componentSignalGraphRef.deref(node.nativeElement!);
} else {
signalGraph = ng.ɵgetSignalGraph?.(injector);
if (signalGraph) {
componentSignalGraphRef.set(node.nativeElement!, signalGraph);
}
}

if (!signalGraph) {
return emitEmpty();
}
Expand Down Expand Up @@ -493,7 +509,7 @@ const getInjectorProvidersCallback =

const serializedProviderRecords: SerializedProviderRecord[] = [];

for (const [token, records] of tokenToRecords.entries()) {
for (const [, records] of tokenToRecords.entries()) {
const multiRecords = records.filter((record) => record.multi);
const nonMultiRecords = records.filter((record) => !record.multi);

Expand Down Expand Up @@ -617,6 +633,10 @@ const getInjectorInstance = (
};

const getSignalGraphCallback = (messageBus: MessageBus<Events>) => (element: ElementPosition) => {
// We assume that a new request for a signal graph
// should invalidate the current ref cache.
componentSignalGraphRef.clear();

const ng = ngDebugClient();

// get injector from position
Expand Down Expand Up @@ -664,3 +684,13 @@ export function sanitizeRouteData(route: Route): Route {

return route;
}

/**
* Keeps a reference to the last requested signal graph.
* This should save us from needlessly calling `ng.ɵgetSignalGraph`
* when we are still managing the same/last graph (e.g. inspecting
* signal value nested properties). The ref is tied to the host element.
*
* Note: If the element is destroyed, the graph is garbage collected.
*/
const componentSignalGraphRef = new SignalGraphRef<Node>();
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ ts_test_library(
"//:node_modules/@angular/core",
"//devtools/projects/ng-devtools-backend/src/lib:highlighter",
"//devtools/projects/ng-devtools-backend/src/lib:interfaces",
"//devtools/projects/ng-devtools-backend/src/lib:utils",
"//devtools/projects/ng-devtools-backend/src/lib/component-tree",
"//devtools/projects/ng-devtools-backend/src/lib/hooks",
"//devtools/projects/ng-devtools-backend/src/lib/utils",
"//devtools/projects/protocol",
],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ ts_project(
"//:node_modules/@angular/core",
"//devtools/projects/ng-devtools-backend/src/lib:interfaces",
"//devtools/projects/ng-devtools-backend/src/lib:property_mutation",
"//devtools/projects/ng-devtools-backend/src/lib:utils",
"//devtools/projects/ng-devtools-backend/src/lib/directive-forest",
"//devtools/projects/ng-devtools-backend/src/lib/ng-debug-api",
"//devtools/projects/ng-devtools-backend/src/lib/state-serializer",
"//devtools/projects/ng-devtools-backend/src/lib/utils",
"//devtools/projects/protocol",
],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import {mutateNestedProp} from '../property-mutation';
import {ComponentTreeNode, DirectiveInstanceType, ComponentInstanceType} from '../interfaces';
import {getAppRoots} from './get-roots';
import {AcxChangeDetectionStrategy, ChangeDetectionStrategy, Framework} from './core-enums';
import {unwrapSignal} from '../utils';
import {unwrapSignal} from '../utils/general';

export const injectorToId = new WeakMap<Injector | HTMLElement, string>();
export const nodeInjectorToResolutionPath = new WeakMap<HTMLElement, SerializedInjector[]>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ ts_project(
"//:node_modules/semver",
"//devtools/projects/ng-devtools-backend/src/lib:highlighter",
"//devtools/projects/ng-devtools-backend/src/lib:interfaces",
"//devtools/projects/ng-devtools-backend/src/lib:utils",
"//devtools/projects/ng-devtools-backend/src/lib:version",
"//devtools/projects/ng-devtools-backend/src/lib/ng-debug-api",
"//devtools/projects/ng-devtools-backend/src/lib/state-serializer",
"//devtools/projects/ng-devtools-backend/src/lib/utils",
"//devtools/projects/protocol",
],
)
Expand All @@ -31,7 +31,7 @@ ts_test_library(
":directive-forest",
"//:node_modules/@angular/core",
"//devtools/projects/ng-devtools-backend/src/lib:interfaces",
"//devtools/projects/ng-devtools-backend/src/lib:utils",
"//devtools/projects/ng-devtools-backend/src/lib/utils",
],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import semver from 'semver';

import {getDirectiveName} from '../highlighter';
import {ComponentInstanceType, ComponentTreeNode, DirectiveInstanceType} from '../interfaces';
import {isCustomElement} from '../utils';
import {isCustomElement} from '../utils/general';
import {VERSION} from '../version';

let HEADER_OFFSET = 19;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {HydrationStatus} from '../../../../protocol';

import {ComponentTreeNode} from '../interfaces';
import {ngDebugClient} from '../ng-debug-api/ng-debug-api';
import {isCustomElement} from '../utils';
import {isCustomElement} from '../utils/general';
import {
ControlFlowBlocksIterator,
createControlFlowTreeNode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ ts_project(
":identity_tracker",
"//devtools/projects/ng-devtools-backend/src/lib:highlighter",
"//devtools/projects/ng-devtools-backend/src/lib:interfaces",
"//devtools/projects/ng-devtools-backend/src/lib:utils",
"//devtools/projects/ng-devtools-backend/src/lib/hooks/profiler",
"//devtools/projects/ng-devtools-backend/src/lib/utils",
"//devtools/projects/protocol",
],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {

import {getDirectiveName} from '../highlighter';
import {ComponentTreeNode} from '../interfaces';
import {isCustomElement, runOutsideAngular} from '../utils';
import {isCustomElement, runOutsideAngular} from '../utils/general';

import {initializeOrGetDirectiveForestHooks} from '.';
import {DirectiveForestHooks} from './hooks';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ ts_project(
deps = [
"//:node_modules/@angular/core",
"//:node_modules/rxjs",
"//devtools/projects/ng-devtools-backend/src/lib:utils",
"//devtools/projects/ng-devtools-backend/src/lib/directive-forest",
"//devtools/projects/ng-devtools-backend/src/lib/hooks:identity_tracker",
"//devtools/projects/ng-devtools-backend/src/lib/ng-debug-api",
"//devtools/projects/ng-devtools-backend/src/lib/utils",
"//devtools/projects/protocol",
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import {ɵProfilerEvent} from '@angular/core';
import {getDirectiveHostElement} from '../../directive-forest';
import {ngDebugClient} from '../../ng-debug-api/ng-debug-api';
import {runOutsideAngular} from '../../utils';
import {runOutsideAngular} from '../../utils/general';
import {IdentityTracker, NodeArray} from '../identity-tracker';

import {getLifeCycleName, Hooks, Profiler} from './shared';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
getLViewFromDirectiveOrElementInstance,
METADATA_PROPERTY_NAME,
} from '../../directive-forest';
import {runOutsideAngular} from '../../utils';
import {runOutsideAngular} from '../../utils/general';
import {IdentityTracker, NodeArray} from '../identity-tracker';

import {getLifeCycleName, Profiler} from './shared';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import type {Signal, WritableSignal} from '@angular/core';
import {isSignal} from './utils';
import {isSignal} from './utils/general';

/** Represents a property access operation. */
interface PropertyAccess {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ ng_project(
exclude = ["*.spec.ts"],
),
deps = [
"//devtools/projects/ng-devtools-backend/src/lib:utils",
"//devtools/projects/ng-devtools-backend/src/lib/utils",
"//devtools/projects/protocol",
],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {unwrapSignal} from '../utils';
import {unwrapSignal} from '../utils/general';

// Intentionally do not include all the prototype (Except for getters and setters)
// because it contains inherited methods (hasOwnProperty, etc.). Also ignore symbols
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {PropType} from '../../../../protocol';

import {isSignal, safelyReadSignalValue} from '../utils';
import {isSignal, safelyReadSignalValue} from '../utils/general';

const commonTypes = {
boolean: PropType.Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {ContainerType, Descriptor, NestedProp, PropType} from '../../../../protocol';

import {isSignal, safelyReadSignalValue, unwrapSignal} from '../utils';
import {isSignal, safelyReadSignalValue, unwrapSignal} from '../utils/general';

import {getDescriptor, getKeys} from './object-utils';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {ContainerType, Descriptor, NestedProp, PropType} from '../../../../protocol';

import {isSignal, unwrapSignal} from '../utils';
import {isSignal, unwrapSignal} from '../utils/general';

import {getKeys} from './object-utils';
import {getPropType} from './prop-type';
Expand Down
34 changes: 34 additions & 0 deletions devtools/projects/ng-devtools-backend/src/lib/utils/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
load("//devtools/tools:defaults.bzl", "ng_project", "ts_test_library", "zoneless_web_test_suite")

package(default_visibility = ["//devtools:__subpackages__"])

ng_project(
name = "utils",
srcs = glob(
include = ["*.ts"],
exclude = ["*.spec.ts"],
),
deps = [
"//:node_modules/@angular/core",
"//devtools/projects/ng-devtools-backend/src/lib/ng-debug-api",
],
)

ts_test_library(
name = "test_lib",
srcs = [
"serialization.spec.ts",
"signal-graph-ref.spec.ts",
],
deps = [
":utils",
"//:node_modules/@angular/core",
],
)

zoneless_web_test_suite(
name = "test",
deps = [
":test_lib",
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {ngDebugApiIsSupported, ngDebugClient} from './ng-debug-api/ng-debug-api';
import {ngDebugApiIsSupported, ngDebugClient} from '../ng-debug-api/ng-debug-api';

export const runOutsideAngular = (f: () => void): void => {
const w = window as any;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {sanitizeObject} from './serialization-utils';
import {sanitizeObject} from './serialization';

describe('sanitizeObject', () => {
it('should not change valid object', () => {
Expand Down
Loading
Loading