The export statement was incorrectly placed inside the JSDoc comment block,
and there was a stray text fragment "nstead." from the deprecation message.
This moves the export statement outside the comment and removes the stray text.
`I18nSelectPipe.transform()` called `mapping.hasOwnProperty()` directly,
which fails in two edge cases:
- Mappings created with `Object.create(null)` have no prototype and
therefore no `hasOwnProperty` method, causing a TypeError at runtime.
- Mappings where a key literally named `hasOwnProperty` shadows the
built-in method return incorrect results silently.
Replace both call sites with `Object.hasOwn(mapping, key)`, which
delegates through `Object` directly and is immune to both issues.
Add two regression tests that demonstrate the broken behaviour before
the fix and pass after it.
Previously I intentionally kept the lexer as generic as possible so that block detection can happen later. However, since #62644 we detect blocks in the lexer so we might as well normalize them there so all the upstream code doesn't have to account for things like whitespace.
The previous fix for GHSA-692r-grfm-v8x7 was incomplete because it rejected script tags only when locating an explicit host element. Dynamic component instantiation can also infer the host element from the component selector.
Move the script-host rejection to the point where ComponentFactory has resolved the host element for either path, so createComponent rejects script hosts consistently.
The AnimationClassBindingFn type was too restrictive, only allowing `string | string[]`. However, the runtime (`getClassListFromValue`) safely handles `undefined` and `null` values by treating them as no animation.
This change updates the type to allow `undefined` and `null`, which is consistent with other class/style bindings in Angular and avoids requiring workarounds (like empty strings) in host bindings.
Added a compliance test case to verify that `[animate.enter]` with a potentially `undefined` value compiles correctly.
Enable foreign components to receive and propagate contextual data
across framework boundaries.
Previously, foreign render functions only accepted component properties,
and foreign content projection instructions (`ɵɵforeignContent` /
`ɵɵforeignContentFn`) did not provide any mechanism to expose foreign
framework context to projected Angular embedded views.
With this change:
- Update `ForeignRenderFn` and `ForeignComponent` interfaces to accept
an optional context parameter and an optional `GET_CONTEXT` symbol
method.
- Introduce `FOREIGN_CONTEXT` injection token and
`provideForeignRootContext` helper to configure root context in
Angular's DI hierarchy.
- Update `ɵɵforeignComponent` instruction to resolve `FOREIGN_CONTEXT`
from the injection tree and pass it to the foreign component's render
function.
- Update `ɵɵforeignContent` and `ɵɵforeignContentFn` instructions to
wrap embedded view creation with a `ForeignContextInjector` when
`GET_CONTEXT` is present.
Furthermore, foreign render functions are no longer run inside an
Angular injection context, since it's expected they use the foreign
context support directly.
PR Close#69502
the toSignal function received a debugName option in 0812ac3bec,
but was not covered by the signalMetadataTransform which sets the debugName in dev mode
automatically.
Transition parameterless `@content` projection in foreign components
from eager DOM creation to lazy evaluation. Previously, projecting
content into a foreign component eagerly instantiated the embedded view
and created DOM nodes, causing unnecessary resource consumption if the
content was hidden or unmounted.
With this change, runtime content instructions (`ɵɵforeignContent` and
`ɵɵforeignContentFn`) pass lazy producer callbacks directly through the
foreign component's configured `contentAdapter`. View creation and
teardown registration occur lazily when the external framework evaluates
the adapted producer.
`foreignImport` now requires a third argument, `contentAdapter`,
specifying how Angular content producer callbacks are adapted for the
target external framework.
Currently, signal migration schematics in best effort mode doesn't do a very good job migrating input writes when there is a nested property access in templates.
In event handlers, no attempt is made to migrate a nested access in the left-hand-side of assignments or anything in their right-hand-side. E.g., nothing will happen here:
`(ngModelChange)="inputD.prop = $event + inputF"`.
Additionally, when a migration attempt is made, parentheses are often incorrectly placed on the parent, both in event handlers and two-way bindings:
`(ngModelChange)="inputC = $event"` is migrated to `(ngModelChange)="inputC = $event()"`.
`[(ngModel)]="inputB.prop.prop"` is migrated to `[(ngModel)]="inputB.prop().prop"`.
When `rootDir` was set in a project's tsconfig (e.g. `rootDir: "src"`),
tsurge-based migrations would fail because `projectRoot` was derived from
`rootDir`, causing `rootRelativePath` to be computed relative to `src/`
instead of the workspace root. This produced paths like `app/app.ts`
instead of `src/app/app.ts`, which the DevKit tree could not resolve.
Fix by overriding `info.projectRoot` to `absoluteFrom(info.program.getCurrentDirectory())`
immediately after program creation, ensuring workspace-relative paths are
used for all tree updates.
When partial declarations are not preprocessed to AOT by the linker, the `ngDeclareComponent`
call causes them to be compiled ad-hoc. In this mode, NgModule imports in standalone components
would be dropped, deviating from the linker. This commit changes the ad-hoc compilation of
component declarations to pass the NgModule imports along just like the linker does.
Fixes#69451
Initialize `zoneSymbolEventNames` and `patches` with `Object.create(null)` instead of `{}`.
This is a hardening change rather than a fix for an exploitable vulnerability. Calling `addEventListener('__proto__', fn)` is not directly attacker-controlled; its presence already implies an application bug. However, if such a call does occur, the current implementation can behave unexpectedly depending on the environment.
For `zoneSymbolEventNames`, accessing `zoneSymbolEventNames['__proto__']` on a plain object invokes the inherited `__proto__` accessor and returns `Object.prototype`, which is truthy. This causes `prepareEventNames()` to be skipped, leaving `symbolEventName` undefined and eventually leading to a runtime error when `window['undefined'] = []` is executed.
In Node.js environments running with `--disable-proto=throw`, the assignment:
```ts id="z8n4qm"
zoneSymbolEventNames['__proto__'] = {};
```
throws immediately because it triggers the disabled `__proto__` setter.
The `patches` registry has a similar issue. A `__proto__` key passed to `__load_patch()` bypasses the duplicate-patch check and reaches:
```ts id="f3v7kx"
patches['__proto__'] = fn(...);
```
which invokes the `__proto__` setter and changes the prototype of the `patches` object.
Using `Object.create(null)` removes the inherited `__proto__` accessor entirely, causing these keys to behave like ordinary properties rather than interacting with JavaScript's prototype machinery.
As part of this change, `patches.hasOwnProperty(name)` is also updated to:
```ts id="n2c8wp"
Object.prototype.hasOwnProperty.call(patches, name)
```
since null-prototype objects do not inherit `hasOwnProperty`.
`model()` signals are special because they combine a signal input with a writable output through an internal `OutputEmitterRef`. During upgrade, `setupOutputs()` subscribes to that emitter to keep Angular → AngularJS two-way binding working.
The issue was that `updateInput()` could overwrite the signal property directly when `isSignal` was `false` (which happens in JIT mode and when `unsafelyOverwriteSignalInputs` is enabled). Once that happened, the original `OutputEmitterRef` was lost, so the two-way binding stopped working.
The fix detects `model()` signals at runtime by checking for both `[SIGNAL]` and a writable `.set()` method, which distinguishes them from read-only `input()` signals. When those traits are present, updates are always applied through `applyValueToInputSignal()` instead of replacing the property directly, regardless of the `unsafelyOverwriteSignalInputs` setting.
Fixes#60599
Without this change, components that use RouterLinkActive in multiple
contexts (e.g. both a navigation menu and body content) are forced to
branch the template for every conditional input:
@if (activeClass) {
<a [routerLink]="href" [routerLinkActive]="activeClass"
[routerLinkActiveOptions]="activeOptions"
[ariaCurrentWhenActive]="ariaCurrent">
<ng-content />
</a>
} @else {
<a [routerLink]="href"><ng-content /></a>
}
Every additional input multiplies the branching, and each @if/@else
injects unwanted comment nodes into the DOM. There is no way to
conditionally attach a directive in Angular templates, making imperative
TypeScript instantiation the only alternative.
Accepting null/undefined collapses this to a single template branch:
<a [routerLink]="href"
[routerLinkActive]="activeClass"
[routerLinkActiveOptions]="activeOptions"
[ariaCurrentWhenActive]="ariaCurrent">
<ng-content />
</a>
When activeClass is undefined (e.g. in content areas), the directive
stays mounted but applies no CSS classes. When it is a string (e.g. in
the navigation), normal active-class behavior applies — no branching, no
extra DOM nodes, no TypeScript workarounds.
- `routerLinkActive`: null/undefined now sets an empty class list.
- `routerLinkActiveOptions`: null and undefined are treated differently:
- undefined → falls back to the default subset match ("not set")
- null → explicit opt-out, link is never considered active
Closes#66233
Preserve explicit referrer policy when the service worker reconstructs asset requests for cache-busted and redirected asset fetches.
For example, an application can load a script or image with referrerPolicy: 'same-origin' or 'origin' to limit referrer data. Dropping that policy can expose more of the current URL to that resource host.
Preserve referrer metadata when the service worker reconstructs asset requests for cache-busted and redirected asset fetches.
For example, an attacker with access to asset host logs could receive a reset token embedded in a page URL if the reconstructed request falls back to default referrer behavior instead of carrying referrer: ''.
`parseHostBindings` throws plain `Error`s for malformed host bindings
(e.g. a property binding with a non-static value, as can happen while
editing in the language service). These were uncaught during directive
analysis, crashing the compiler and the Angular Language Service.
Wrap the call and surface the error as a `FatalDiagnosticError` so it
becomes a diagnostic and analysis can complete normally.
Fixes#69106
A custom FormValueControl only participates in debounce('blur') if it emits
the touch output on the native blur event. This was undocumented, and the
touch name reads like a focus event, so users wired it to (focus) and
blur-based debouncing silently did nothing.
Add a dedicated guide section with a working example, link the debounce API
reference to it, and clarify the touch JSDoc that it must fire on blur, not
focus.
Fixes#69370
Adds a 'Chaining resources' section to the resource guide covering:
- Basic usage of chain() to depend one resource on another
- Status propagation for all ResourceStatus values (idle, loading,
reloading, error, resolved, local)
- Chaining vs reading .value() directly, shown as an avoid example
- Guidance on passing the chained value directly as params
Also adds an @see link from ResourceParamsContext to the new section.
Closes#69329
Adds an error reference page for NG05102 (UNSUPPORTED_EVENT_TARGET) explaining
what triggers it and how to fix it. Also marks the error code as negative (-5102)
so that in dev mode the error message automatically links to the new guide page
on angular.dev/errors, consistent with other documented runtime errors.
Skip HttpTransferCache serialization for HTTP responses that contain a
Set-Cookie header.
Cookie-setting responses commonly represent session-specific,
user-specific, or security-sensitive state. Serializing their bodies into
SSR TransferState can embed sensitive data into the generated HTML, where
it may be reused during hydration or replayed by a shared cache/CDN.
Fixes a minor issue where the `preload` function in `injectAsync` might cause an uncaught promise error.
I also fixed that in `onIdle` we were passing the wrong function into `assertInInjectionContext`.
Adds a new error reference page for NG05101 (NO_PLUGIN_FOR_EVENT),
which is thrown when no registered EventManagerPlugin supports the
event name passed to addEventListener. The page covers the two common
causes: a typo in the event binding and a missing plugin provider.
After #68581 graduated the Signal Forms APIs to public API and #68654 removed
the experimental warnings from the Signal Forms documentation in adev, the
package READMEs still framed the API as experimental.
Update `packages/forms/signals/PACKAGE.md`: drop the experimental title and
intro, remove the now-shipped entries from "Not yet supported" (interop with
reactive/template forms and strongly-typed binding to UI controls), and remove
the remaining experimental and exploratory wording from the FAQ.
Update `packages/forms/PACKAGE.md`: it listed only two ways to build forms
(reactive and template-driven). Add signal forms as the third.
Fixes#68724
Previously, the modelContext truthiness check could be bypassed via DOM
clobbering (e.g. `<form id="modelContext">`), causing a truthy HTMLElement
to pass the guard and then throw when `registerTool` was called on it.
Replace the truthiness check with a duck-type check that asserts
`registerTool` is a function, rejecting both absent and clobbered values.
Add handling in navigation for creating and destroying injectors scoped
to `ActivatedRoute` life.
The code for creating the injectors is certainly more complicated
than it _could_ be since there's no actual feature built around this yet.
Keeps as much implementation code tree-shakeable as possible:
Raw size: +764 bytes
Gzipped size: +182 bytes
This commit addresses a scaling issue in the signal dependency graph where
the detection of duplicate dependency links would perform a linear scan across
all consumer links of all producers. The linear scan is replaced with a version
comparison of the dependency edge against the current epoch; if they are
equal the existing dependency edge is known to be valid in this epoch. This means
that the link won't be eligible for removal and therefore doesn't have to be
recreated.
`COMMENT_DISALLOWED` is matched globally, so overlapping delimiter
sequences are skipped: `<!-->` only escapes the leading `<!--` and
leaves a live `-->` that can close a programmatically created comment
node early. Drop the `^` anchors so a standalone `>`/`->` is escaped
wherever it appears, which neutralizes the trailing delimiter left
behind by an earlier match.
Adds support for `@Input` transform functions in isolated declarations mode (`emitDeclarationOnly: true`), allowing components and directives to specify `transform` functions without triggering fatal compiler errors.
Synthesizes the `ngAcceptInputType_` write type syntactically:
- For referenced functions (`transform: booleanAttribute`), emits `Parameters<typeof booleanAttribute>[0]`, relying on downstream template type checking to resolve the type.
- For inline functions (`transform: (v: string) => boolean`), extracts `parameters[0].type` directly from the local TypeScript AST.
Removes restrictions around using external references and local directives in `hostDirectives` under isolated declarations mode (`emitDeclarationOnly: true`).
By wrapping the host directive reference in a `WrappedNodeExpr`, TypeScript's declaration emitter seamlessly emits `typeof hostReference.node`, preserving existing imports or local identifiers exactly as authored. Also adds support for translating `PropertyAccessExpression` inside `WrappedNodeExpr` into `QualifiedName` for `.d.ts` emission, ensuring namespace imports (`import * as n from './dir'`) are preserved correctly.
Mark the iframe `credentialless` attribute as security-sensitive so dynamic
bindings are handled consistently with other iframe attributes that affect the
initial navigation, such as `sandbox`, `allow`, `referrerPolicy`, `csp`, and
`fetchPriority`.
Because `credentialless` must be present before the iframe starts loading to
affect the navigation’s credential mode, late dynamic updates can leave the final
DOM looking correct while the initial request was not loaded credentiallessly.
Fixes that when a listener unsubscribes from an `output` within its own callback, it was preventing subsequent listeners from running.
These changes fix the issue by not mutating the array while the emit loop is running, but replacing the listener with `null` and coming back later to remove it.
Fixes#69325.