Commit Graph

38148 Commits

Author SHA1 Message Date
Matthieu Riegler 49f4e1573b ci: exclude markdown files from requiring dev-infra review
613c51e wasn't enough to exclude dev-infra

(cherry picked from commit d364c83c44)
2026-08-18 16:38:49 +00:00
Kristiyan Kostadinov 44137117b3 fix(core): replace all hasOwnProperty usages with Object.hasOwn
We keep getting PRs that target single usages of `hasOwnProperty` and we have ~100 of them. These changes aim to address the issue centrally by swapping out all the instances and adding a lint rule against introducing new ones.

(cherry picked from commit 732e505018)
2026-08-18 16:17:23 +00:00
arturovt 85f12a5a13 fix(core): stop running further effects once one destroys the view mid-flush
When a view has more than one effect scheduled to run, and one of them
destroys the view (e.g. by calling `componentRef.destroy()`), the
remaining effects in that same flush could still run afterward,
against a view that no longer exists. In some cases this crashed
outright with `TypeError: view[EFFECTS] is not iterable`.

Here's why: `runEffectsInView` walks a view's effects in a `for...of`
loop, wrapped in an outer `while` loop that re-checks for any effects
that became dirty as a side effect of ones that already ran. When an
effect destroys its view, `view[EFFECTS]` gets set to `null` as part
of tearing the view down.

First attempt checked for that inside the `for...of` loop, before each
effect runs. That covers a sibling effect later in the *same* pass,
but misses a second case: if the effect that destroys the view *also*
dirties another effect on that same view in the process (e.g. by
writing a signal the sibling depends on), the outer `while` loop sees
`HasChildViewsToRefresh` set and tries to restart — and immediately
crashes re-entering `for (const effect of view[EFFECTS])` on a
now-null value, before the in-loop check ever gets a chance to run.

Reproduced that exact crash with a test first: two effects on one
view, the second one writes a signal the first depends on and then
destroys the view in the same call — confirmed it throws before
touching the fix.

Fixed by checking right after `effect.run()` instead of before it,
covering both cases in one place: the remaining effects in the current
pass, and the loop trying to restart afterward. As soon as one effect
destroys the view, nothing else runs against it again.

This is intentionally narrow in scope. An earlier version of this fix
also tried to guarantee that `onCleanup()` callbacks still ran even
when registered after an effect destroyed its own view. That's been
dropped — destroying your own view and then continuing to register
more work for it isn't something the framework should have to paper
over. If you need to do both, register `onCleanup` first, then
destroy.

(cherry picked from commit c658d73210)
2026-08-18 15:59:17 +00:00
aminesbdev 886da9780f docs: update naming-conventions skill
(cherry picked from commit 560d3f0412)
2026-08-18 15:58:48 +00:00
Alon Mishne 223f25ff37 Revert "fix(router): limit protocol-relative URL handling to serialization"
This reverts commit 435f8b2b8b.

(cherry picked from commit 292991e2df)
2026-08-18 15:58:17 +00:00
Angular Robot f61f2d0500 build: lock file maintenance
See associated pull request for more information.
2026-08-18 08:56:26 -07:00
Matthieu Riegler 68a644d648 ci: add local skills to the fw-general scope
They were caught by dev-infra which isn't the best scope for the imho

(cherry picked from commit 613c51e324)
2026-08-18 15:54:20 +00:00
arturovt b3c78a5081 fix(common): preserve literal key union in KeyValuePipe.transform()
Previously, when you passed an object typed like
Record<'a' | 'b', number> into the `keyvalue` pipe, TypeScript would
"forget" that the keys could only ever be 'a' or 'b', and just tell
you the key was a plain `string` instead. So code like this used to
fail to compile, even though it's correct:

```ts
  const input: Record<'a' | 'b', number> = {a: 1, b: 2};
  const result = pipe.transform(input);
  const key: 'a' | 'b' = result[0].key; // error: string is not 'a' | 'b'
```

This happened because the pipe has multiple overloaded versions of
transform(), and TypeScript checks them top to bottom, using the
first one that matches. The "number keys" overload was listed first,
and it happened to also match string-keyed objects by accident, so
it "won" before the correct "string keys" overload ever got a
chance to run.

The fix just reorders those two overloads so the string-keys one is
checked first. Nothing about runtime behavior changes — objects with
actual numeric keys (e.g. Record<1 | 2, string>) still correctly
report their keys as plain `string`, matching what Object.keys()
really returns at runtime.

(cherry picked from commit 46d2cb7ff0)
2026-08-17 22:01:28 +00:00
Jaime Burgos 3ddcb1a101 fix(platform-browser): disallow event handler attributes in Meta
Prevent arbitrary MetaDefinition properties from writing on* handlers directly to meta elements. Browser events can execute these handlers, including on meta elements rendered in the document body.

(cherry picked from commit 6f9a6bea50)
2026-08-17 21:59:53 +00:00
Shayan 14fbe04612 fix(language-server): recover project for external templates in solution-style workspaces
In a composite/solution-style workspace (e.g. an Nx monorepo, where an
app's tsconfig.json only contains project references), TypeScript can
never resolve a config file for an HTML file, since HTML files are not
listed in any referenced project. angular/vscode-ng-language-service#2165
worked around this in onDidOpenTextDocument by briefly opening the
sibling TS file so the right project loads when a template is opened
first.

However, getDefaultProjectForScriptInfo - the recovery path used by
getLSAndScriptInfo and onDidChangeTextDocument when a script info has no
configured project - did not receive the same workaround. When an open
template loses its project association (e.g. its component file is
closed and the project graph updates), every subsequent request on the
template fails with "No config file" and returns null indefinitely,
until the user manually reopens the component file.

Apply the same sibling-TS best effort in getDefaultProjectForScriptInfo,
and additionally attach the template's script info to the configured
project of its component when the config lookup still comes back empty
(openClientFile does not repeat the config lookup for already-open
files).

Also skip the sibling lookup when the .ts file does not exist, so
non-component HTML files (e.g. src/index.html) do not trigger an
open/close and config search that cannot succeed.

Fixes #69768

(cherry picked from commit 3f8d9d6ea6)
2026-08-17 21:59:07 +00:00
Nikita Barsukov 3a82a16314 docs: use transformedValue in Forms | Custom Controls | Value transformation section
The "Value transformation" section taught readers to hand-roll
transformation with `linkedSignal()` and a manual parse method, even
though `@angular/forms/signals` ships `transformedValue()` for exactly
this case. Readers ended up with a weaker version of a feature the
framework already provides — notably, no parse error reporting.

Rewrite the section around `transformedValue()` and document the parts
the manual pattern could not cover: returning `{error}` from `parse` to
surface parse errors on the field's `errors()`, and `reset()` clearing
them. This also makes good on the cross-reference from the validation
guide, which pointed here for parse error details the section never
covered.

Fixes #70206

Co-authored-by: Matthieu Riegler <kyro38@gmail.com>
(cherry picked from commit 182c371d82)
2026-08-17 21:58:18 +00:00
splincode 1e53aa0b38 refactor: correct typos in comments, docs, and error messages
Fix misspellings found across multiple packages:

- `paramters` → `parameters` (utils.spec.ts)
- `directve` → `directive` (typecheck/context.ts)
- `subscriper` → `subscriber` (zone.js rxjs test)
- `swich` → `switch` (adev animation parser test)
- `subscribtion` → `subscription` (forms/abstract_model.ts)
- `lifecyle` → `lifecycle` (ng-devtools-backend hooks)
- `compatability` → `compatibility` (tree-visualizer.ts)
- `indentifier(s)` → `identifier(s)` (compiler-cli shared.ts, i18n_helpers.ts, declaration_only_emission_spec.ts)
- `identifer` → `identifier` (platform-browser shared_styles_host.ts)
- `prcess` → `process` (standalone-migration to-standalone.ts)

(cherry picked from commit d35c17d393)
2026-08-17 21:57:09 +00:00
splincode 1ee3172d1d refactor(localize): replace any with unknown in messages and translations utils
Replace unsafe `any` type annotations with `unknown` across the localize
utility layer to improve type safety and catch potential type errors at
compile time rather than at runtime.

Changes in `messages.ts`:
- `ParsedMessage.substitutions`: `Record<string, any>` → `Record<string, unknown>`
- `parseMessage` parameter `expressions`: `readonly any[]` → `readonly unknown[]`
- Local `substitutions` variable: `{[key: string]: any}` → `Record<string, unknown>`

Changes in `translations.ts`:
- `isMissingTranslationError` parameter: `any` → `unknown`, with proper
  narrowing (`typeof e === 'object' && e !== null`) before property access
- `MissingTranslationError.type` visibility: `private` → `readonly` to allow
  access through the narrowed `unknown` type in the type guard
- `translate` parameter and return type: `readonly any[]` → `readonly unknown[]`
- `makeTemplateObject` cast: `cooked as any` → `cooked as unknown as TemplateStringsArray`

Fix in `mock_message.ts` (test helper):
- `substitutions: []` → `substitutions: {}` — the array literal was only
  assignable because the field was typed as `any`; the correct empty value
  for a `Record<string, unknown>` is an object literal

(cherry picked from commit b10021c79b)
2026-08-17 21:56:35 +00:00
arturovt 5cb4ea7e35 fix(forms): warn in dev mode when ngModel cannot reach parent NgForm across component boundary
NgModel injects ControlContainer with @Host(), which stops the injector at
the component host element boundary. When NgForm lives in a parent component
and ngModel lives in a child component, the injection returns null silently
and the control acts standalone — never registering with the form.

To surface this invisible failure, emit a dev-mode warning (NG01354) when
ngModel's @Host() injection finds nothing but the element Injector can still
reach a ControlContainer further up the hierarchy. The warning identifies the
cross-boundary issue and points developers to the viewProviders fix or the
standalone option.

Adds the NG01354 reference page explaining why the warning fires and providing
two remediation paths: bridging ControlContainer via viewProviders, or opting
out with [ngModelOptions]="{standalone: true}".

Fixes #47580

(cherry picked from commit 38d093232c)
2026-08-17 20:59:44 +00:00
Vincent edcb45bd91 test(core): Add test to ensure Angular correctly detects paths when served from file system
This test makes sure that when Angular is served from Electron or just from the file system that the router works correctly.

(cherry picked from commit 70b252cac3)
2026-08-17 20:58:59 +00:00
Jaime Burgos 9d8aa3a829 refactor(compiler-cli): add error guide links to diagnostics
Add the error guide URL when a compiler diagnostic uses a negative
marked error code.

(cherry picked from commit 45ebb127e3)
2026-08-17 20:58:16 +00:00
arshiya tabasum d9620e0f1b fix(animations): detect object trigger values with Object.hasOwn
StateValue and AnimationTransitionNamespace.trigger detect the {value,
params} object form of a trigger binding by calling hasOwnProperty on the
bound value. When that value is an object from untrusted data (for example
a parsed JSON payload) carrying an own hasOwnProperty key, the shadowed
property is called as a method and throws, breaking the animation flush.
Use Object.hasOwn for the check so a shadowing key no longer matters.

(cherry picked from commit c73a001fbf)
2026-08-17 20:53:21 +00:00
SkyZeroZx 0cd635e9e2 fix(http): cancel oversized fetch response bodies
Cancel the unread response body before reporting NG02825 when its declared Content-Length exceeds the configured buffer limit. Without cancellation, SSR can finish while the underlying connection remains open.

Add regression coverage for the declared-length rejection path.

(cherry picked from commit 1a006a8f97)
2026-08-17 20:52:16 +00:00
Matthieu Riegler 5def30e945 refactor(language-service): adapt strict template suggestion
In v22, `strictTemplates` is true by default. We need to adapte the LS to online report the suggestion when the option is explicitly `false`

(cherry picked from commit ed3373868d)
2026-08-17 20:51:46 +00:00
Kam 6edbae2b17 feat(docs-infra): add Angie to the routing illustration
The routing header draws a serpentine route with map pins on it but
nobody travelling it. Angie now stands on the top segment, the same way
she stands on the road in the roadmap header.

She needs more headroom than the canvas had, so the viewBox gains 12
units at the top and the illustration carries its own max-height, which
keeps the rest of the drawing at the size it rendered before.

(cherry picked from commit 064530447e)
2026-08-17 20:46:50 +00:00
SkyZeroZx 809253e626 docs: correct Angular developer skill guidance
(cherry picked from commit 3e7094b049)
2026-08-17 20:44:55 +00:00
Evgenii Fomin 7a91332c42 docs: make a note regarding i18n messageIdFormat
(cherry picked from commit 8d6c6a9a0c)
2026-08-17 20:44:25 +00:00
Angular Robot 2bc9a542eb docs: update cross-repo adev docs
Updated Angular adev cross repo docs files.
2026-08-17 13:40:46 -07:00
SkyZeroZx 0849facb32 docs: add example for conditional redirects in routing
(cherry picked from commit ea3097c774)
2026-08-17 20:26:53 +00:00
Angular Robot e1b8306f89 docs: update cross-repo adev docs
Updated Angular adev cross repo docs files.
2026-08-17 13:24:46 -07:00
hello 2d87ed9159 docs: update Angular MCP skill reference
(cherry picked from commit 789c9c242d)
2026-08-17 17:43:15 +00:00
Matthieu Riegler 01fa2431e4 ci: update github nick
ethan changed his nick, this was causing some pullapproves errors when a pr hit the primitives-shared scope.

(cherry picked from commit 28f323a578)
2026-08-17 17:40:42 +00:00
Angular Robot 734c82d7ab build: update pnpm to v11.22.0
See associated pull request for more information.
2026-08-17 10:36:21 -07:00
arturovt c04931c88b fix(core): throw a descriptive error instead of crashing when a hydration node is missing
locateOrCreateElementNodeImpl looks up the DOM node for an element
during hydration and immediately checks its nodeType. If the
client-rendered DOM has fewer nodes than the server-rendered HTML,
the lookup returns null, and in production that null flows straight
into the nodeType check and crashes with a raw, uncoded
"Cannot read properties of null (reading 'nodeType')" TypeError.

The dev-mode check that would normally catch this (validateMatchingNode)
already handles a missing node, but it's compiled out of production
builds, so the crash only shows up outside of dev mode.

Add a null check ahead of the nodeType check that throws a coded
RuntimeError using the existing HYDRATION_MISSING_NODE (NG0502) code,
with a descriptive message in dev mode and a cheap fallback in
production. Also add a regression test that removes a server-rendered
element before hydration runs and asserts a coded RuntimeError is
thrown instead of a raw TypeError.

(cherry picked from commit c6e4a36be1)
2026-08-14 15:30:53 +00:00
arturovt 640460d606 fix(platform-browser): throw a descriptive error when insertBefore reference node is missing
Angular's internal LView/TNode bookkeeping can get out of sync with the
real DOM: manual DOM manipulation, a browser extension, or an edge case in
Angular's own view-insertion/reordering code can all leave Angular believing
a node is still attached at a given position when it isn't. The next time
Angular's renderer calls `insertBefore` relative to that stale reference
node, the native DOM API throws an opaque `NotFoundError` with no indication
of which node or component was involved, making these errors effectively
undebuggable in production:

    NotFoundError: Failed to execute 'insertBefore' on 'Node': The node
    before which the new node is to be inserted is not a child of this node.
        at Node.insertBefore (native)
        at DefaultDomRenderer2.insertBefore (packages/platform-browser/src/dom/dom_renderer.ts)
        at nativeInsertBefore (packages/core/src/render3/dom_node_manipulation.ts)
        at nativeAppendOrInsertBefore (packages/core/src/render3/dom_node_manipulation.ts)
        ... (called while Angular inserts or moves a view during change detection)

Check the reference node's actual parent against the expected parent before
calling the native `insertBefore`, and throw a descriptive `RuntimeError`
(NG05106) instead, following the same pattern already used for hydration
node mismatches.

(cherry picked from commit 1cb3d606bf)
2026-08-14 15:30:03 +00:00
Kristiyan Kostadinov 0cd243d99a build: resolve CI failures
Resolves some e2e failures that only happened on CI.

(cherry picked from commit 262fba7f7d)
2026-08-14 15:22:40 +00:00
Kristiyan Kostadinov e120d2830b build: switch adev tests away from protractor
Reworks the tests in adev not to depend on Protractor.

(cherry picked from commit 7b74bee5b4)
2026-08-14 15:22:39 +00:00
Kristiyan Kostadinov 3e02b0a2e5 build: switch examples away from protractor
Reworks the `examples` tests not to depend on Protractor.

(cherry picked from commit 204265f9a3)
2026-08-14 15:22:39 +00:00
Kristiyan Kostadinov 003e35de81 build: switch core tests away from protractor
Reworks the tests under `core` not to depend on Protractor.

(cherry picked from commit 413c79c10b)
2026-08-14 15:22:39 +00:00
Kristiyan Kostadinov 48fb5647b7 build: switch playground away from protractor
Reworks the `playground` tests not to depend on Protractor.

(cherry picked from commit 3d43067e20)
2026-08-14 15:22:39 +00:00
Kristiyan Kostadinov 31c624e203 build: add webdriver build rule
Sets up a build rule to use Selenium Webdriver for e2e tests.

(cherry picked from commit 4d2dc1fb08)
2026-08-14 15:22:39 +00:00
Angular Robot efbe456748 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-08-14 08:21:58 -07:00
Angular Robot a9f8fb2ef9 build: update cross-repo angular dependencies to v22.1.4
See associated pull request for more information.
2026-08-13 13:35:03 -07:00
Jaime Burgos 8adaa09f95 fix(vscode-extension): prevent command URI injection in TSDK approval
VS Code parses notification text for links and permits `command:` URIs. Interpolating the workspace-controlled TSDK path can therefore let a malicious path add a command link to the approval prompt.

Remove the path from the notification instead of attempting to sanitize or escape it. This keeps the prompt static and matches VS Code's TypeScript extension workspace-version approval flow.

Fixes #70176

(cherry picked from commit ba13a3ce22)
2026-08-13 20:34:40 +00:00
Aristeidis Bampakos ec5f4e86f0 docs: add code style in Antigravity file reference
(cherry picked from commit 144b90c907)
2026-08-13 20:33:45 +00:00
Alex Rickabaugh afe529cb2d fix(core): accept readonly arrays for setClassMetadata decorators
When reflection metadata is emitted via setClassMetadata, passing readonly arrays or const tuples for the decorators parameter causes TypeScript type checking errors because setClassMetadata previously expected decorators to be a mutable any[] or null.

This change updates the setClassMetadata type signature to accept decorators as readonly any[] or null and casts the parameter internally when mutating the class metadata property.

(cherry picked from commit dc65e3656f)
2026-08-13 20:33:11 +00:00
Alex Rickabaugh 2c72fe3797 fix(core): allow readonly arrays in RawScopeInfoFromDecorator
When components pass  arrays or readonly tuples to decorator metadata fields (such as ), typechecking generated decorator reflection metadata causes a TS2322 type mismatch error because  previously only accepted mutable .

This change updates  to accept , allowing  arrays and readonly tuples to be assigned without TypeScript compilation errors.

(cherry picked from commit eee9ef4d09)
2026-08-13 20:33:11 +00:00
arturovt 601d1f6576 fix(core): throw NG0500 instead of a raw TypeError on element hydration mismatch
When hydration locates the DOM node for an ɵɵelementStart/ɵɵdomElementStart
instruction, locateOrCreateElementNodeImpl assumed the located node was
always an Element and called hasSkipHydrationAttrOnRElement(native), which
does native.hasAttribute(...). The check that would normally catch this
class of mismatch, validateMatchingNode, is gated behind `ngDevMode &&` and
is compiled out of production builds. So when a real SSR/hydration
structural mismatch located a Text or Comment node instead of the expected
Element, production builds hit .hasAttribute on a node type that doesn't
have it and crashed with a raw, uncoded TypeError instead of a coded
hydration-mismatch RuntimeError.

Add a cheap, always-on nodeType check ahead of that call. On mismatch it
throws RuntimeError(HYDRATION_NODE_MISMATCH, ngDevMode && '...'), the same
pattern used elsewhere in the codebase, so the descriptive message is only
built in dev mode and production keeps throwing just the bare NG0500 code
without pulling validateMatchingNode's DOM-printing machinery into the
production bundle (verified via the bundling/hydration golden-symbols test,
which is unchanged).

(cherry picked from commit 4560f4fdcd)
2026-08-13 20:32:38 +00:00
Alon Mishne 148fee3991 release: cut the v22.1.2 release v22.1.2 2026-08-13 11:57:25 -07:00
Bhuvansh855 0a708e95bf docs: note SafeResourceUrl audio src change
(cherry picked from commit 647bf8e143)
2026-08-13 15:55:07 +00:00
Andrew Scott 910f391674 build(vscode-extension): dynamically resolve upstream remote and use token for https pushes
Previously, the release script hardcoded the upstream repository URL as an unauthenticated HTTPS URL (https://github.com/angular/angular.git). Although the script verified that a GITHUB_TOKEN environment variable was present, it only used that token for REST API calls (such as creating the GitHub release) and did not provide it to Git commands. As a result, users who authenticate to GitHub via SSH (and do not have an HTTPS Git credential helper configured) were prompted interactively for GitHub login credentials when pushing the release tag.

This change dynamically resolves the upstream remote name from the user's configured remotes by checking for any remote pointing to angular/angular. When pushing over SSH, Git uses the user's existing SSH credentials. When pushing over HTTPS (or falling back), the script injects GITHUB_TOKEN into the push URL to prevent interactive authentication prompts.

(cherry picked from commit 6f848db435)
2026-08-13 15:38:56 +00:00
Angular Robot 5a516cdc37 build: update all github actions
See associated pull request for more information.
2026-08-13 08:37:06 -07:00
Angular Robot 1aeec887b4 build: update dependency tar.bzl to v0.10.8
See associated pull request for more information.
2026-08-13 08:34:49 -07:00
Angular Robot 8fa99a2b6d build: lock file maintenance
See associated pull request for more information.
2026-08-13 08:29:30 -07:00
Andrew Scott e9660b1801 fix(compiler-cli): correctly resolve symbol for SafePropertyRead in chained optional navigation
When resolving template symbols for SafePropertyRead in TCBs emitted with optional chaining (strictSafeNavigationTypes: true), SymbolBuilder falls back to finding a TS node matching the AST expression's nameSpan. It then traverses up through parent nodes to find the enclosing expression.

Previously, the traversal loop checked isAccessExpression(node.parent) without verifying whether node was the accessed member name or the expression receiver. When multiple optional navigation expressions are chained (e.g. route?.data?.['icon']), the parent of ((route)?.data) is an access expression where ((route)?.data) is the receiver. Because isAccessExpression was true, the loop continued ascending into the outer access expression, causing symbol resolution for data to erroneously return the symbol and TCB location of icon.

This commit refines the parent traversal condition so that it only climbs into a parent PropertyAccessExpression if node is the accessed name (node.parent.name === node), preventing escape into outer receiver expressions.

(cherry picked from commit e8aa222e7d)
2026-08-12 23:11:27 +00:00