Skip to content

Commit

Permalink
fix(devtools): check for all new DI debug APIs before trying to deter…
Browse files Browse the repository at this point in the history
…mine 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
  • Loading branch information
AleksanderBodurri authored and thePunderWoman committed Nov 10, 2023
1 parent 38aab6a commit 54a7b33
Showing 1 changed file with 48 additions and 45 deletions.
93 changes: 48 additions & 45 deletions devtools/projects/ng-devtools-backend/src/lib/component-tree.ts
Expand Up @@ -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;
Expand Down

0 comments on commit 54a7b33

Please sign in to comment.