Commit graph

3916 commits

Author SHA1 Message Date
arturovt
ca44055166 docs: clarify ngDoCheck invocation behavior with OnPush strategy
The previous documentation for `DoCheck` / `ngDoCheck` implied that the
default change-detector had run on the directive itself, which is
misleading. `ngDoCheck` is actually invoked when the *parent's*
change-detector checks the directive's input bindings — meaning it fires
even for `OnPush` components whose own change detection was skipped.

Updated three places in lifecycle_hooks.ts:
- Interface description: scopes "the check" to input bindings in the
  parent template and adds an explicit OnPush callout.
- "detects changes" clarified to "detects changes to the directive's
  input bindings".
- Method description: "after the default change-detector runs" →
  "after the default change-detector has checked the directive's input
  bindings in the parent template".

Fixes #48140
2026-05-20 11:12:06 -07:00
leonsenft
933608c07f fix(core): synchronize core sanitization schema with compiler
https://github.com/angular/angular/pull/68689 recently updated the compiler
schema which should be kept in sync with the core schema. Fix applied by
running `pnpm bazel run //packages/core:dom_security_schema`.
2026-05-19 18:02:43 -07:00
Kam
96ba942a91 refactor(compiler): sync compiler_facade_interface replica with main
The replica at packages/core/src/compiler/compiler_facade_interface.ts drifted from the main copy. The file header specifies syncing via `cp main replica`; running it fixes field-order drift and relocates `legacyOptionalChaining?: boolean;` back onto R3DeclareDirectiveFacade (it was incorrectly on R3DeclareComponentFacade in the replica).
2026-05-19 13:07:05 -07:00
Alan Agius
90494cd909
fix(compiler): strip namespaced SVG script elements during template compilation
Ensures that namespaced <script> elements (such as :svg:script) are correctly classified as PreparsedElementType.SCRIPT by the template preparser and stripped during compilation to prevent potential XSS vulnerabilities. Consequently, obsolete security schema mappings and runtime sanitization checks for <script> attributes have been removed since these elements are never present in compiled template outputs.
2026-05-19 13:06:00 -07:00
Alan Agius
61a97f22e8
fix(core): support prefix-insensitive DOM schema lookups and compile-time i18n attribute validation
Updates `DomElementSchemaRegistry` to strip `:svg:` and `:math:` namespace prefixes
from tag names before querying `SECURITY_SCHEMA` at compile-time. This allows SVG
and MathML attributes to correctly match their security contexts during compilation.
2026-05-19 13:00:32 -07:00
Kristiyan Kostadinov
9b7b9ba304 refactor(core): update internal utility
Updates the `getClosestComponentName` function to add support for a predicate function, based on internal requirements.
2026-05-18 13:23:46 -07:00
Alan Agius
0011664d1c fix(core): reject script element as a dynamic component host
To enhance application security and prevent accidental or malicious script execution, this change ensures that dynamically mounting a component via createComponent directly onto a <script> element throws a runtime error in development mode. SVG <script> elements are also rejected. The error message is designed to be fully tree-shakable under production builds where ngDevMode is disabled.
2026-05-18 13:16:31 -07:00
Kam
51b1db54ad refactor(core): remove deprecated UNSAFE_IFRAME_ATTRS alias
`UNSAFE_IFRAME_ATTRS` in the `RuntimeErrorCode` enum is a `@deprecated`
alias of `UNSAFE_ATTRIBUTE_BINDING` (same value -910) with no usages
anywhere. Drop it along with the paired
`tslint:disable-next-line:no-duplicate-enum-values` suppression.
`RuntimeErrorCode` is re-exported as `ɵRuntimeErrorCode`, so the
enum's value set is not a stability commitment.
2026-05-18 13:16:02 -07:00
Alan Agius
cef4a095a2
refactor(core): align namespaced attribute validation and security schema contexts
Refactors the element security schema lookups and runtime attribute validation to
consistently account for SVG and MathML namespaces. This improves the modularity
and accuracy of security context mapping during template compilation and runtime
constant evaluation, eliminating redundant or false-positive lifecycle checks.
2026-05-18 13:09:39 -07:00
Leon Senft
88b0e420cf
refactor(compiler): add support for importing foreign components
- Added the ForeignComponent interface in @angular/core.
- Added Component.foreignImports for importing ForeignComponents (supporting direct references and adapter function wrappers).
- Updated the compiler to handle ForeignComponent in template dependencies.
- Updated ngtsc to extract foreignImports from standalone components.
2026-05-18 13:08:59 -07:00
SkyZeroZx
00c284015c fix(core): makes resource URL sanitizer lookup case-insensitive
Ensures the resource map for URL sanitization is queried using lowercase tag and property names, improving robustness by handling case variations consistently.
2026-05-18 13:07:34 -07:00
Alex Rickabaugh
0a9b19454d refactor(core): add internal API for creating foreign views
Introduces `createForeignView`, an internal API for creating foreign view
directly inside `LContainer`s. Foreign views (`TViewType.Foreign`) are bounded
by head and tail comment nodes and can contain dynamic, non-Angular DOM nodes.

Updates Render3 node manipulation to support inserting, detaching, and moving
foreign views along with their internal content.
2026-05-15 10:33:52 -07:00
Kam
7557b339ea refactor(core): mark resource() overloads as @publicApi 22.0
#68253 graduated `resource`, `rxResource`, and `httpResource` to stable
by swapping `@experimental` for `@publicApi 22.0` across three files.
The two `resource()` overloads in `packages/core/src/resource/resource.ts`
were missed and still carried `@experimental 19.0`. The public-api
golden already lists both overloads as `// @public`, so this aligns the
source with what the rest of the codebase reflects.
2026-05-13 15:54:55 -07:00
AleksanderBodurri
ec63947dc6 refactor(core): patch special provider classes with __NG_ELEMENT_ID__
Some checks failed
CI (push) / lint (push) Waiting to run
CI (push) / devtools (push) Waiting to run
CI (push) / test (push) Waiting to run
CI (push) / integration-tests (push) Waiting to run
CI (push) / adev (push) Waiting to run
CI (push) / vscode-ng-language-service (push) Waiting to run
CI (push) / publish-snapshots (push) Waiting to run
CI (push) / zone-js (push) Waiting to run
CI (push) / adev-deploy (push) Blocked by required conditions
Update ADEV Cross Repo Docs / Update Cross Repo ADEV Docs (push) Waiting to run
Performance Tracking / list (push) Waiting to run
Performance Tracking / workflow (push) Blocked by required conditions
OpenSSF Scorecard / Scorecards analysis (push) Waiting to run
DevInfra / assistant_to_the_branch_manager (push) Has been cancelled
Calls a new patchSpecialProvider function to attach __NG_ELEMENT_ID__ and track special providers for debug tooling
2026-05-13 12:15:21 -07:00
Douglas Parker
38e26f0759 refactor(core): add "experimental" to WebMCP API names.
WebMCP is still an experimental standard and going through frequent changes in the Chrome implementation and the standards process. As a result, we should be clear about the support status of this API and its overall stability guarantees.
2026-05-11 12:43:06 -07:00
Kristiyan Kostadinov
c72ebcb1ad fix(core): allow service with factory on abstract classes
Some checks are pending
CI (push) / zone-js (push) Waiting to run
DevInfra / assistant_to_the_branch_manager (push) Waiting to run
CI (push) / lint (push) Waiting to run
CI (push) / devtools (push) Waiting to run
CI (push) / test (push) Waiting to run
CI (push) / integration-tests (push) Waiting to run
CI (push) / publish-snapshots (push) Waiting to run
CI (push) / adev (push) Waiting to run
CI (push) / vscode-ng-language-service (push) Waiting to run
CI (push) / adev-deploy (push) Blocked by required conditions
Update ADEV Cross Repo Docs / Update Cross Repo ADEV Docs (push) Waiting to run
Performance Tracking / list (push) Waiting to run
Performance Tracking / workflow (push) Blocked by required conditions
OpenSSF Scorecard / Scorecards analysis (push) Waiting to run
Fixes that setting a `@Service` with a `factory` on an abstract class was resulting in a compilation error.
2026-05-08 10:16:15 +02:00
Matthieu Riegler
a7dab601fa refactor(core): use the @Service decorator where possible.
A few bytes to win.
Added only on the services that don't rely on constructor DI.
2026-05-07 17:03:30 -06:00
Alan Agius
5b421c61cd
fix(core): disallow event attribute bindings in host bindings unconditionally
Moves the event attribute validation check outside of `ngDevMode` in the `elementAttributeInternal` instruction to ensure that bindings to event attributes like `on*` are always blocked at runtime.
2026-05-07 16:19:22 -06:00
Douglas Parker
3b0ae5fef0 feat(core): add provideWebMcpTools
Some checks are pending
DevInfra / assistant_to_the_branch_manager (push) Waiting to run
This is an ergonomic wrapper around `declareWebMcpTool`, allowing a user to define multiple tools directly on an injector's providers, rather than needing to find an injection context.

Example:

```typescript
import {bootstrapApplication, provideWebMcpTools} from '@angular/core';

await bootstrapApplication(RootComp, {
  providers: [
    provideWebMcpTools([
      {
        name: 'hello',
        description: 'Says hello',
        inputSchema: {type: 'object', properties: {}},
        execute: async () => ({content: [{type: 'text', text: 'Hello, World!'}]});
      },
    ]),
  ],
});
```

The `execute` function is invoked in the injection context of the `Injector` it is provided to, meaning you can easily `inject` dependencies and invoke them.

This also works particularly well with route `providers` and `withExperimentalAutoCleanupInjectors`, registering the tools when the router is navigated to and then automatically unregistering them when navigating away. Note that `withExperimentalAutoCleanupInjectors` is required for unregistration to work.

```typescript
import {provideWebMcpTools} from '@angular/core';
import {provideRouter} from '@angular/router';

provideRouter(
  [
    {
      path: '',
      component: Home,
      providers: [
        provideWebMcpTools([
          {
            name: 'hello',
            description: 'Says hello',
            inputSchema: {type: 'object', properties: {}},
            execute: async () => ({content: [{type: 'text', text: 'Hello, World!'}]}),
          },
        ]),
      ],
    },
  ],
  withExperimentalAutoCleanupInjectors(),
);
```
2026-05-06 14:13:20 -07:00
Douglas Parker
77ec83782f refactor(core): run declareWebMcpTool callback in an injection context
This uses the injection context the tool is registered in for the `execute` callback and makes it a little more ergonomic to inject and use services in this context.
2026-05-06 14:13:20 -07:00
Douglas Parker
ef1810197b feat(core): export experimental declareWebMcpTool support
This exports `declareWebMcpTool`, a mechanism for registering WebMCP tools and tying them to Angular's `Injector` lifecycle. This function immediately registers the given tool and automatically unregisters it once the associated `Injector` is destroyed.

This exports the function and all transitively reachable types *except* for JSON Schema types as there are quite a lot and we don't want to couple to this particular implementation will likely be obsoleted by built-in types as the standard develops. If users want to leverage those, they should add their own dependency on `@mcp-b/webmcp-types`.
2026-05-06 14:13:20 -07:00
Douglas Parker
b2c0c91f8f refactor(core): implement declareWebMcpTool
This is a relatively light wrapper around `navigator.modelContext.registerTool` which ties tool registration to the lifecycle of an `Injector`. When the `Injector` is destroyed, the tool is automatically unregistered. This makes it easier to create WebMCP tools without having to worry about managing unregistration.

I went a little off-spec by providing the `AbortSignal` to the `execute` function. I suspect something like this will be added eventually and there are some early discussions of that, but AFAICT, this behavior is not defined yet so I'm making something up instead so the `execute` function can observe a cancellation based on the `Injector` being destroyed.

This uses `@mcp-b/webmcp-polyfill` for testing, as it provides a small `modelContextTesting` utility for listing and invoking WebMCP tools. Unfortunately it is slightly out of date of the current Chrome spec (it requires `modelContext.unregisterTool` to be called, whereas the spec recently removed this option and expects you to provide an `AbortSignal` to `registerTool`). My slightly hacky solution for the moment is to both trigger the `AbortSignal` and also call `unregisterTool` safely. In production, only the `AbortSignal` happens, but in testing the `unregisterTool` code path is used. Hopefully this will get smoothed out as the spec matures and `@mcp-b/webmcp-polyfill` updates over time.
2026-05-06 14:13:20 -07:00
Matthieu Riegler
5a7c1e62dc
feat(core): add ability to cache resources for SSR
This commit adds a `transferCacheKey` option to enable easy caching for `resource`/ `rxResource`.
2026-05-06 09:57:49 -07:00
Jaime Burgos
f81fa6e691
docs: add documentation for lazy loading services and update navigation 2026-05-05 15:57:36 -07:00
Matthieu Riegler
d7b475122a refactor(core): promote resource & rxResource to stable
The time has come.

Note: #67382 introduced a breaking change where you could notice some sublte timing change on how `value` is set when using `rxResource` or a `stream` on a `resource`
2026-05-05 15:55:25 -07:00
Kristiyan Kostadinov
6339d264eb fix(core): i18n flags leaking on errors
The i18n sub-system has the `changeMask` and `changeMaskCounter` flags which are set by i18n-related instructions and reset once the state is applied. The problem is that if something throws within the application logic, the flags would never be reset. This is currently causing flakes in our CI runs.

These changes resolve the issue by adding a try/finally around the flags.
2026-05-05 09:30:53 -07:00
Kristiyan Kostadinov
49748b5c79 fix(core): enforce return type for service factory
Updates the `factory` signature in `@Service` to enforce the type of the returned value.
2026-05-05 09:30:29 -07:00
Alex Rickabaugh
0ea50ffe5a fix(forms): ensure debounced async validators produce pending status during debounce
When using a debounced async validator, the pending status from the internal
debounced resource was not flowing through to the resource created by the
factory. Replicate the 'chain' logic using the new privately exported ɵchain
function to propagate the loading status correctly.

Fixes #68105
2026-05-04 13:03:07 -07:00
SkyZeroZx
11721509b0 refactor(core): Makes @defer(hydrate ...) runtime tree-shakable
This commit updates `@defer` logic related to incremental hydration to be tree-shakable.

If hydrate triggers are used in a `@defer` block, the compiler emits a single top-level call to `ɵɵenableIncrementalHydrationRuntime`, placed once per create block before the first `ɵɵdefer` that requires it.

As a result, the incremental hydration runtime is only included in the bundle when hydrate is explicitly used.
2026-05-01 15:54:55 -07:00
cexbrayat
1ab654cf28 fix(core): allow explicit read generic with signal input transforms
Using explicit single generic arguments with transforms (for example, input<boolean>(false, {transform: booleanAttribute})) previously failed overload resolution.

Before this fix, type-checking produced:
````
✘ [ERROR] TS2769: No overload matches this call.
  Overload 1 of 5, '(initialValue: boolean, opts?: InputOptionsWithoutTransform<boolean> | undefined): InputSignal<boolean>', gave the following error.
    Type '(value: unknown) => boolean' is not assignable to type 'undefined'.
  Overload 2 of 5, '(initialValue: undefined, opts: InputOptionsWithoutTransform<boolean>): InputSignal<boolean | undefined>', gave the following error.
    Argument of type 'true' is not assignable to parameter of type 'undefined'. [plugin angular-compiler]
```

This change adds specialized overloads for explicit read generics.
2026-05-01 15:53:56 -07:00
Kristiyan Kostadinov
7aad302c3e fix(core): mark service decorator as stable
Marks `@Service` as stable for v22.
2026-04-30 16:08:27 -07:00
Matthieu Riegler
bc637a304f refactor(core): add support for default exports to injectAsync
ex:
```
await injectAsync(() => import('./test_service'))
```

We'll be reusing the features that were already used by the router to support components lazy-loading.
2026-04-30 15:53:07 -07:00
Alan Agius
9d7a609458 fix(core): validate security-sensitive attributes in i18n bindings
Ensures that security-sensitive attributes (e.g., sandbox, allow) are correctly validated when applied through i18n-* dynamic attribute bindings, preventing potential policy bypasses.

Closes #68418
2026-04-30 15:47:12 -07:00
Sonu Kapoor
4c9afb68a3 fix(core): respect ngSkipHydration on components with projectable nodes in LContainers
When a component is created dynamically via ViewContainerRef.createComponent
and receives projectable nodes (e.g. raw DOM nodes or embedded view root nodes),
applying ngSkipHydration to its host element did not prevent NG0503 from being
thrown during SSR serialization.

The root cause is an asymmetry in the serialization pipeline. For inline child
components, serializeLView already guards the annotateHostElementForHydration
call with a ngSkipHydration attribute check, so the component's lView is never
serialized when hydration is opted out. For components hosted inside an
LContainer (created via ViewContainerRef.createComponent), serializeLContainer
called serializeLView unconditionally — bypassing that guard entirely. When
serializeLView then encountered a projection slot backed by a raw DOM node
array, it threw NG0503 regardless of the ngSkipHydration flag.

The fix adds the same guard inside serializeLContainer before calling
serializeLView: if the child lView belongs to a component whose host element
carries ngSkipHydration, the lView serialization is skipped. This matches the
existing behavior for inline components and allows the documented workaround to
actually work for dynamically created ones.

Fixes #67928
2026-04-29 16:09:14 -07:00
Matthieu Riegler
37ec63e745 refactor(compiler): introduce default constant for legacyOptionalChaining flag
This will help patch the value in G3 to help land this change.
2026-04-29 10:01:13 -07:00
Matthieu Riegler
2896c93cc1
feat(compiler): Angular expressions with optional chaining returns undefined
To mitigate this breaking change,  this behavior can be disabled by wrapping expressions with the `$null` magic function.
: `$null(foo?.bar?.baz)`
2026-04-28 15:26:53 -07:00
Matthieu Riegler
8c11816490 fix(core): fix ordering of view queries metadata in JIT mode
AOT was generating an array that was ordered as signal queries first, then the decorator queries.
Aligning JIT with AOT fixes the issue illustrated by the test.

fixes #68404
2026-04-28 12:03:41 -07:00
Matthieu Riegler
444b024d49 feat(core): Add a injectAsync helper function
The commit introduces a new function to assist users who want to lazy load services and use the DI system to create them.

Example:

```ts
import {injectAsync} from 'angular/core';

class MyCmp {
  someSvc = injectAsync(() => import('..'));

  async onClick() {
    (await this.someSvc()).handleClick();
  }
}
 ```
2026-04-28 12:01:27 -07:00
Sonu Kapoor
3583c01bf9 fix(core): guard against non-object events and avoid listener wrapper identity mismatch
Two issues caused browser test failures after the event replay fix:

1. `markEventHandledForElement` used the event object as a WeakMap key, but
   `DebugElement.triggerEventHandler` can pass null or primitive values as the
   event argument. Added an early return for non-object values.

2. Registering a separate `domListener` closure with `renderer.listen` instead of
   `wrappedListener` caused `DebugElement.triggerEventHandler` to invoke the
   handler twice: once via `this.listeners` (which holds `wrappedListener`) and
   once via Zone.js's `eventListeners` (which holds the unwrapped `domListener`).
   The existing dedup logic in `triggerEventHandler` checks if the unwrapped
   Zone.js listener is already in `invokedListeners`, but with two different
   function objects that check always fails.

   Replaced the `domListener` wrapper with a property (`__ngNativeEl__`) stored
   directly on `wrappedListener`. `wrapListenerIn_markDirtyAndPreventDefault` reads
   this property and calls `markEventHandledForElement` when the listener fires,
   while `renderer.listen` receives the same `wrappedListener` function that
   Angular stores in `lCleanup`, preserving the dedup invariant.
2026-04-27 17:07:36 -07:00
Sonu Kapoor
d5fd51e956 fix(core): prevent event replay double-invocation when element hydrates before app stability
When `withEventReplay()` is enabled and a component hydrates before the
application becomes stable (e.g. while a pending HTTP request is in
flight), a user interaction on the hydrated element triggers both the
real DOM listener registered by Angular and the jsaction replay path.
This causes the event handler to be invoked twice.

The root cause is that `listenToDomEvent` registers the same
`wrappedListener` both as a stashed jsaction handler (via
`stashEventListenerImpl`) and as a native DOM listener (via
`renderer.listen`). When the user interacts after hydration but before
app stability, jsaction queues the event because no dispatcher is
registered yet. Once the app stabilises and `initEventReplay` runs,
jsaction replays the queued event through `invokeListeners`, which
calls the stashed handler a second time.

The fix tracks dispatched `(event, element)` pairs in a
`WeakMap<Event, WeakSet<Element>>`. The native DOM listener wrapper
records each pair via `markEventHandledForElement`, and `invokeListeners`
skips replay for any pair already present. Keying by element (rather
than event alone) preserves incremental hydration behaviour, where
jsaction legitimately replays the same event on a different element
(the deferred block content) from the one that originally triggered
hydration.

Fixes #67328
2026-04-27 17:07:36 -07:00
Matthieu Riegler
4ad3a1fe37 refactor(core): Don't throw when there are not async metadata
In the context of AOT tests, component with defer blocks no longer throw on instanciation if the component is not overridden (with `overrideComponent`)

Prior to this change, all components with a `@defer` block would throw if `compileComponents` was not invoked.

In none-JIT apps, this change makes `compileComponents()` uneccesary.
2026-04-27 17:04:09 -07:00
Kristiyan Kostadinov
8f3d0b9d97 feat(core): introduce @Service decorator
These changes introduce the new `@Service` decorator which is a more ergonomic alternative to `@Injectable`. The reason we're adding a new decorator is that `@Injectable` has been around since the beginning of Angular and it has a lot of baggage that adds unnecessary overhead for users that generally want to define a singleton service, available in their entire app. The key differences between `@Service` and `@Injectable` are:
1. `@Service` is `providedIn: 'root'` by default. You can opt into providing the service yourself by setting `autoProvided: false` on it.
2. `@Service` doesn't allow constructor-based injection, only the `inject` function.
3. `@Service` doesn't support the complex type signature of `@Injectable` (`useClass`, `useValue` etc.). Instead it supports a single `factory` function.

Example:

```ts
import {Service} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {AuthService} from './auth';

@Service()
export class PostService {
  private readonly httpClient = inject(HttpClient);
  private readonly authService = inject(AuthService);

  getUserPosts() {
    return this.httpClient.get('/api/posts/' + this.authService.userId);
  }
}
```
2026-04-22 11:01:01 -07:00
Andrew Scott
9f479ae964 feat(core): Update Testability to use PendingTasks for stability indicator
Since angular@12181b9, zone stability
contributes to the PendingTasks. There is now a single source of truth for application stability
tracked in PendingTasks. This change makes protractor's whenStable compatible with zoneless.
The `Router` and `HttpClient` also contribute to stability using the
`PendingTasks` injectable. There will likely be more updates in the
future to have more features contribute to stableness in a zoneless
compatible way.

This update uses PendingTasks for stability by default when ZoneJS is not present or
can be enabled with an option when ZoneJS is present (but otherwise ignored with ZoneJS).

fixes #68180
2026-04-20 13:08:43 -07:00
SkyZeroZx
3ae40e6685 refactor(core): complete removal of deprecated createNgModuleRef alias
Finalize the cleanup by removing the remaining `createNgModuleRef` alias.
2026-04-20 12:09:45 -07:00
aparziale
d771a65ac0 refactor: Improve hydration mismatch errors for third-party scripts
Improves error messages shown during hydration mismatches to better
surface cases where third-party scripts or browser extensions have
modified the DOM outside of Angular's control.

Fixed #59224
2026-04-17 14:33:10 -07:00
Matthieu Riegler
4e331062e8 feat(core): allow synchronous values for stream Resources
In order for resources to allow caching in SSR context (eg in the TransferState), resource need to be able to set their value synchronously.

If the resource value is not set synchronously, the resource will be in in a "loading" state which is responsible for destroying the server-hydrated resolved DOM.
2026-04-16 00:13:04 +03:00
SkyZeroZx
281a2dba78 docs: Add guide for debounced signals
Add guide for `debounced` signals.
Also add `@see` tags
2026-04-15 20:04:10 +03:00
Matthieu Riegler
a46c64758e docs: fix bootstraping link
fixes #68212
2026-04-15 19:25:35 +03:00
Doug Parker
75f2cb8f56 feat(core): implement Angular DI graph in-page AI tool
This creates a new `angular:di-graph` in-page tool which returns the entire dependency injection graph for the application.

We use the following rough algorithm for discovering all element injectors:
1. Find all root `LView` objects by querying for `[ng-version]`.
2. Walk all the transitive `LView` descendants of the roots.
3. Filter these `LView` objects to just directives.
4. Find the injector for a given directive and walk up its ancestors to find all element injectors.

Discovering environment injectors works mostly the same way, just following the environment injector graph instead.

This approach has a few known limitations which are out of scope for the moment:
1. Any given component typically has both an element injector *and* an environment injector. The relationship of "component -> environment injector" is not expressed in the result as of now, meaning the AI doesn't really have any insight into _which_ environment injector is being used for a particular component, though the injector will be one of the returned values.
2. The implementation does not support MFE use cases of multiple applications on the page at the same time.
3. The performance is not ideal, as we walk `LView` descendants twice and walk up the injector tree for every directive, repeatedly covering the same scope (ideally we'd just walk up every *leaf* directive, which would cover the same result for less effort). However for a debug tool, this is likely fine for now and we can optimize later if/when it becomes necessary.

I did consider reusing more of the existing implementation in `global_utils` which exists to support Angular DevTools (we are already using some of it), however the existing support in `@angular/core` is actually fairly limited, returning very primitive data structures and relying on Angular DevTools to do the heavier lifting of collapsing the code into a usable graph representation. There's a potential path in the future to converge these implementations and potentially have `global_utils` use some of this code instead, but I will leave that for a future cleanup effort.
2026-04-14 18:35:51 +03:00
Doug Parker
de03e83980 refactor(core): add walkLViewDirectives
This walks all transitive descendant directives via the `LView` structure of the given input. This is a generic utility, but useful for finding all components in a tree to look for their associated `Injector` objects.

One known limitation is that this does not cover child components of i18n messages as that was more complicated than I wanted to get into right now.
2026-04-14 18:35:51 +03:00