From 54a7b33245a5fd935fb147a409bbab26b9f5ecc7 Mon Sep 17 00:00:00 2001 From: AleksanderBodurri Date: Fri, 10 Nov 2023 12:23:19 -0500 Subject: [PATCH] fix(devtools): check for all new DI debug APIs before trying to determine resolution path providers (#52791) Previously, some versions of Angular 16.1.x that had 3/4 of the new DI debug APIs would enter a code path that required them to have access to the 4th. Now DevTools checks for the existence of all 4 explicitly before going down this code path. PR Close #52791 --- .../src/lib/component-tree.ts | 93 ++++++++++--------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/devtools/projects/ng-devtools-backend/src/lib/component-tree.ts b/devtools/projects/ng-devtools-backend/src/lib/component-tree.ts index 53610e058b6f0..7dcd9167dbd4c 100644 --- a/devtools/projects/ng-devtools-backend/src/lib/component-tree.ts +++ b/devtools/projects/ng-devtools-backend/src/lib/component-tree.ts @@ -88,54 +88,57 @@ export function getDirectivesFromElement(element: HTMLElement): export const getLatestComponentState = (query: ComponentExplorerViewQuery, directiveForest?: ComponentTreeNode[]): - {directiveProperties: DirectivesProperties;}|undefined => { - // if a directive forest is passed in we don't have to build the forest again. - directiveForest = directiveForest ?? buildDirectiveForest(); - - const node = queryDirectiveForest(query.selectedElement, directiveForest); - if (!node) { - return; - } - - const directiveProperties: DirectivesProperties = {}; - - const injector = ngDebug().getInjector(node.nativeElement); - - const resolutionPathWithProviders = getInjectorResolutionPath(injector).map( - injector => ({injector, providers: getInjectorProviders(injector)})); - - - const populateResultSet = (dir: DirectiveInstanceType|ComponentInstanceType) => { - const {instance, name} = dir; - const metadata = getDirectiveMetadata(instance); - metadata.dependencies = getDependenciesForDirective( - injector, resolutionPathWithProviders, instance.constructor); - - if (query.propertyQuery.type === PropertyQueryTypes.All) { - directiveProperties[dir.name] = { - props: serializeDirectiveState(instance), - metadata, - }; - } - - if (query.propertyQuery.type === PropertyQueryTypes.Specified) { - directiveProperties[name] = { - props: deeplySerializeSelectedProperties( - instance, query.propertyQuery.properties[name] || []), - metadata, - }; - } - }; + {directiveProperties: DirectivesProperties;}| + undefined => { + // if a directive forest is passed in we don't have to build the forest again. + directiveForest = directiveForest ?? buildDirectiveForest(); + + const node = queryDirectiveForest(query.selectedElement, directiveForest); + if (!node) { + return; + } + + const directiveProperties: DirectivesProperties = {}; - node.directives.forEach((dir) => populateResultSet(dir)); - if (node.component) { - populateResultSet(node.component); - } + const injector = ngDebug().getInjector(node.nativeElement); + + let resolutionPathWithProviders: {injector: Injector; providers: ProviderRecord[];}[] = []; + if (hasDiDebugAPIs()) { + resolutionPathWithProviders = getInjectorResolutionPath(injector).map( + injector => ({injector, providers: getInjectorProviders(injector)})); + } + + const populateResultSet = (dir: DirectiveInstanceType|ComponentInstanceType) => { + const {instance, name} = dir; + const metadata = getDirectiveMetadata(instance); + metadata.dependencies = getDependenciesForDirective( + injector, resolutionPathWithProviders, instance.constructor); + + if (query.propertyQuery.type === PropertyQueryTypes.All) { + directiveProperties[dir.name] = { + props: serializeDirectiveState(instance), + metadata, + }; + } - return { - directiveProperties, + if (query.propertyQuery.type === PropertyQueryTypes.Specified) { + directiveProperties[name] = { + props: deeplySerializeSelectedProperties( + instance, query.propertyQuery.properties[name] || []), + metadata, }; - }; + } + }; + + node.directives.forEach((dir) => populateResultSet(dir)); + if (node.component) { + populateResultSet(node.component); + } + + return { + directiveProperties, + }; + }; export function serializeElementInjectorWithId(injector: Injector): SerializedInjector|null { let id: string;