angular/devtools/projects/ng-devtools-backend/src/lib/directive-forest/index.ts
AleksanderBodurri 5115050928 fix(devtools): DOM traversal bug (#62719)
Previously, Angular devtools would mistakenly traverse the same DOM elements multiple times while doing traversal for the component tree explorer. This error case would occur when more than 1 Angular application root component was present on the same page and in distinct DOM branches.

Some example cases that did work previously:

```html
<app-root>
...
</app-root>
```

```html
<app-root>
...
<app-root-2></app-root-2>
...
</app-root>
```

An example of where it would enter the irregular behaviour

```html
<app-root>
...
</app-root>
<app-root-2>
...
</app-root-2>
```

Now, we properly ignore duplicate DOM paths when looking for application and non-application root component to begin the Angular DevTools component discovery logic.

PR Close #62719
2025-08-18 15:43:09 +00:00

49 lines
1.3 KiB
TypeScript

/**
* @license
* Copyright Google LLC 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.dev/license
*/
import {ComponentTreeNode} from '../interfaces';
import {LTreeStrategy} from './ltree';
import {RTreeStrategy} from './render-tree';
export {
getDirectiveHostElement,
getLViewFromDirectiveOrElementInstance,
METADATA_PROPERTY_NAME,
} from './ltree';
// The order of the strategies matters. Lower indices have higher priority.
const rTreeStrategy = new RTreeStrategy();
const lTreeStrategy = new LTreeStrategy();
const strategies = [rTreeStrategy, lTreeStrategy];
const selectStrategy = (element: Element): RTreeStrategy | LTreeStrategy | null => {
for (const s of strategies) {
if (s.supports(element)) {
return s;
}
}
return null;
};
export const buildDirectiveForestWithStrategy = (elements: Element[]) => {
if (!elements || !elements.length) {
return [];
}
let i = 0;
return elements.flatMap((element) => {
// Different roots can have different Angular versions.
// Different versions depend on different component tree discovery strategies.
const strategy = selectStrategy(element);
if (!strategy) {
return [];
}
return strategy.build(element, i++);
});
};