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(),
);
```
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.
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`.
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.
This copies WebMCP types into `@angular/core` and redistributes them. Ideally this would just be a regular dependency, but we need to do this vendoring for API extractor to properly process the types, since they will inform `@angular/core` public API.
One downside of this approach is that the dependency is not visible in Intellisense, breaking type inference.
This commit removes runtime console warnings and uses TypeScript overloads with JSDoc @deprecated annotations to handle backward compatibility for conditional rules.
This commit updates the signal forms API to use a consistent 'when' parameter for conditional rules and validators, replacing direct function arguments.
Replaced `@experimental` tags with `@publicApi 22.0` across all Signal Forms APIs under `packages/forms/signals` to mark them as ready for general use in v22.
TAG=agy
CONV=0af6c644-225a-4212-a49a-5843d17ec638
* Test that `minDate`/`maxDate` binds to `min`/`max` on date and time inputs
* Test that `min`/`max` attribute can be set directly on date and time inputs
* Relax type checker to allow `min`/`max` bindings on date and time inputs
PR Close#68001
- Added `minDate()` and `maxDate()` for validating constraints on `Date` inputs.
- `ReadonlyFieldState.min` and `.max` now return
`Signal<NonNullable<TValue>`. This ensures that `min` and `max` inputs
on custom controls can accept a reliable type (matching their value
type).
- Made the `TWrite` type parameter of `MetadataKey` contravariant to
properly indicate that it's writable.
- Added `LimitKey` as a convenience type for defining validation limit
metadata (e.g. `MAX_NUMBER`, `MIN_DATE`).
- Added `LimitSelectionKey` which can be used to bind a `LimitKey` with
value-specific aggregation logic, to a generic metadata key (e.g. use
`MAX_NUMBER` to aggregate numbers for `MAX`).
PR Close#68001
The `min` and `max` validation rules previously handled `string` values
to accommodate numbers bound to text inputs. However, this is no longer
necessary as the control binding itself handles the conversion.
This change removes string support from these rules, simplifying the
types to `number | null`. The validation logic has been updated to use
concrete checks (`value === null || Number.isNaN(value)`) to ensure safe
TypeScript narrowing.
Associated tests have been updated to:
- Remove string-specific validation checks.
- Add coverage for text input bindings.
- Add coverage for empty input handling (standard behavior where empty
sets model to null and skips validation).
BREAKING CHANGE: `min` and `max` validation rules no longer support
string values. Bound values must be numbers or null.
PR Close#68001
Introduce a highly decoupled FVC and CVA custom control reset mechanism, and implement the framework-wide automatic `transformedValue` and native controls clearing bridge for both new Signal Forms and legacy forms (Template-driven and Reactive).
1. Custom Control Reset Propagation (Bug #2):
- Establish agnostic custom control resetting via `FormFieldBindingOptions.reset` in `FormField`.
- Ensure that `FieldNode.reset()` unconditionally triggers `writeValue` updates on CVA custom controls.
- Protect against duplicate writes during subsequent change detection updates in `control_cva.ts` by verifying and tracking previous written values in the local bindings cache.
2. Unified Framework-wide FormControl Integration:
- Introduce a monorepo-wide private InjectionToken `ɵFORM_CONTROL_INTEGRATION` and `ɵFormControlIntegration` interface to act as the single, decoupled bridge for hooking up FVC parse errors and receiving control resets across both Signal and legacy forms architectures.
- Simplify Signal Forms: make `FormField` implements `ɵFormControlIntegration` directly, removing the intermediate context object and reducing DI boilerplate down to a clean `useExisting: FormField` provider. Triggers the `onReset` callback directly inside `FormField.reset()`.
- Upgrade Legacy Forms: `NG_CONTROL_INTEGRATION_PROVIDER` provides the renamed token. `NgControl` handles the event subscription internally (`set onReset(callback)`) to recursively listen to `control.events` (`FormResetEvent`) lazily only when assigned, resolving all `FormControl` swapping timing and lifecycle cleanup races automatically.
3. Automatic `transformedValue` and Native Controls Utility Clearing:
- Make `Parser.reset()` method required in the interface for a cleaner and non-defensive execution.
- Wire `transformedValue` into the new integration token `ɵFORM_CONTROL_INTEGRATION` to clear validation parsing states on resets.
- Lazily resets the UI-facing `rawValue` linked signal utilizing the original native `linkedSignal.set` callback (`originalSet`), correctly bypassing the UI-to-model parser loopback and preventing redundant model writes during `reset()`.
- Wire up Native Controls (`control_native.ts\Device`): Hook `parent.onReset` inside native element creation to automatically trigger the native `parser.reset()` and force DOM writes (`setNativeControlValue`) back down to the DOM input value during resets, ensuring native elements with pending parsing validation errors are successfully cleared and synced on form resets.
TAG=agy
CONV=8b4cee1e-2117-42a4-b242-c8ec7bf01752
Synchronize `controlValue` with the model `value` following `reset()`. This
ensures the UI will reflect the form model in cases where a control had a
pending change–delayed by debouncing–at the time it was reset.
Updates the supported Node.js engine versions to include Node.js 26.
This allows running the CLI on Node.js 26.0.0 and above while continuing to support active LTS versions.
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`
- Short-circuit `FieldNode.debounceSync()` if the node is orphaned right
before calling `this.sync()`, preventing unhandled promise rejections
on dead state reads.
- Include `this.node.structure.isOrphaned()` in `shouldSkipValidation`
computed signal in `ValidationState`. This safely shields the entire
validation layer (sync and async errors) from executing on dead nodes during
in-flight async validator resolutions.
- Append robust reproduction specs to `orphan_repro.spec.ts` for both the
`debounceSync` and `validateAsync` async race conditions. Include an intentional
promise resolution workaround for an experimental Angular `core/resource`
`PendingTasks` leak deadlock bug uncovered during testing.
TAG=agy
CONV=054e0185-f5f0-40e3-9c9b-413309f36cf6
Explain the race condition: when an item is deleted from a model array, its
DOM element is removed during change detection, which fires a `blur` event
synchronously. The `blur` handler tries to mark the field as touched,
navigating up to `keyInParent` which throws because the item is already gone
from the array in signals state.
Fix by introducing an `isOrphaned` check that short-circuits `markAsTouched`
early, backed by a reactivity-insulated `childrenMap` poll to avoid double
scans and prevent unhandled exceptions.
TAG=agy
CONV=054e0185-f5f0-40e3-9c9b-413309f36cf6
Fixes#66711
Co-Authored-By: Matthieu Riegler <kyro38@gmail.com>
"AngularJS" is the official product name for the v1.x line and is
written as a single word. A few places in the docs and package
READMEs used "Angular JS" with a space. This normalizes those
references to the canonical spelling.
Prohibit concurrent submits in signal forms to prevent duplicate actions and side effects when a submission is already in progress.
If `submit()` is called while a prior submit is in progress for the same field or any of its parents, it returns `false` immediately without running the action again.
This commit also updates the documentation in `form-submission.md` to reflect this behavior.
Fixes#68317
On phones, opening the primary-nav drawer left the page behind it scrollable, and the secondary drawer's mask had no explicit height so long submenus got clipped above the page content. Lock the page with overflow: clip on :host:has(.adev-nav-primary--open) for phone-only (preserves the primary nav's sticky context), give the secondary mask height: 100dvh on tablet-landscape-down so it fills the visible viewport, and align the nav-list :host height to 100dvh too so its inner scroll matches.
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.
This migration ensure that existing code is wrapped by the `$safeNavigationMigration` magic function when necessary to maintain the pre-exisiting behavior of exisiting optional chaining expressions.
Avoid deep write path traversal and triggering source signal updates
when calling `deepSignal.set(value)` with a new value that is
identical to the current value (`Object.is`).
This shortcuts the entire write path and unnecessary array/object
copying early on. This approach relies on the guarantee that `source`'s
value is non-nullable in the context where `deepSignal` is created and
used.
TAG=agy
CONV=9e5bd277-0d0a-466c-be36-5e3a8e6910be
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
Introduce a new configuration option `unmatchedInputBehavior` to the `componentInputBinding` feature. This option allows users to configure the behavior when a component input is not matched by any key in the router data.
The available values are:
- 'alwaysUndefined': (Default) Always binds undefined to unmatched inputs.
- 'undefinedIfStale': Binds undefined only if the input was previously available in the router data for the active route in the outlet.
This feature addresses concerns raised in #63835 and #52946 regarding the retention of default values for inputs that were never targeted by the router, while still ensuring that stale data is cleared when a parameter is removed.
In order to raise an error on upload progress on the `FetchBackend`, we split `reportProgress` into 2 respective properties.
DEPRECATED: The `reportProgress` option is deprecated please use `reportUploadProgress` & `reportDownloadProgress` instead.
Add required, pattern, min, max, minLength and maxLength to LINK_EXEMPT
so FieldState property names stop auto-linking to the validator
functions of the same name.
There was not a test demonstrating local compilation with the
'bootstrap' param on NgModule. This test adds one, among other NgModule
fields in one. These other fields are broadly covered already, but this
rolls them into one test exercising all fields.
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.
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.
Update the MCP documentation to reflect the removal of find_examples and modernize tools from the server. Add a new file documenting automatic migrations as the preferred alternative.
ex:
```
await injectAsync(() => import('./test_service'))
```
We'll be reusing the features that were already used by the router to support components lazy-loading.
To support `fakeAsync` usage while using `vitest` as a test runner, Zone.js
now provides patching when using the `zone.js/testing` package import.
This patching is similar to that of the existing jasmine, mocha, and jest
functionality.
PR Close#68395
Add `shallowArrayEquals` to computed signals returning arrays of errors or reasons in Signal Forms. This prevents unnecessary downstream invalidations when the content of the arrays remains unchanged.
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
This change adds a new that allows environments that cannot support inline TCBs (such as the language service or source-to-source transforms where TS compilation and emit are downstream) to still perform template type checking.
Instead of inlining the TCB into the original source file when non-exported symbols are referenced, we now copy the file content to the .ngtypecheck.ts shim file and generate the external TCB there, if requested by the inlining mode. This preserves the local scope of the original file while keeping the original file unmodified.
External links in the update guide opened inconsistently. Override
marked's link renderer to add `target="_blank" rel="noopener noreferrer"`
to external anchors and apply the `external-link-with-icon` mixin for
the icon. Convert raw HTML and bare URLs in recommendations.ts to
markdown so they all flow through the renderer.
The GHSA-x288-3778-4hhx patch requires `allowedHosts` on
`CommonEngine` or SSR silently falls back to CSR. Add a checklist
item to the v21 update guide.
all necessary info is already available in the tcb meta objects. environments without full ts program no longer need a reflectionhost for tcb generation
- `CombinedControl.value` and `InteropNgControl.value` getter now return
`unknown` instead of `any`, matching the actual `ReadonlyFieldState<unknown>`
return type of `controlValue()`.
- Remove redundant `as any` cast in `cvaControlCreate`: `parent` is typed as
`FormField<unknown>`, so `state().controlValue` is `WritableSignal<unknown>`
and accepts `unknown` directly.
becomes input + linkedSignal
When a component has both a model() property and a conflicting output property (e.g., foo model + fooChange output), this migration converts the model() to an input() + linkedSignal() pattern to avoid naming conflicts.
Fixes#67340
Focus the target element using `focus({preventScroll: true})` after scrolling, so the browser doesn’t adjust the scroll position when applying focus.
Fixes#65938
Add the NG01902 (Orphan field in signal forms) documentation page
to the Error Encyclopedia and change the ORPHAN_FIELD_PROPERTY
error code to -1902 so Angular's RuntimeError automatically appends
a link to angular.dev/errors/NG01902 in the thrown error message.
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
The example already uses the signal-based input() but still declares
items with the @ContentChildren decorator. Convert to the signal-based
contentChildren() query for consistency.
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();
}
}
```
Removes the `checkTwoWayBoundEvents` flag since the code it generates is quite breaking and we never got the chance to enable it. Also it caused our tests to misrepresent how the compiler behaves for actual users.
Currently, the exec() utility uses childProcess.spawn() with shell: true. This commit changes the spawn option to shell: false to prevent OS command injection vulnerabilities and quotes the benchmark target in the github action.
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.
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
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.
Updates the Playground card copy and adds a `titleInline` attribute on
<docs-card> so the icon and title sit on the same row. Existing cards
are unaffected.
Update the security guide to explain how to configure `trustProxyHeaders` when initializing the application engine. Also, update the validation rules for `X-Forwarded-Prefix` to reflect that it must start with `/` and contain only alphanumeric characters, hyphens, and underscores.
Client-Only Wiz doesn't have the concept of a directive. Once the new ng.getComponentForest function is implemented, Client-Only Wiz cowilluld provide `ComponentTreeNode`s without a `directives`` property. This change supports that case by making the `directives` property optional.
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);
}
}
```
This fixes an issue where when removing NgClass from the imports array of a component, an extra trailing comma would be left behind if it was the last element in that component`.
This fixes an issue where when removing NgClass from the imports array of a component, an extra trailing comma would be left behind if it was the last element in that component`.
Fixed an issue where back/forward (`popstate`) navigation attempted to match the displayed `browserUrl` instead of the internal route, which could result in `NG04002: Cannot match any routes`.
Fixes#67549
changeTemplate() was calling reset() on the sandbox before init()
completed, causing a TypeError when spawning processes on an
uninitialized WebContainer. Add isSandboxReady signal to skip
reset until the sandbox is fully initialized.
Adds a single-expansion accordion playground template under
adev/src/content/tutorials/playground/5-aria-accordion demonstrating the
Angular Aria primitives. Wires @angular/aria into the editor TypingsLoader
so imports resolve in the sandbox.
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
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
Set the default value of paramsInheritanceStrategy to 'always'. This change ensures that route parameters are inherited from parent routes by default, which is the behavior most users expect. It simplifies routing configuration for the majority of use cases.
This change aligns Angular with other popular routing systems where child routes automatically have access to parent parameters:
- React Router: useParams() includes parent params.
- Vue Router: $route.params includes parent params.
- Next.js: params are passed to nested layouts and pages.
- TanStack Router: useParams() includes parent params with full type safety.
BREAKING CHANGE: paramsInheritanceStrategy now defaults to 'always'
The default value of paramsInheritanceStrategy has been changed from 'emptyOnly' to 'always'. This means that route parameters are inherited from all parent routes by default. To restore the previous behavior, set paramsInheritanceStrategy to 'emptyOnly' in your router configuration.
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.
Explain two non-obvious behaviors of the commands array in router.navigate():
- Multiple '..' segments must be combined in the first array element
(e.g. ['../../foo']), not spread across separate elements
(e.g. ['..', '..', 'foo']), because the router only parses '..'
from the first command string. Subsequent elements are treated as
literal path segments, causing a navigation error.
- A leading '/' in the first command makes navigation absolute and
silently ignores the relativeTo option entirely.
Closes#65657
Moves the logic for generating type check blocks into the compiler since it isn't coupled to TypeScript anymore.
Note: the tests haven't been moved over, because they depend on the environment that's currently in `compiler-cli` and it still has some dependencies on TypeScript.
These changes are essentially the same as those introduced in
angular#45273, but they include backward compatibility
for applications that explicitly rely on the order in which microtasks are drained.
This is critically important for our code and other third-party code, which is
beyond our control, to work properly. If a microtask is scheduled within an event
listener to be executed "later", it should indeed be executed later and not synchronously,
as this would break the expected flow of code execution.
The simple code that reproduces the behavior that exists now:
```ts
Zone.current.fork({name: 'child'}).run(() => {
const div = document.createElement('div');
div.style.height = '200px';
div.style.width = '200px';
div.style.backgroundColor = 'red';
document.body.appendChild(div);
function listener() {
Promise.resolve().then(() => {
div.style.height = '400px';
});
}
div.addEventListener('fakeEvent', listener);
div.dispatchEvent(new Event('fakeEvent'));
console.log(div.getBoundingClientRect().height); // 400
});
```
The code above logs 400 as the height, but it should actually log 200 because the
height is updated in a microtask within the event listener.
When using Angular with microfrontend applications, especially when other apps might be
using React, zone.js can disrupt the classical order of operations. For example, when using a
`react-component/trigger`, it schedules a microtask within an event listener using
`Promise.resolve().then(...)` to determine whether the event needs to be re-dispatched.
The event is re-dispatched when the layout has changed, which is why a microtask is used.
With this change, we introduce a global configuration flag,
`__zone_symbol__enable_native_microtask_draining`, to allow consumers to enable
microtask draining within a browser microtask.
This flag is necessary to prevent any breaking changes resulting from this modification.
The previous attempt to address this issue caused a significant number of failures in g3.
Therefore, we are hiding that fix behind the configuration flag.
Closes angular#44446
Closes angular#55590
Closes angular#51328
The `parseUrl` function in `ServerPlatformLocation` uses `new URL(urlStr, origin)` to parse incoming request URLs during SSR. Per the WHATWG URL specification, protocol-relative URLs (`//evil.com`) and backslash-prefixed URLs (`/\evil.com`) can override the hostname component of the base URL.
This vulnerability typically manifests in SSR setups (e.g., Express) where `req.url` is passed directly to `renderApplication` or `renderModule`:
```typescript
// Example usage in an Express server handling: http://localhost:4000//evil.com
app.get('*', async (req, res) => {
const html = await renderApplication(bootstrap, {
document: template,
url: req.url, // req.url is "//evil.com"
});
res.send(html);
});
```
Priori to this change, the InMemory API threw when request was emited outside an injection context and that request hit the passThru.
This commit fixes this.
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.
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.
- Injected `NG_VALIDATORS` into `FormField` and exposed it via an internal getter.
- Created a `computed` signal in `cvaControlCreate` to run legacy validators and map into standard validation errors without generic `as any` type assertions.
- Intercepted `registerOnValidatorChange` to trigger updates even when the model value remains unchanged (e.g., going from `null` to `null`).
- Added integration tests to verify parse error propagation and reactivity.
PR Close#67943
use controlValue() instead of value() to ensure that CVA controls see the most recent user input immediately rather than waiting for it to be synchronized after debouncing
PR Close#67943
Inline code elements inside table cells inherited `width: 100%` from
the global code styles, causing short codes like `s`, `dev` to stack
vertically instead of rendering on the same line. Add `min-width` to
table cells containing code to ensure proper inline layout.
URLs with three or more consecutive leading slashes (e.g. `///test`) were
parsed incorrectly by `DefaultUrlSerializer`. The parser consumed only two
leading slashes, leaving a third that caused `parseSegment()` to produce an
empty `UrlSegment`. When serialized back, that empty segment rendered as
`//test` — a protocol-relative URL that browsers resolve as a different
origin and reject with a `SecurityError` when passed to
`history.pushState`/`replaceState`.
The fix changes `parseRootSegment()` to consume all consecutive leading
slashes instead of just one, normalizing any number of leading slashes to
a single `/` before the path is parsed.
Closes#49610
To support the need to resolve symbols without full AST access (e.g. when using virtual files), this commit decouples `ReferenceSymbol` from `ts.ClassDeclaration`.
Changes:
- Updated `ReferenceSymbol.target` to use `SymbolReference` instead of `ts.ClassDeclaration`.
- Removed `getReferenceTargetNode()` from `SymbolDirectiveMeta` and transitioned to `getSymbolReference()`.
- Refactored `getTsSymbolOfReference` in `checker.ts` to handle `SymbolReference` and resolve it to a `ts.Symbol` using a position-optimized AST traversal. This avoids using the private `getTokenAtPosition` API and avoids full file scans by only traversing nodes containing the target position.
Enhances the Chrome DevTools performance profiling integration by adding links to relevant Angular documentation for lifecycle hooks and profiler events.
The `ComponentFactory` has been removed from the public API in #68055.
This commit continues the cleanup and also removes `ModuleWithComponentFactories` from the public API.
This change allows to toggle attributes that are on their own line and have a 1+ leading space.
This change doesn't suffer from the issue that was reverted in #68067.
Also this change fixes another regression that messed up highlighting if an attribute value included a '//', like in an href.
Add support for CSP nonces in JsonpClientBackend by injecting the CSP_NONCE token.
This ensures that dynamically created script tags for JSONP requests include the
required nonce attribute to comply with strict Content Security Policies.
This API was deprecated for a longtime, and was remove by #68055 from the public API.
We do have alternatives to this old API, so we can entirely remove it to spare some bytes
This registers AI runtime debugging tools during platform creation and unregisters them when the platform is destroyed. This roughly matches existing usage of global utils with respect to timing. It is limited to dev mode only because these tools are exclusively for debugging Angular's internals and not something production users would leverage.
This provides an `angular:signal_graph` in-page tool which exposes the signal graph from the component rendered for a particular DOM element. It leverages the algorithm defined for Angular DevTools, which essentially means it takes the effects registered on the components injector and walks transitive dependencies to find all signals referenced by the component in an effect or the template.
These serve as the type definitions for interacting with the `chrome-devtools-mcp` AI runtime debugging functionality. Eventually this will hopefully be upstreamed to some more authoritative location, but for now this will do.
Apparently the Rollup bundle for these tests defaults to `es` format, meaning it expects to be loaded at runtime as native ESM. This was not happening because it was loaded as a regular `<script src="...">` tag (note the lack of `type="module"`).
This is problematic because Rollup assumed it would be running in a scoped environment, meaning [this function](https://github.com/angular/angular/blob/adb8d1078d5f127085952ca81951c18e0178a038/packages/core/primitives/event-dispatch/src/event.ts#L45), which happens to be named `addEventListener` but does *not* implement the `EventTarget.prototype.addEventListener` contract, was being bundled as a simple:
```javascript
function addEventListener(element, ...) {
// ...
}
```
Since this was loaded with no `type="module"` or `'use strict';`, the script executed in "sloppy mode", meaning all `var` statements and function definitions are implicitly global. Since `window` *is* the `globalThis` object, this random `addEventListener` function clobbers the actual `window.addEventListener` and breaks any calls to it because they're not implementing the same contract.
Fix is to just use `<script src="..." type="module">`. Alternatively we could bundle in an IIFE, which Rollup does support, but in theory we could depend on external ES modules which aren't bundled, so the `type="module"` seems a little safer and more future-proof.
Creating a platform and bootstrapping an application might register more events than just what the router expects (and an event will be added to platform creation in this PR). This test shouldn't be so strict about it.
This commit escapes forward slashes in the transfer state JSON output as \u002F to prevent search engine crawlers from aggressively indexing relative paths inside the inline script tag. It also updates related unit and integration tests across core and platform-server.
Fixes#65310
Replace separate margin-left/margin-right overrides with a single
margin shorthand in the phone-only media query, aligning spacing
with the base rule and preventing edge collision on small screens.
Update the "Next step" pill in templates to point to signal-forms
instead of skipping it, and add a next-step pill in signal-forms
linking to dependency-injection.
Link "W3C Accessibility Guidelines" to WCAG 2.2 and "WAI-ARIA patterns"
to the W3C APG patterns page, giving readers direct access to the
referenced specifications.
This is a minimal implmentation which just focuses on registering parent shadow roots in `SharedStylesHost` correctly.
We don't currently reference count usage of host values, meaning that as soon as we call `removeHost`, all styles are removed from it, even if other components relied on them. Therefore there is no good way to know whether styles are still needed or not, leaving us with the choice of either leaking them longer than necessary or destroying them while another component still needs them. The compromise I'm using here is to delete styles when destroying a component under a shadow root (based on the assumption that only one component will exist per shadow root) and to leave styles when destroying a component in the main document (based on the assumption that dialogs being destroyed should not impact the main application).
Neither assumption is totally safe to make, but we're hoping this is a viable balance for the moment. In the future we should look into lifting these restrictions to better support those use cases while properly reference counting usage of hosts in `SharedStylesHost`.
I also added some small tests to confirm that SSR styles are not duplicated, as an earlier implementation accidentally duplicated them. This should ensure we don't repeat that mistake.
This shouldn't have been happening before, but now that we're going to start calling `addHost` during root component boostrap, we may call `addHost` on the same node multiple times and don't want to duplicate styles.
This is necessary for an `RNode` to discover whether it is within the context of a shadow root, which is needed to know where a component's style should be placed.
The method is Baseline Widely Available, however we need to treat it as optional for SSR / JSDom contexts where shadow DOM is not supported.
Migrate from using use_repo_rule and override_repo directly to using the rules_angular.setup module extension for configuring configurable dependencies.
The homepage navigation bar rendered with `height: 0` on viewports between
701–900px, causing its content to overflow on top of the announcement banner
and block scrolling. Reset nav height to `auto` at tablet sizes, center the
v21 banner, adjust its top margin, and hide the redundant search field since
the nav bar already provides one.
I've had some success asking the Antigravity agent to find flaky tests and propose fixes for them, then just running it in the background and reviewing what it finds. Upstreaming this to the repo so others can use it, since it includes helpful notes like `--runs_per_test` and leveraging random seeds as well as an iteration loop.
I opted not to have the agent do anything with PRs just yet, but if this is useful and we build confidence in it, we can explore that in the future.
Adds a documentation page for the NG01002 runtime error thrown by
FormGroup and FormArray when setValue is called with a value that is
missing an entry for one or more registered controls.
The error code is also changed from positive (1002) to negative (-1002)
so that Angular appends a link to the error reference page in dev mode,
consistent with how other documented errors (e.g. NG01101, NG01203) are
handled.
In standard DOM definitions (lib.webworker.d.ts), the messageerror event
is typed as MessageEvent, which lacks the waitUntil property found on
ExtendableMessageEvent. In modern versions of TypeScript (including TS 6.0),
this causes compile-time overload resolution errors when the listener function
is explicitly typed to expect ExtendableMessageEvent.
This commit updates provideClientHydration to automatically enable incremental hydration by default. It also introduces a new withNoIncrementalHydration feature for opting out, adds conflict safety checks, and includes a schematic migration.
The commit updates the TCB for safe navigation expressions to allow for correct narrowing of nullables.
This will trigger the `nullishCoalescingNotNullable` and `optionalChainNotNullable` diagnostics on exisiting projects.
You might want to disable those 2 diagnotiscs in your `tsconfig` temporarily if you want to update your project without having to fix all the issues at once.
Narrowing can be disabled altogether with `strictSafeNavigationTyes: false`.
fixes#37619
BREAKING CHANGE: This change will trigger the `nullishCoalescingNotNullable` and `optionalChainNotNullable` diagnostics on exisiting projects.
You might want to disable those 2 diagnotiscs in your `tsconfig` temporarily.
Update the supported TypeScript version range for Angular 22.0.x from `>=5.9.0 <6.0.0` to `>=6.0.0 <6.1.0` to reflect the correct compatibility requirements.
Decouple `SymbolBuilder` from the full `BoundTarget` interface by introducing a purpose-built `SymbolBoundTarget` interface containing only the 4 methods required for symbol resolution. This eliminates the need for the large, pass-through `BoundTargetAdapter` and further isolates `SymbolBuilder` from compiler-internal implementation details.
Also minimize `TypeCheckableDirectiveMetaAdapter` by redefining `SymbolDirectiveMeta` to not extend `DirectiveMeta`, exposing only the properties actually used by `SymbolBuilder`.
Removed dead code `getDirectiveMeta` in `template_symbol_builder.ts` which was unused.
These changes improve maintainability and ensure a cleaner architecture by strictly defining the boundaries of what `SymbolBuilder` needs from the rest of the system.
By limiting the required inputs to only what's necessary for the implementation, we make it easier to re-use
the implementation between different compiler architectures
Since WebKit commit 67a62d98 (merged for iOS 13), WebKit no longer restricts
click event bubbling to interactable nodes like `div` or `body`. The
`cursor: pointer` hack polyfill is therefore obsolete and can safely be
removed without breaking JSAction behavior.
- Enclose the spam saved reply in a code block in `saved-issue-replies.md`
- Correct spelling and punctuation in `saved-issue-replies.md` and `spam.md`
removing ts.typechecker in a prior refactor caused some regressions, particularly when multiple directives
appear on a single elemnt. this is now addressed by using an id for directives and storing that in the tcb comment
Prioritize custom ControlValueAccessor instances over default or built-in accessors when applying the [formField] directive. This is achieved by directly consuming selectValueAccessor from @angular/forms, ensuring absolute alignment with the precedence rules used across standard Angular form directives.
Update bindings['controlValue'] during onChange to track the view value. This allows bindingUpdated to skip writeValue if the model value matches the last seen view value, preventing redundant writes.
Fixes#67847
This is to align the shape of the method with `createComponent`
BREAKING CHANGE:The second arguement of appRef.bootstrap does not accept `any` anymore. Make sure the element you pass is not nullable.
fixes#67946
Simplify the hydration regression test by removing conditional early-return branches and relying on direct Jasmine expectations while keeping strict typing and OnPush configuration.
When a sidebar item links to a page in a different category (e.g., Route
transition animations under Animations links to a Routing page), clicking
back navigates to the main menu instead of the originating category.
Store the originating category in NavigationState when clicking a
cross-referenced item, so the back button returns to the correct section.
The "Log to console" button in the prop-actions-menu component incorrectly logs the entire props object rather than the value of the individual prop with which the button is associated. Passing the `node` to the logValue function fixes the prop lookup logic and logs the appropriate prop value to the console.
Those APIs date back to pre-ivy times and are long deprecated.
BREAKING CHANGE: `ComponentFactoryResolver` and `ComponentFactory` are no longer available. Pass the component class directly to APIs that previously required a factory, such as `ViewContainerRef.createComponent` or use the standalone `createComponent` function.
Fixes an error that was heppning when a generic param has type parameters of its own. There were a few different issues going on:
1. In #67707 I had changed a bit how we pass the `genericContextBehavior` which ended up ignoring the `useContextGenericType` option from the environment.
2. All directives depend on themselves, but we were overridding the `genericContextBehavior` for the directive being processed.
3. The type translator wasn't handling type parameter declarations. Technically we shouldn't be able to hit a code path that has a type parameter, however it's also easy enough to handle so we might as well.
Relates to #67704.
Fixes that we were parsing bindings in the `host` object with a regex that didn't account for nested brackets which may come up with something like Tailwind.
Fixes#68039.
- Fixes TemplateSymbolBuilder.getTcbPositionForNode to recursively unwrap AsExpression and NonNullExpression nodes.
- Added a test case in type_checker__get_symbol_of_template_node_spec.ts to verify symbol mapping when strictSafeNavigationTypes is false.
- Note: The issue likely broke in commit 13c8df67d9.
This fixes a memory leak in `SharedStylesHost` where calling `removeHost` would leave any `<style>` or `<link>` tags associated with that host in the DOM. This is wasteful in general, and can create even more leaks if the same host is added and removed multiple times, causing styles to be consistently reappended but never removed.
BREAKING CHANGE: This removes styles when they appear to no longer be used by an associated `host`. However other DOM on the page may still be affected by those styles if not leveraging `ViewEncapsulation.Emulated` or if those styles are used by elements outside of Angular, potentially causing other DOM to appear unstyled.
The IdentityTracker singleton never deleted entries from its internal
maps (_currentDirectiveId, _currentDirectivePosition, isComponent) for
destroyed directives. This caused the maps to grow monotonically for
the entire DevTools session, retaining references to destroyed component
instances and preventing garbage collection.
The cleanup was intentionally commented out because the profiler needs
to resolve IDs and positions of removed components during recording.
Introduce `setProfilingActive()` to gate cleanup: when profiling is
inactive, removed entries are deleted immediately during `index()`.
When profiling is active, removals are deferred into a `_pendingRemovals`
set and flushed once profiling stops via `capture.ts` start/stop calls.
The `HttpClient` tests in `client_spec.ts` were failing intermittently in Node/Domino environment because `MockPlatformLocation` defaults to `http://_empty_/`. This valid URL satisfied the URL parser in `xsrfInterceptorFn`, causing it to proceed to cookie extraction which throws `NotYetImplemented` in Domino.
To fix this:
1. Disabled XSRF protection in `client_spec.ts` using `withNoXsrfProtection()`, as these tests are not for XSRF.
2. Provided `ɵprovideFakePlatformNavigation` to remove state leakage effects and ensure consistency.
On narrow viewports, the search result icon was pushed to its own flex line when the title text was too long, causing vertical misalignment.
The fix wraps the title text and package badge in a single container that manages its own flex layout, preventing the icon from being separated from the text on narrow viewports.
Fixes#68005
This updates the SymbolBuilder to no longer use ts.TypeChecker internally to
build symbols for the language service. These lookups are deferred/done later
using the newly expanded template type checker API.
The test was using a brittle fixed timeout of 10ms to wait for change detection to run in Zoneless mode. This failed in CI sometimes presumably because CI can execute slower based on resource constraints. This commit replaces it with a polling approach which checks until the expected content is rendered.
This test appears to be flakey in CI, presumably because resource constrained environments can run unexpected slower and exceed the timeout. This switches to a polling approach, waiting for the queue to drain.
Document that FormArray.value includes only enabled child controls when the array is enabled, but includes all child values when the FormArray itself is disabled.
Fixes#67759
Ensure that input [type] bindings are evaluated dynamically rather than cached eagerly during initialization. This allows late-bound expressions for input types to correctly apply constraints like min/max and maxLength.
Fixes#66987
With host directives we can end up in a situation where the same directive applies multiple times to the same element, potentially with conflicting configurations. The runtime isn't set up for a directive to apply more than once so historically we were throwing an error when we detect duplicates.
This ended up limiting the usefulness of host directives to library authors, because it meant that host directives couldn't be reused as much as authors wanted. To address the issue, these changes introduce logic in the compiler and runtime that will de-duplicate host directives with the following logic:
1. If a directive matches once in the template and more than once as a host directive, the host directive matches will be discarded and only the template match will apply. The mental model is that a host directive match represents `Partial<YourDirective>` while a template match represents the full `YourDirective`.
2. If a directive matches multiple times as a host directive, we merge the input/output mappings from all the instances into a single one. If we detect a case where an input/output is exposed under multiple names during the merging process, both the compiler and the runtime will produce an error.
Fixes#57846.
Implements the logic at the compiler level that will de-duplicate host directives and merge them together. It will also report if a conflict is detected during merging.
Moves the `ClassPropertyMapping` into the compiler, rather than having to pass around the limited `InputOutputPropertySet` interface that is only implemented by `ClassPropertyMapping`.
Those APIs date back to pre-ivy times and are long deprecated.
BREAKING CHANGE: `ComponentFactoryResolver` and `ComponentFactory` are no longer available. Pass the component class directly to APIs that previously required a factory, such as `ViewContainerRef.createComponent` or use the standalone `createComponentFunction`.
This adds a bit more context to the NG0750 error message to provide details about which module failed to load when executing the dependencyResolverFn. This can help with debugging a failed lazy load in a defer block.
it was only optional to avoid a breaking change in a minor
BREAKING CHANGE: The `currentSnapshot` parameter in `CanMatchFn` and the `canMatch` method of the `CanMatch` interface is now required. While this was already the behavior of the Router at runtime, existing class implementations of `CanMatch` must now include the third argument to satisfy the interface.
PR Close#67452
Depending on the client app version, either show "OnPush" (pre-v22) or "Eager" (v22+); As part of the change, `APP_DATA` root signal has been introduced along with a minor bug fix related to component metadata displaying.
Previously, the Language Service fetched Quick Info and definitions for template variables (such as `@let` declarations) using mapping to their `initializerLocation` (the right-hand side expression). This aggressively bubbled the type, JSDoc, and definition identity of the initializer backwards onto the variable itself.
This approach had two flaws:
1. It broke type narrowing because the LS read the original un-narrowed type from the source expression rather than the type of the narrowed intermediate variable in the Type Check Block.
2. It deviated from native TypeScript semantics, where a local `let` binding (`let address = hero.address`) does not inherit the docstrings or `(property)` kind of its initializer, acting solely as a local inferred variable.
By using `localVarLocation` rather than `initializerLocation` for LetDeclaration Quick Info and Type Definitions, these intermediate variables now properly preserve type narrowing within templates and flawlessly match the standard behavior expected of TypeScript block variables. `VariableSymbol.initializerLocation` is retained solely to map the value spans of structural directive contexts (e.g., `exportAs` strings).
fixes#65491
The `split` helper function in `packages/router/src/utils/config_matching.ts` was blind to the current outlet being processed. When encountering an empty path named outlet in the config, it would assume it needed to pull it in as a synthetic empty group, even if we were already in the process of resolving that very outlet!
When navigating to `/(secondary:component-copy)` with this config:
```typescript
{
path: '',
component: MainLayout,
children: [
{ path: '', outlet: 'secondary', component: SecondaryComponent, children: [{path: 'component-copy'}] }
]
}
```
The router uses `MainLayout` as a pass-through and calls `split` on its children with segments `['component-copy']`.
`split` uses the `containsEmptyPathMatchesWithNamedOutlets` helper to determine if there are any candidate empty path named outlets to pull in. Because of this, it sees `{ path: '', outlet: 'secondary' }` and says: "Ah, an empty path named outlet! I must pull it in!"
Rather than falling through to standard segment matching, it returns `UrlSegmentGroup(segments: [], children: {secondary: emptyGroup})`.
The router then tries to process `primary` (with `[]` segments) and fails because the config only has `secondary`. It also tries to process `secondary` with the `emptyGroup`. While `{ path: '', outlet: 'secondary' }` matches the empty group, its child `{ path: 'component-copy' }` fails to match because the `emptyGroup` has no segments! So both branches fail, resulting in a `NoMatch` error for the entire navigation!
Pulling in empty path named outlets IS desired when they act as siblings to segments we are matching. This has worked before and continues to work!
```typescript
{
path: 'a',
children: [
{ path: 'b', component: ComponentB },
{ path: '', component: ComponentC, outlet: 'aux' }
]
}
```
When navigating to `a/b`, `split` sees segments `['b']` and the `aux` empty path. It pulls in `aux` so it gets instantiated alongside `b`. This is correct!
If we have a named outlet with a non-empty path under an empty path parent:
```typescript
{
path: '',
component: MainLayout,
children: [
{ path: 'component-copy', outlet: 'secondary', component: ComponentE }
]
}
```
When we navigate to `/(secondary:component-copy)`:
- `split` uses `containsEmptyPathMatchesWithNamedOutlets` to see if there are any empty path named outlets. Since it only sees `path: 'component-copy'`, it returns `false`.
- It falls through to standard segment matching, which finds `component-copy` in the segments array and activates it flawlessly!
This worked perfectly before the fix because it didn't use `containsEmptyPathMatchesWithNamedOutlets`.
The fix passes the **current active outlet context** into `split`. If `split` finds an empty path named outlet that matches the outlet we are already processing, it ignores it as a pull-in candidate.
When evaluating `MainLayout` children for `secondary`:
- URL Segments left to process: `['component-copy']`
- Current Outlet: `secondary`
- `childConfig`: `[{ path: '', outlet: 'secondary' }]`
Previously, `split` saw the empty path and pulled it in as a synthetic empty group, breaking matching. Now, since `getOutlet(r) === outlet` (both are `secondary`), the fix ignores it. Instead of returning empty segments, it **falls through to standard segment matching**, which successfully find the `component-copy` segment!
When evaluating `ComponentA` children for `primary`:
- URL Segments left to process: `['b']`
- Current Outlet: `primary`
- `childConfig`: `[{ path: 'b' }, { path: '', outlet: 'aux' }]`
Since `getOutlet(aux) !== primary`, the fix **does not ignore it**. `split` pulls in `aux: emptyGroup` as a sibling, instantiating `ComponentC` alongside `ComponentB`. This preserves correct behavior for auxiliary outlets!
fixes#67708
SVG animation elements (`animate` and `set`) can be used to animate sensitive attributes like `href` or `xlink:href`. Binding to these animation attributes (like `to`, `from`, or `values`) with a sensitive target creates an XSS vector.
This change mitigates this risk by:
1. Classifying `to`, `from`, and `values` on `<animate>` and `<set>` elements as `ATTRIBUTE_NO_BINDING` in the DOM security schema to prevent standard dynamic bindings.
2. Adding runtime validations in `ɵɵvalidateAttribute` to verify that `attributeName` is not a sensitive attribute (such as `href` or `xlink:href`) when processed by a set of `SECURITY_SENSITIVE_ATTRIBUTE_NAMES`. If it is, a runtime error `UNSAFE_ATTRIBUTE_BINDING` is thrown.
3. Adding regression tests in `integration_spec.ts` to ensure unsafe bindings throw an error while safe ones pass correctly.
PR Close#67797
Previously, the `data` attribute of the `<object>` tag was being sanitized as a regular URL instead of a `ResourceURL`, which is security-sensitive.
This commit updates the runtime sanitization logic to correctly identify `object[data]` as a `ResourceURL` context. Additionally, the sanitizer lookup logic has been refactored to use a more efficient lookup map (`RESOURCE_MAP`) instead of multiple `Set` lookups, providing better performance and maintainability.
Added tests to verify the correct sanitization of `object[data]` and its behavior with trusted values.
PR Close#67797
This change is a security hardening measure to prevent potentially unsafe attribute value manipulation through SVG animations. By mapping `animate|to`, `animate|from`, `animate|values`, and `set|to` to the `SecurityContext.URL`, Angular will now automatically sanitize these attributes.
PR Close#67797
Avoid substring matching on importClause.getText() which caused suffix collisions (e.g., BarComponent vs FooBarComponent). Use AST-based matching for default and named (including aliased) imports to reliably resolve the correct import path when generating loadComponent.
Fixes race conditions where intermediate layout renders caused the browser to emit 'largest-contentful-paint' events or 'load' events that led to inconsistent console logs. Updated tests to correctly wait for elements to stabilize and properly filter expected log messages.
The `pending` getter in `AbstractControl` used loose equality (`==`)
while all other status getters (`valid`, `invalid`, `disabled`) use
strict equality (`===`). Both sides are strings so behavior is
identical, but this inconsistency would fail strict linting rules.
Updates the Angular CLI reference to reflect current framework defaults:
- Changes the recommended application builder to @angular/build:application.
- Replaces Jasmine and Web Test Runner with Vitest as test runner examples.
The `localize-translate` CLI tool uses the `locale` field from translation files to expand the `{{LOCALE}}` placeholder in the output directory. It failed to sanitize `locale` input, allowing malicious translations to write files outside of the configured output directory.
This change mitigates this issue by combining.
Closes#67906
Aligns list formatting, replaces the “Helpful” block with an
IMPORTANT note for better visibility, and removes the separate
example file by inlining the single relevant line directly
in the documentation.
Replaced testing constructions of `Date` objects from `formatDate` tests from plain ISO strings over to 'new Date(year, month, date)'.
Instantiating 'new Date("2024-01-01")' parses the string strictly as UTC midnight ("2024-01-01T00:00:00.000Z"). When local operations execute (such as calculating `getThursdayThisIsoWeek` boundaries), the UTC date shifts relative to the executing machine's timezone. For example, in PST (GMT-8), that date translates exactly to 'December 31st 16:00:00', pushing week boundaries backwards.
By wrapping date constructs explicitly as 'new Date(2024, 0, 1)', it natively guarantees local midnight execution and prevents boundaries shifting on global CI Remote Build Execution (RBE) workers.
Example (from a machine in PST):
```javascript
> new Date('2024-01-01')
Sun Dec 31 2023 16:00:00 GMT-0800 (Pacific Standard Time)
> new Date(2024, 0, 1)
Mon Jan 01 2024 00:00:00 GMT-0800 (Pacific Standard Time)
```
Removes the 'America/New_York' timezone string test case from `formatDate` tests because the underlying `Date.parse` API does not support IANA timezone strings. This caused the timezone calculation to silently fall back to the local executing machine's timezone, leading to non-deterministic test flakiness on Remote Build Execution (RBE) workers operating in varying geographic locations.
The current PR review skill blindly attempts to checkout branches using the `gh` CLI.
This creates fatal errors if the branch being checked out is already tied to a different git worktree.
Additionally, the logic didn't give the user a clear way to enforce a remote code review when they are the author.
This change updates the `Execution Workflow` to prioritize an explicit user instruction to review remotely, and updates the `Local Code Review` instructions to enforce checking for worktree conflicts before executing local checkouts.
This adds support for a `debounce` option to the `validateAsync` and `validateHttp` functions.
This allows developers to debounce the triggering of async validators to improve performance.
A `DebounceTimer` type was also added to `@angular/core` to represent the wait condition parameters uniformly.
Move the domino bundling logic and related shims into a centralized third_party directory within packages/platform-server. This avoids duplication of the bundling logic and ensures consistent shimming across the platform-server package and its entry points.
Following a conversation with OSS licensing, this change also includes the domino LICENSE file in the generated npm package to comply with licensing requirements for bundled third-party code.
```
├── fesm2022
│ ├── init.mjs
│ ├── init.mjs.map
│ ├── platform-server.mjs
│ ├── platform-server.mjs.map
│ ├── _server-chunk.mjs
│ ├── _server-chunk.mjs.map
│ ├── testing.mjs
│ └── testing.mjs.map
├── LICENSE
├── package.json
├── README.md
├── third_party
│ └── domino
│ ├── bundled-domino.d.ts
│ ├── bundled-domino.mjs
│ ├── bundled-domino.mjs.map
│ └── LICENSE
└── types
├── init.d.ts
├── platform-server.d.ts
└── testing.d.ts
```
Custom controls can be modeled using a set of host directives to alias
and expose value and valueChange (or checked/checkedChange) bindings,
as well as native attributes like disabled.
This commit updates initializeCustomControlStatus to correctly identify
host components using mapped inputs/outputs, even when those inputs are
exposed via transitive host directives. It also updates
customControlHasInput so that the custom control presence check correctly
evaluates the exposed inputs across all applied host directives, caching
the result to optimize performance on hot code paths.
Currently the `OutOfBandDiagnosticRecorder` is tied to producing TypeScript diagnostics, however some of our use cases might call for a different form.
These changes decouple the recorder from TypeScript and make the diagnostic type generic.
Update the allowedHosts security warning in the security guide to remove the mention of DNS rebinding, which is primarily relevant for the dev server, and refocus on host header injection and SSRF. Additionally, clarify that allowing all hosts with "*" is only appropriate when header validation is handled by an external layer.
The default change detection strategy is now OnPush.
BREAKING CHANGE: Component with undefined `changeDetection` property are now `OnPush` by default. Specify `changeDetection: ChangeDetectionStrategy.Eager` to keep the previous behavior.
Added a `getError(kind: string)` method to `FieldState` that returns the first validation error of a given kind, or `undefined` if no such error exists. This method is reactive and will re-evaluate when errors change.
Fixes#63905
Also updated public API goldens and added unit tests.
The `[formRoot]` directive will no longer call `submit()` if the bound
form doesn't define its own submission options. This allows the
directive to be used solely for the default behavior it provides:
setting `novalidate` on the `<form>` and calling `preventDefault()` on
the `submit` event.
Fix#67367
PR Close#67727
Destroy uses window.removeEventListener but the ChromeMessageBus doesn't actually depend on a window object.
In practice this code is unlikely to ever be reached. If a tab is closed the entire context script JS process is killed so this is not an bug that would be very common or even reachable. That being said for correctness this should not be using window.
Fixed misspellings in test descriptions in devtools/projects/shell-browser/src/app/tab_manager_spec.ts: recieved/recieves → received/receives in three it(...) titles.
Updates the snapshot publishing script to package the contents of
`skills/dev-skills` and publish them to the `angular/skills`
repository.
The changes include:
- Ensuring the script always runs from the repository root.
- Updating `publishRepo` to support an optional third argument for
specifying a custom repository name (defaulting to `-builds`).
- Implementing `publishDevSkills` to package individual skills at the
root of the snapshot repository.
Currently the directive inputs and outputs are typed to match the members of the class. We can't guarantee that when generating code, because of cases like `model` where an output is generated implicitly.
These changes widen the type to be any string.
Fixes that the `ɵɵresolveWindow` function wasn't match the type expected by `ɵɵlistener`. I've also added explicit type annotations to make cases like this easier to catch.
The comment placeholder restoration in `shimCssText` appended an unconditional
`+ '\n'` to each non-hash comment replacement. Because `_commentRe` does not
consume the newline that follows a comment in the source, that newline already
remains in `cssText`. The extra `'\n'` was therefore inserted on top of the
existing one, shifting every line after each comment down by one. In files with
many comments (e.g. large SCSS preambles) this shifts all subsequent CSS rules
far enough that the CSS sourcemap — generated before `shimCssText` runs —
points to completely wrong source locations in browser DevTools.
The fix is to drop the `+ '\n'`; internal newlines within a multi-line comment
are still preserved via `_newLinesRe`, and the trailing newline that follows the
comment in `cssText` is already present without any extra injection.
When a native date input gets cleared manually by a user via the internal browser
UI, the element changes from invalid to valid, but no `input` event is emitted.
This commit introduces `InputValidityMonitor`, an injectable service that
intercepts these edge-case native status changes. The monitor dynamically
installs CSP-compliant styles appending specific animation keyframes for
`:valid` and `:invalid` pseudoclasses on native form controls. By attaching an
`animationstart` listener, Angular intercepts these changes immediately and
re-invokes the parser.
Fixes#67300
Currently, Signal Forms eagerly instantiates all nodes in the form tree because `childrenMap` iterates over the `value` and creates a `FieldNode` for every property. This ensures validation side-effects are run early, but creates pure overhead for fields without validation logic unless explicitly accessed.
This commit makes `childrenMap` lazy by default, skipping materialization for children without schema logic. This is achieved by introducing `hasLogicRules()` and `anyChildHasLogic()` across the `LogicNode` hierarchy. Fields are now only instantiated when a direct read occurs via `getChild()` (which calls the new `ensureChildrenMap()`) or if their subtree requires eager evaluation due to existing validation rules.
Fixes#67212
When building a debounced resource, we previously eagerly started tracking the 'source' signal state by instantiating a regular signal. However, if this 'debounced' primitive is initialized in a computation reactive graph (like signal forms 'validateAsync'), reading the current UI source dependency eagerly can induce a cycle if we haven't finished calculating the graph node yet.
This fix uses a 'linkedSignal' block to define the eager 'source' instead. Because linkedSignals are lazy by default, this bypasses the initial eager evaluation, allowing the containing reactive graph to finish forming first without losing our timing logic inside the ambient effect().
Add NG8023 extended diagnostic to report duplicate component selectors
during compilation.
This replaces the former NG0300 runtime error, ensuring the failure
occurs at build time instead of runtime.
Closes angular#48377
BREAKING CHANGE: Elements with multiple matching selectors will now throw at compile time.
This fixes a regression bug that resulted in reordered elements not getting properly removed from the DOM. Reused nodes were not being cleared out in this situation.
fixes: #67728
`<input type="number">` often does not provide the desired user experience when editing numbers in
a form. MDN even [describes](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/number#using_number_inputs)
how text inputs should be used in many cases instead, via `<input type="text" inputmode="numeric">`
or similar configurations. Previously, this did not work with Signal Forms without a custom input
component/directive.
This PR builds support for binding `number|null` models directly to `<input type="text">` native
controls via `[formField]`. When a model has a number or `null` value, signal forms will preserve
that status when the user makes edits/changes. Empty string values are converted to `null`, other
values are parsed as numbers, and a parse error is raised when a non-numeric value is entered.
Note that it's up to the UI developer to configure additional UI affordances such as setting an
appropriate `inputmode`, rejecting non-numeric keypresses, etc.
Fixes#66903Fixes#66157
This commit introduces a formal mechanism to manually re-trigger
asynchronous validations in Signal Forms, addressing #66994.
It exposes a `reloadValidation` method on the `FieldState` interface
that recursively cascades down the form tree and invokes the underlying
`ResourceRef`'s `reload()` method for any metadata keys tagged with the
internal `IS_ASYNC_VALIDATION_RESOURCE` symbol.
Fixes#66994
Fix inject migration in multi-project workspace. The inject migration doesn't work when targeting one of the projects due to either not finding any files in other projects or considering them external thus it throws a SchematicsException
Fixes: #66074
Preserve the redirect mode when rebuilding asset requests in newRequestWithMetadata(). This keeps explicit redirect:error semantics intact across service-worker redirect handling.
Update the worker test mocks to model redirect defaults correctly and add focused regression coverage for redirected lazy assets with redirect:error.
Add DocumentSymbol provider for Angular templates, surfacing structural
elements like components, directives, control flow blocks, and template variables
in the VS Code Outline and breadcrumbs.
resolves#65488
Includes:
- Imports and setup instructions
- Validation examples (sync, async, conditional)
- FieldState vs FormField distinction
- Common pitfalls and best practices
- Full-featured example application
Adds a new agent skill focused on providing fundamentals to coding agents and adhering
to modern Angular code including Signals, Signal Forms and other latest updates.
This fixes an issue where when removing NgStyle from the imports array of a component, an extra trailing comma would be left behind if it was the last element in that component`.
This commit resolves an issue where using an uninstantiated generic type
parameter in a signal form model caused TypeScript compilation failures due to
distributive conditional types (#66596). The previous attempt to fix this issue
by tuple-wrapping everything caused another bug (#65535) that prevented property
access on generic unions.
This commit balances the need to resolve nested generic property access while
handling infinitely recursive generic structures without depth errors.
What changed and why:
- Base State Wrappers: Tuple wrappers (`[TModel] extends [AbstractControl]`) are
applied to `FieldTreeBase` to safely defer generic evaluation. This prevents
primitive unions (like `boolean`) from incorrectly evaluating to `never`.
- Naked Map Over Children: Object subfield checks (`TModel extends Record`) are
re-evaluated as purely naked conditionals. Eager distribution over generics
allows users to directly access shared properties of unresolved union types.
- Array Interface Deflection: `ReadonlyArrayLike<T>` generic abstraction is
redefined as an explicit `interface` instead of a mapped `Pick` type alias.
This optimally intercepts TypeScript from eagerly evaluating infinitely
recursive array structures (e.g. `RecursiveType = (number | RecursiveType)[]`).
- Overloaded Context Methods: `FieldNodeContext.stateOf` and `fieldTreeOf` are
defined as explicitly overloaded class methods and lexically bound (`this`) in
the constructor. These changes are required to safely align the runtime bindings
with the tautological conditionals implemented in the `RootFieldContext`
interface structure.
Fixes#65535
These type annotations allow TS to associate the object's properties
with their corresponding declaration in the interfaces, enabling
much better code navigation. For example, "Find all implementations"
for `ReactiveNode.producerRecomputeValue` now finds the implementation
in `COMPUTED_NODE` and `LINKED_SIGNAL_NODE`.
This commit ports the changes in #55818 from `computed` to `linkedSignal`,
which duplicates the core logic to recompute the downstream value for an
upstream change.
The lexer's isNamedEntityEnd function stopped scanning entity names
when encountering a digit character, causing 24 valid HTML named
entities with digits in their names (e.g. ¹, ½, ▓)
to be treated as plain text instead of decoded to their corresponding
Unicode characters.
Fixes#51323
Fixes a regression caused by the recent TCB changes where we moved the type parameter processing earlier in the pipeline and stopped properly accounting for the `TcbGenericContextBehavior`.
Fixes#67704.
Implement support for `FormUiComponent`s in both Reactive and Template-driven
forms. This allows components that use the new signal-based form control
architecture to be used seamlessly within existing Angular form paradigms.
Key changes:
- Integrated `ɵngControlCreate` and `ɵngControlUpdate` lifecycle hooks into
`NgModel`, `FormControlDirective`, and `FormControlName`.
- Implemented branching logic to choose between the traditional `ControlValueAccessor` (CVA) path and the new FVC path based on the host element's capabilities.
- Added comprehensive unit tests for FVC integration in both Reactive (`reactive_fvc.spec.ts`) and Template-driven (`template_fvc.spec.ts`) forms, covering:
- Value synchronization (model -> view and view -> model).
- Status synchronization (touched, dirty, valid, invalid, pending, required).
- Error propagation and `parseErrors` support.
- Fallback behavior to native DOM properties (disabled, required) when FVC inputs are missing.
- Graceful fallback to CVA when no FVC pattern is detected.
- Refined `NgModel` to correctly handle `required` validation via its existing `RequiredValidator` directive while supporting FVC for other properties.
Update `NgControl` to support binding to custom controls via the new `ngControlCreate` and
`ngControlUpdate` lifecycle hooks. This will allow Reactive and Template-driven forms to integrate
with components that use the new `FormValueControl` (FVC) binding convention.
Key changes:
- Implement synchronization of control state between `FormControl` and custom controls.
- Add support for `parseErrors` signals from custom controls, integrating them into the Reactive
Forms validation loop via a dynamic validator.
- Convert Reactive Forms errors into `ReactiveValidationError` objects for consumption by custom
controls.
- Update `NgModel`, `FormControlDirective`, and `FormControlName` to provide necessary dependencies
(`Injector`, `Renderer2`) to `NgControl`.
- Rename `setUpControl` to `setUpControlValueAccessor` to clarify its role in the traditional
CVA path.
Introduces an internal signal that tracks whether `Validators.required` is in the set of validators
for an `AbstractControl`. This signal is updated whenever the validators are changed.
Relocate some utility code into `@angular/forms` instead of the signal-forms specific entrypoint,
to facilitate their reuse in existing template & reactive forms.
Delay the selection of a CVA until after the `ɵɵcontrol` instruction has a chance to execute.
This is necessary to delay the error that would be thrown for a missing CVA until after we have a
chance to recognize we're actually on an FVC/FCC.
If `FormsModule` or `ReactiveFormsModule` is present in the scope of a
template, plain `<input>` and other form elements will get default CVA
directives added. This commit adds an `ngNoCva` attribute as a negative
selector for those directives, so `<input ngNoCva>` elements will not have
them matched.
`markAsTouched()` now marks all descendants as touched. In general this
method is called when controls update the model. Most controls update
leaf nodes, in which case this change has no effect.
Marking all descendants allows triggering validation for subsections of
a form, independently from having to call `submit()` on the entire form.
`markAsTouched()` now accepts a `MarkAsTouchedOptions` parameter, which
includes a `skipDescendants` property. This can be used mark only the
receiving field as touched: `node.markAsTouched({skipDescendants: true})`.
Utilize the new `ng.getControlFlowBlocks` API by refactoring the existing render tree extraction code; Slighly modify @for loop details view
PR Close#66167
Create a universal mechanism for adding and managing control flow discovery utilities. Those utilities are intended to be consumed by third parties via the `ng` global interface.
PR Close#66167
- Handle @for data in tree strategies and view extraction
- Show @for details in the UI and property tab
- Persist @for state and update UI accordingly
PR Close#66167
Optimization Goals:
The primary goals of this optimization are to dramatically reduce the execution time of the language-service test suite and stabilize the mock file system infrastructure. Previously, the suite suffered from significant overhead due to recreating the `MockFileSystem`, `MockServerHost`, and TypeScript `ProjectService` for every single test block, leading to redundant parsing operations, slow test initialization, and reduced spec performance.
How the Goals Were Achieved:
1. **Mock File System Optimizations (Shared State)**:
- Evaluated that standard test files (e.g., TS/Angular lib definitions) are immutable across tests.
- Introduced and utilized `lockMockFileSystem()` to initialize the mock `FileSystem` with `loadStandardTestFiles()` only once per test suite run rather than repeatedly per test.
- Refactored `LanguageServiceTestEnv.setup()` to reuse the singleton file system, completely skipping redundant module loading by eagerly flagging `fsInitialized = true`.
2. **Language Service Test Environment Enhancements (TypeScript Project Reuse)**:
- Implemented partial configuration reloads in the `Project` class via the `update()` method, removing the need to tear down and rebuild the entire `MockServerHost` and TypeScript `ProjectService` from scratch when minimal file changes (like HTML templates or local TS edits) are made dynamically by a test.
- Applied `projectService.reloadProjects()` and `scriptInfo.reloadFromFile()` to synchronously push mock file tree invalidations to the active TS program, skipping expensive environment initialization and saving considerable latency across tests.
- Added `projectName` identifiers inside complex isolate tests (e.g. module alias aliasing) so custom environment injections can sandbox safely without invalidating the global default environment cache.
3. **Test Suite Unification**:
- Flattened fragmented test groups (`grp1`, `grp3`, `grp4`) into a cohesive single directory at `packages/language-service/test/`. This simplifies execution config, improves test runner concurrency, and unifies local development targeting.
- Cleaned out broken inline debug logging and unneeded config reloading loops.
4. **Maintaining Test Isolation**:
- **Explicit TypeScript Configuration**: While the underlying `MockFileSystem` ("disk") is aggressively reused across tests, the TypeScript `ProjectService` and its execution environment are entirely recreated for every test run to ensure isolated ASTs and module resolution caches.
- **Strict tsconfig.json Files Array**: When a project is initialized, it explicitly defines its boundary using the strict `files: [ ... ]` array in `tsconfig.json`. This ensures that any leftover files physically on the mock disk from an older test run are completely invisible to the TS Compiler.
- **Namespace Sandboxing**: For tests doing custom modifications (e.g., overriding module resolution paths), they utilize localized `projectName` arguments (like `"test_alias_completions"`) to configure sandboxed working directories.
This commit introduces an AI agent skill for reviewing pull requests
against the Angular repository. It establishes guidelines for ensuring
code cleanliness, performance, testing, API design, and payload size.
It supports performing reviews through both the GitHub CLI (remote) and
local editing, factoring in package-specific guidelines (e.g., router)
and prioritizing user approval before posting comments. By checking existing
comments first, the agent can avoid duplicate reviews.
This provides the AI agent with a reproducible workflow for providing
constructive, manual PR feedback.
Implement a context menu and add it to each property in the properties pane in order to optimize the available space by consolidating the action buttons of property items with multiple of them. Property items with a single action will retain their original behavior where the action button is directly available to click right after the displayed value.
During HMR, `recreateLView()` destroys the old LView and removes its
DOM nodes, but never cleans up dehydrated view DOM nodes stored in
`LContainer[DEHYDRATED_VIEWS]`. These are SSR-rendered DOM nodes
preserved by Angular's hydration system. When the new view renders,
both the old dehydrated DOM and the new DOM coexist, causing visible
duplication (e.g. `<app-shell>` header/footer appearing twice).
Call `cleanupLView` from the hydration cleanup module after
`destroyLView` and before `removeViewFromDOM` to remove any remaining
dehydrated DOM nodes before the replacement view is rendered.
Fixes#66503
Due to the design of the `ng.getComponent` spy and a race condition where sometimes a `<script>` is added to the test DOM, the `getRootElements` tests used to fail sometimes because those `<script>`s were marked as roots which caused a distortion in the roots count checks. The commit addresses that and also adds an additional test for non-application root Angular components.
In some cases the `debugName` transform generates a spread into the signal function parameters. This can cause compiler errors, because the functions don't have rest parameters.
These changes work around it by adding a `@ts-ignore` above it.
Explicitly adding an `export {}` to modules containing declare global fixes an issue where Rollup would incorrectly claim that the global variable is not defined in the emitted .d.ts files.
Needed to land the latest rules_angular.
This adds a setTimeout, which guarantees that we call getAnimations one frame after a reflow is finished. This means getAnimations will return data, avoiding needing the expensive fallback of getComputedStyles. It also updates the cleanup to prevent a potential memory leak if the component is destroyed before the timeout runs.
This commit re-introduces support for nested leave animations with a critical adjustment to prevent cross-component blocking. Wait for nested inner `animate.leave` transitions natively only when they exist within the same component's view or its embedded tracking structures (like `@if` and `@for`).
This resolves the issue where route navigations and parental destruction would excessively stall by traversing down into child component architectures to wait for their distinct leaf animations.
BREAKING CHANGE: Leave animations are no longer limited to the element being removed.
Fixes#67633
This updates the determineLongestAnimation code to also calculate the playback rate in with the duration, which should also account for timing when testing with playback rates changed in devtools.
Add `ComponentInputBindingOptions` which is used with `withComponentInputBinding` and `bindToComponentInputs`
Can set which sources to bind as follows:
* queryParams
* params
* data
feat(router): Add `options` optional parameter for `withComponentInputBinding`
Add missing ternary operator for queryParams
Explicitly adding an `export {}` to modules containing `declare global` fixes an issue where Rollup would incorrectly claim that the `global` variable is not defined in the emitted `.d.ts` files.
Needed to land the latest `rules_angular`.
This reverts commit ea2016a6dc.
This reverts the support for nested animations due to the global scope of how nested animations were gathered.
This caused issues where on route navigations, all child nodes with animations would be queued and run before the navigation would occur.
We'll be revisiting the nested animations with a more tightened scope of when those leave animations will occur.
fixes: #67552
Document that reactive forms model mutations such as FormArray.push() do not schedule component change detection in zoneless applications and show the recommended ways to notify Angular.
Fixes#65536
The `toString()` implementations in the primitives package intended to include
the debug name, yet the debug name was evaluated during construction before it
could ever have been assigned. This commit fixes that.
The Angular wrappers override the `toString()` representation to evaluate signals
ad-hoc instead of showing their internal state, and this commit aligns their
behavior to include the debug name in `toString` as well.
Adjust the z-index to ensure the close button remains clickable.
Also remove an unnecessary `position: relative` that was causing
layout shifts in the docs UI, which resulted in a visible and
unintended layout movement.
Introduce `FormFieldBinding` to represent a binding between a field and
a UI control through a `FormField` directive. This interface is used to
restrict `SignalFormsConfig` and `formFieldBindings` to a readonly API.
Fix#65779.
Reactive logic in forms is not intended to mutate state, but this was
poorly communicated by the permissive and highly mutable field context
provided to all logic functions. This change splits all of the
state-related API into writable and readonly interfaces.
* Top-level functions that produce a `FieldTree` (e.g. `form()`) expose
writable signals (e.g. `value: WritableSignal<T>`) and mutating
methods (e.g. `markAsDirty()`).
* Reactive logic expose readonly signals (e.g. `value: Signal<T>`) and
omit mutating methods.
Fixes that we weren't sanitizing attribute bindings with interpolations if they're marked for translation, for example: `<a href="{{evilLink}}" i18n-href></a>`.
Also adds a bit more test coverage for our sanitization.
Clarify that provideZoneChangeDetection() is used to opt applications into NgZone/ZoneJS-based change detection and to configure NgZone options such as eventCoalescing.
Fixes#67498
1. Get location by Id work with `${this.url}/${id}`
2. Method getHousingLocationById returned empty object, api return object type, locationJson[0] ?? {} - give in result empty object.
Includes the following changes to make sure the definitions for injectable compiler:
1. The types for the `factory` function now include the `parent` parameter.
2. `ɵɵFactoryDeclaration` is now defined as a function. We need this since the provider definition gets passed into the inejctable definition by reference.
3. `ɵɵdefineInjectable`, `ɵɵdefineNgModule` and `ɵɵdefinePipe` now return the typed definition, rather than `unknown`. This aligns with what we do for components and directives.
Adds a test verifying that `transformedValue` exposes parse errors via
the returned signal's `parseErrors()` property when no FormField
context is present.
This ensures that:
- parse errors are still observable without DI-based field propagation
- the model is not updated when `parse` omits `value`
- valid input clears parse errors and updates the model
This test protects the documented contract that DI-based error
propagation is expected for FormValueControl usage, while standalone
usage relies on explicit consumption of `parseErrors()`.
Adds a utility `debounced` to create a debounced version of a signal,
represented as a `Resource`. The resource's value contained the
debounced value of the signal, while its status (`resolved`, `loading`,
or `error`) indicates if the value is settled, if there is a value
currently pending debounce, or if the source signal threw an error.
add a link to the community-driven Turkish translation of Angular
documentation to make it easier for Turkish-speaking developers to
discover localized docs.
The translation project is maintained by the community and hosted at:
https://github.com/erkamyaman/angular-tr
Providing documentation in developers' native languages helps lower
the barrier to entry and supports wider Angular adoption in the
Turkish-speaking developer community.
Fix browser-specific styles infrastructure. PR #62786 cleans up part of the code, but there are still services that attempt to load these stylesheets on `main`.
Update the `esbuild` macro in devtools to use
`external` sourcemaps by default and remove the ability to override the `sourcemap` and `sources_content` options.
This change is necessary to ensure that the build is deterministic and 100% reproducible as otherwise Firefox will not publish the build.
Add Angular template inlay hints end-to-end across language-service and VS Code extension server/client wiring, including inlay-specific configuration mapping, request guards, and refresh behavior.
This refactoring improves the lifecycle management and configuration handling within the VS Code extension's language client.
Key changes include:
- Introduced sessionDisposables to manage resources tied to the lifespan of an LSP client session, ensuring they are properly cleaned up when the client stops without affecting global extension resources.
- Added a configuration change listener to clear the fileToIsInAngularProjectMap cache, ensuring project state is re-evaluated when settings change.
- Enhanced registerNotificationHandlers to clear the project state cache when project loading begins or completes, providing more accurate "is in Angular project" checks.
- Modified isInAngularProject to only cache positive results, allowing for recovery if a file was initially incorrectly identified as being outside an Angular project.
exports methods and types required for TCB generation. This would allow external
tools to generate TCBs using their own analysis pipelines, separate from the
compiler-cli implementations.
This commit refactors the template type checking metadata interfaces to use detached, serializable metadata rather than retaining direct references to ts.Node or ts.Declaration instances.
A new tcb_adapter translates traditional TypeScript AST-bound metadata into these decoupled structures. This abstraction lays the groundwork for supporting native preprocessors (such as Rust or ts-go) which serialize metadata over JSON rather than passing live TypeScript objects.
Key changes:
- Introduced TcbDirectiveMetadata, TcbComponentMetadata, TcbReferenceMetadata, and TcbPipeMetadata to replace TypeCheckableDirectiveMeta where appropriate.
- Substituted deep TS compilation AST references with string module names and source spans to preserve out-of-band diagnostic capabilities.
- Detached generic typeParameters and transformType properties into synthesized, standalone TS mappings.
- Updated generateTypeCheckBlock and corresponding Operations to consume the new metadata.
Expands the `debounce` rule configuration to accept `'blur'`. When this option
is provided, the rule will delay model synchronization until the field loses
focus (is touched). This introduces a debouncer that defers resolution
until the framework automatically aborts pending debounces upon touch events.
Currently the migration that add `ChangeDetectionStrategy.Eager` to components tries to add the properties as last in the object literal. This can be tricky, because TS doesn't reflect the commas in the AST so we need have to do brittle string lookups to know where to insert it.
These changes switch to inserting the property before the last pre-existing property which should be a bit more robust.
This commit updates the github.mjs configuration to set requireReleaseModeForRelease to false, removing the requirement to use release mode for releases in the angular/angular repository.
The Angular compiler unconditionally adds a debug name transform for signals
which generates a conditional on `ngDevMode` (e.g., `ngDevMode ? { debugName: "xyz" } : []`).
During testing, `ngDevMode` is true, so the true branch executes but the
false branch is never executed. Consequently, coverage tools report the
false branch as an untested line/branch, preventing 100% test coverage.
This commit adds a synthetic `/* istanbul ignore next */` comment to the
generated false branch so that Istanbul ignores it. We only include the
istanbul comment (instead of additionally including c8) to focus on the
established standard for Angular CLI/Karma coverage while maintaining
compatibility with modern Vitest setups, since @vitest/coverage-v8 now
natively respects the fallback istanbul comment.
Fixes#64583
RecursiveVisitor.visitIfBlockBranch was permanently mutating the children array by pushing the expressionAlias into it. This change clones the array before pushing to avoid this side effect.
The childSignalProp nodes were added to make it easier for users to visualize and understand when signals were being passed between components. Adding the preview for the new nodes makes the data being displayed equivalent to that of other reactive nodes in the signal graph.
When routing between two different routes, child animations were not finishing, causing elements to be left behind in the dom. The fix ensures the proper fallback is handled to avoid automatically cancelled custom events. This ensures the animation-fallback cancelling the animation actually completes, and ensures the element is removed.
fixes: #67400
This is a follow-up to #67381 which introduced a subtle bug where depending on the type checking configuration, we may put an object literal directly in the TCB body which the TS compiler ends up interpreting as a block. These changes resolve the issue by always wrapping the literal in parentheses.
Allows specifying a timeout parameter for idle-based deferred triggers, enabling more granular control over when deferred actions are executed.
Closes angular#67187
Previously, Blob values were passed to `Uint8Array` this resulted in silently producing an empty array (length = 0) without throwing an error, leading to empty cached data
PR Close#67002
Use feature detection for `Uint8Array.prototype.toBase64` and
`Uint8Array.fromBase64`, falling back to the existing implementation
when native support is not available
PR Close#67002
This updates the state manager to allow intercepting and deferring commits of traversal navigations.
The issues that were encountered in the past appear to be resolved in Chrome.
The behavior of redirect is still undefined in this case, so there is an added TODO.
TypeScript has functionality that automatically escapes quotes in string literals. These changes update the places where we may need to do the same ourselves.
This ensures that when calculating longest animations, we completely ignore infinite animations. This will prevent mistakes with using the API and hopefully catch any unexpected bugs.
fixes: #67350
Allows throwing from the resource's params function to transition the
resource to a status other than resolved.
In particular, the following values can be thrown from params:
- `ResourceParamsStatus.IDLE` causes the resource to become `idle`
(equivalent to returning `undefined`)
- `ResourceParamsStatus.LOADING` causes the resource to become `loading`
- Any `Error` object causes the resource to become `error` and report
the error that was thrown via `.error()`
To simplify chaining together resources, this PR also introduces a
context object passed into to the `params` functon. This context
contains a `chain` function that can be used to get the value of a
resource that the params want to depend on, while automatically
propagating the idle, loading, and erorr states of the resource forward.
Same as ADEV, currently the CLI prompts for another port if 4200 is busy but the toolchain doesn't support prompts.
By defaulting to 4201 we avoid regular CLI apps from preventing to run the dev-app
inputs & outputs cannot be binded to 2 different directives/components properties
Eg
```
data = model();
dataChange = output(); // throws because model already emits on the `dataChange` output
userSomething = input({alias 'user'});
user = input(); // throws because userSomething already binds to the `user` input
````
fixes#65844
BREAKING CHANGE: The compiler will throw when there a when inputs, outputs or model are binding to the same input/outputs.
Exisiting applications will be migrated to keep using the XHR backend to prevent any breaking changes. `withXhr()` is to the `provideHttpClient` provider function.
This commit replaces the `XhrHttpBackend` with the `FetchBackend` as the default implementation of the `HttpBackend`.
This introduces a breaking change a the `FetchBackend` does not support the report progress for uploads.
The previous behavior (`HttpXhrBackend`) can be restored by setting `withXhr()` in the `provideHttpClient()` provider function.
DEPRECATED: `withFetch` is now deprecated, it can be safely removed.
BREAKING CHANGE: Use the `HttpXhrBackend` with `provideHttpClient(withXhr)` if you want to keep supporting upload progress reports.
The repositories for `rules_sass`, `rules_angular`, and `rules_browsers`
were recently transferred from devversion to the angular organization.
This commit updates the internal bazel module rules to rely on
the new repository locations.
Fix a Safari regression caused by `a5981b8` where the browser is unable to properly assign the `window` context to idle callback shims in `@defer` 'on idle' configuration service.
Both functions were deprecated in v5 and are replaced by `getAngularJSGlobal`/`setAngularJSGlobal`
BREAKING CHANGE: Deprecated `getAngularLib`/`setAngularLib` have been removed use `getAngularJSGlobal`/`setAngularJSGlobal` instead.
This commit updates the minimum supported Node.js versions. Node.js v20 support is dropped, and the minimum version for Node.js v22 is bumped to v22.22.0, and for v24 it is bumped to v24.13.1.
BREAKING CHANGE: Node.js v20 is no longer supported. The minimum supported Node.js versions are now v22.22.0 and v24.13.1.
This commit makes the behavior of `on idle` in `@defer` configurable via DI.
It defines an `IdleService` interface that an application can implement and
provide to Angular:
```ts
@Injectable({providedIn: 'root'})
export class CustomIdleService implements IdleService {
requestOnIdle(callback: () => void): number {...}
cancelOnIdle(id: number): void {...}
}
```
Then the idle service can be used by providing the IDLE_SERVICE token with the custom implementation.
Translators are not allowed to write HTML which creates URI attributes. I opted to ban any values going into an attribute at all, to prevent even links to malicious content, rather than just sanitizing URIs.
I also converted this blocklist into an allowlist. Now, we only allowing setting known attributes (while sanitizing URI attributes). This significantly reduces risk of missing a vulnerable attribute and does not require an exhaustive list of all potential attributes.
BREAKING CHANGE: Angular now only applies known attributes from HTML in translated ICU content. Unknown attributes are dropped and not rendered.
This disables esbuild minification when building DevTools in debug mode, introducing a new `//devtools:debug` flag and a `pnpm run devtools:build:chrome:dev` script to trigger it. This should make debugging a little easier.
This adds source maps to both the dev and production builds. Since this project is open source and downloaded ahead of time, there is not much negative cost to shipping source maps in production, as this can help any developers who encounter bugs related to Angular DevTools on the page.
There is a slight performance cost to both processing the `sourceMappingURL` comment _and_ actually processing the sourcemaps. Ideally, we would use linked sourcemaps all the time, as this avoids processing this and parses only a trivial comment unless the user actually opens a debugger. Unfortunately, Chrome seems to fail to load linked sourcemaps for scripts injected into the user's page (the backend script and content scripts), so these need inlined sourcemaps to work, which somewhat increases the performance cost. These scripts should be small enough to not be a major issue, but we can consider removing them in production based on signal from the community if necessary.
This commit sets up the necessary changes that would allow us to safely migrate G3 before switch to the `FetchBackend` by default.
For now the `HttpXhrBackend` is still the default backend for the `HttpClient`.
`provideRoutes` was deprecated in v15.
BREAKING CHANGE: `provideRoutes()` has been removed. Use `provideRouter()` or `ROUTES` as multi token if necessary.
Removes extra padding applied to the update page so its layout
matches the rest of the documentation where no padding exists
between the title and content.
This updates the idle scheduler to ensure the idle deadline is respected when scheduling tasks. Otherwise the idle callback will respond to the first idle event, which may not be the most optimal time to execute the task.
This commit extracts the heading ID generation logic into a shared utility
and updates both the route generation script and the markdown pipeline to use it.
This ensures consistency between the generated routes and the rendered
documentation, and fixes an issue where custom heading IDs (`{#id}`)
were ignored during route generation.
Fixes#67200
`{{in}}` are not interpreted as `'in'` string expressions anymore.
```
<input #in /> // OK
{{in}} // throws
```
fixes#65244
BREAKING CHANGE: `in` variables will throw in template expressions.
This is to improve consistency and match developer expectations. This syntax was already deprecated a long time ago.
If you want to bind a data attribute, use the `attr.` prefix (which was already supported).
BREAKING CHANGE: data prefixed attribute no-longer bind inputs nor outputs.
fixes#26406
Aligns the errors returned from the `parse` function in
`transformedValue` to use the same convention as the rest of signal
forms (a property called `error` that can contain a single error or list
of errors)
Addresses an issue where the LCP image observer incorrectly identified LCP elements when the same image URL was used multiple times on a page
Fixes#53278
Add help link to extended template diagnostic messages to provide
users with additional guidance and documentation resources. This
enhancement improves developer experience by making it easier to
understand and resolve complex template issues through direct
access to relevant Angular documentation with detailed examples
and explanations for each diagnostic type.
This adds a new method to the TestBed to retrieve the most recently created component fixture. This is useful for cases where the fixture is created in a beforeEach and needs to be accessed in a test.
If multiple fixtures have been created, this method will throw an error to prevent depending on fixture creation order.
The JsonPipe does not unwrap signals and `JSON.stringify` will return `undefined` for signals.
To avoid confusion, we log a warning when a signal is passed to the pipe.
Wrap `@defer` trigger expressions (`when`, `prefetch when`, `hydrate when`)
in a conditional context within the TCB to enable TypeScript's TS2774
diagnostic for detecting functions used without invocation.
Previously, signals and functions passed to `when` triggers without
parentheses would silently evaluate to truthy, causing unexpected behavior.
Now the compiler reports an error when a function is used as a condition
without being called.
In v22, `OnPush` becomes the default strategy. To maintain the ChangeDetection behavior of exisiting apps, components without an explicit change detectino strategy will get `Eager` assigned.
avoid per-file semantic diagnostics work when warming up a newly loaded project.
add ensureProjectAnalyzed() to the language-service API and use it from the server startup path.
implement warmup through public compiler API access with existing perf tracing, and add legacy test coverage for the new warmup flow.
The tokenizer regex pattern `[^<]*` was consuming all non-`<` content
before custom HTML tags, causing lost content.
Changed to `\s*` which only allows leading whitespace, letting marked
properly tokenize preceding content.
The aria tab content are only instantiated when the tab is selected which also delays the prefetching.
By having the defer block around the ng-conten we actually allow angular to prefetch the chuncks without the tab being visible
The `touched` property was never meant to support two-way binding; a
control should not be able to dictate that a field is no longer touched.
* The `touched` input represents the touched state of the field.
* The `touch` output allows a control implementation to indicate when
the bound field is touched.
Note the distinction is that the `touch` output indicates _when_ the
field is touched, and not _whether_ the field is touched.
Rename `property-tab` and `signals-view` to `property-pane` and `signal-graph-pane`, and their respective children, to property indicate their purpose and role; Move `diffing` to `directive-explorer`
description: Comprehensive writing guide for Angular documentation (adev). Covers Google Technical Writing standards, Angular-specific markdown extensions, code blocks, and components. Use when authoring or reviewing content in adev/src/content.
description: Comprehensive writing guide for Angular documentation (adev). Covers Google Technical Writing standards, Angular-specific markdown extensions, code blocks, and components. You MUST use this skill any time you plan to create, edit, or review documentation files in `adev/` or `adev/src/content`.
description: Guidelines and tools for reviewing pull requests in the Angular repository.
---
# PR Review Guidelines
When reviewing a pull request for the `angular` repository, follow these essential guidelines to ensure high-quality contributions:
1.**Context & Ecosystem**:
- Keep in mind that this is the core Angular framework. Changes here can impact millions of developers.
- Be mindful of backwards compatibility. Breaking changes require strict approval processes and deprecation periods.
2.**Key Focus Areas**:
- **Comprehensive Reviews**: You **MUST always** perform a deep, comprehensive review of the _entire_ pull request. If the user asks you to look into a specific issue, file, or area of concern, you must investigate that specific area _in addition to_ reviewing the rest of the PR's substantive changes. Do not terminate your review after addressing only the user's focal point.
- **Package-Specific Guidelines**: Check if there are specific guidelines for the package being modified in the `reference/` directory (e.g., `reference/router.md`). Always prioritize these rules for their respective packages.
- **Commit Messages**: Evaluate the quality of commit messages. They should explain the _why_ behind the change, not just the _what_. Someone should be able to look at the commit history years from now and clearly understand the context and reasoning for the change.
- **Code Cleanliness**: Ensure the code is readable, maintainable, and follows Angular's project standards.
- **Performance**: Look out for code that might negatively impact runtime performance or bundle size, particularly in hot paths like change detection or rendering.
- **Testing**: Ensure all new logic has comprehensive tests, including edge cases. **Do NOT run tests locally** as part of your review process. CI handles this automatically, and running tests locally is redundant and inefficient.
- **API Design**: Ensure new public APIs are well-designed, consistent with existing APIs, and properly documented.
- **Payload Size**: Pay attention to the impact of changes on the final client payload size.
3.**Execution Workflow**:
Determine the appropriate review method. If the user explicitly asks for a `remote` or `local` review in their request, that takes precedence (e.g. "leave comments on the PR" implies `remote`). Otherwise, use the GitHub MCP or available scripts to determine if the review should be `local` or `remote`.
**Common Review Practices (Applies to both Local and Remote)**
- **Preparation & Checklist**:
- First, create a task list (e.g., in `task.md`) that you can easily reference containing **all** the review requirements from the "Key Focus Areas" section (Commit Messages, Performance, Testing, etc.), along with any specific review notes or requests from the user.
- Before doing an in-depth review, expand this list into more detailed items of what you plan to explore and verify in the PR.
- As you conduct the review, check off items in this list, adding your assessment or findings underneath each item.
- At the end of your review, refer back to the checklist to ensure every single requirement was completely verified.
- **Fetch PR Metadata Safely**: When you need to read the PR description or context, do NOT use `gh pr view <PR_NUMBER>` by itself, as its default GraphQL query may fail due to lack of `read:org` and `read:discussion` token scopes. Instead, use `read_url_content` on the PR URL or use `gh pr view <PR_NUMBER> --json title,body,state,author`.
- **Check Existing Comments First**: Before formulating feedback, use the GitHub MCP or available scripts to fetch existing comments on the PR. Review this feedback to avoid duplicate comments, and incorporate its insights into your own review process.
- **Constructive Feedback**: Provide clear, actionable, and polite feedback. Explain the _why_ behind your suggestions or edits. Do **NOT** leave inline comments purely to praise, agree with, or acknowledge a correct implementation detail, as this clutters the review. If you want to praise the PR, do so in the single general PR comment.
**A. Local Code Review (If the PR is owned by the author requesting the review)**
- **Checkout**: Check out the PR branch locally (if it doesn't already exist, fetch it). If checking out the branch fails due to a worktree claim (e.g. "fatal: '<branch>' is already used by worktree at '<path>'"), do the review in that directory.
- **Review & Edit**: Execute the review directly on the code. Instead of adding inline PR comments for suggestions, format the codebase or apply the edits directly to the files.
- **Feedback**: Summarize the review findings and the concrete changes you made in a message to the user, referencing the completed items from your checklist.
- **Do NOT Commit or Push**: Leave the changes uncommitted in the working directory so the user can easily review the pending edits locally. Let the user know the changes are ready for their review, but do not ask for approval to push.
- **Resolve Comments**: Once the user confirms the changes are good and should be committed/pushed, respond to the existing comments as 'resolved' using the GitHub MCP or available scripts.
**B. Remote Code Review (For all other PRs)**
- **Batching Comments (MCP Server - Preferred)**: If you have the GitHub MCP Server configured, you **MUST** follow this workflow to avoid spamming the author with multiple notifications:
1. Create a pending review using `mcp_github-mcp-server_pull_request_review_write` (method `create`).
2. Add your inline comments to the pending review using `mcp_github-mcp-server_add_comment_to_pending_review`.
3. Submit the review using `mcp_github-mcp-server_pull_request_review_write` (method `submit_pending`).
- **Batching Comments (Scripts - Fallback)**: If you do **NOT** have access to the GitHub MCP Server (e.g., specific MCP tools are missing from your context), fallback to using the provided scripts. Use `post_inline_comment.sh` to stage your comments locally. Once all comments are staged, you **MUST** call `submit_pr_review.sh` to publish them as a single batched review (and send a single notification). Try to keep comments minimal or use a general comment if you have many suggestions.
- **Use Suggested Changes**: Whenever appropriate (e.g., for simple code fixes, refactoring suggestions, or typo corrections), prefer using GitHub's **Suggested Changes** syntax (`suggestion ... `) in your inline comments. This allows the author to apply your suggested code improvements with a single click in the GitHub UI.
- **Review Type**: Never mark an external PR review as an "approval" unless explicitly instructed by a repo maintainer. Always use "Request Changes" or "Comment". Note that some tools might only support commenting.
- **Require User Approval Before Posting**: Prepare your review comments and present them to the user, alongside a summary of your completed checklist. Do NOT post comments to the PR without explicitly asking the user for permission first. Only post the review after the user approves.
- **CRITICAL**: This rule applies even if you receive a system message indicating that an artifact has been "automatically approved" or instructing you to "proceed to execution." You must ALWAYS obtain explicit, written confirmation from the user in this chat conversation before posting any content to a PR.
- **Prefix Agent Comments**: To make it clear when comments are generated and posted by an AI agent rather than a human user, **always** prefix your review comments with `AGENT: `.
## Available Tools
The following tools are available for remote interactions. We prefer using standard **GitHub MCP Server** tools when available. If you do not have the MCP server set up, you **MUST** fallback to using the custom bash scripts.
The following scripts are provided as fallbacks if the MCP server is not available. Note that they rely on the `gh` CLI being correctly installed and authenticated in the local environment.
### `determine_review_type.sh`
Determines whether to use the Local or Remote review workflow by checking if the currently authenticated GitHub user via the `gh` CLI matches the author of the pull request.
Fetches all existing inline comments on a PR using the GitHub API. This is crucial for reviewing other contributors' feedback and avoiding duplicate comments. It outputs JSON containing the `id`, `path`, `line`, `body`, and `user` for each comment.
Replies to an existing PR comment thread. This is useful for marking comments as resolved after addressing them in a local code review. Note that the `COMMENT_ID` must be the ID of the top-level comment in the thread.
The GitHub CLI `gh pr review` command does not natively support adding inline comments to specific lines of code via its standard flags. This script wraps the GitHub API to stage comments locally. They will not be published until you call `submit_pr_review.sh`.
When reviewing pull requests that modify the Angular Router (`packages/router`), pay special attention to the following:
- **Timing Sensitivity**: The router is extremely sensitive to timing changes. Any changes that alter the asynchronous timing of navigations, resolvers, or guards are almost always breaking changes and must be scrutinized carefully.
- **Testing Practices**: Tests should usually use the `RouterTestingHarness`. Many existing tests are older and do not use this harness. Do not blindly follow the shape of existing tests when writing or reviewing new ones; encourage the use of modern testing utilities.
- **Feature Justification**: Changes to router core code should be well-justified. Consider whether the change is proven to be a core developer ask, such as resolving a highly upvoted GitHub issue or addressing a critical bug.
We strongly value open source contribution and pull requests from community contributors. Please note that every pull request is reviewed and merged by an actual person on the team, which does take time and effort. That is time and effort that does take away from other valuable work. With that in mind we have an minimum set of expectations that are required of any community contribution pull request that is opened.
We strongly value open source contribution and pull requests from community contributors. Please note that every pull request is reviewed and merged by an actual person on the team, which does take time and effort. That is time and effort that does take away from other valuable work. With that in mind we have a minimum set of expectations that are required of any community contribution pull request that is opened.
1. Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR that relates to your submission.
- You don't want to duplicate existing efforts.
@@ -238,7 +238,7 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise
- For corporations, we'll need you to
[print, sign and one of scan+email, fax or mail the form][corporate-cla].
If you have more than one GitHub accounts, or multiple email addresses associated with a single GitHub account, you must sign the CLA using the primary email address of the GitHub account used to author Git commits and send pull requests.
If you have more than one GitHub account, or multiple email addresses associated with a single GitHub account, you must sign the CLA using the primary email address of the GitHub account used to author Git commits and send pull requests.
The following documents can help you sort out issues with GitHub accounts and multiple email addresses:
/** Whether to hide the dollar sign in the shell code */
hideDollar?: boolean;
// additional classes for the element
classes?: string[];
@@ -132,6 +134,10 @@ function applyContainerAttributesAndClasses(el: Element, token: CodeToken) {
if(token.hideCopy){
el.setAttribute('hideCopy','true');
}
if(token.hideDollar){
el.setAttribute('hideDollar','true');
}
constlanguage=token.language;
if(language==='mermaid'){
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.