Compare commits

...

290 Commits

Author SHA1 Message Date
Alex Rickabaugh 5316753957 release: cut the v21.2.12 release 2026-05-06 15:47:48 -07:00
Matthieu Riegler 9e38ed7d57 fix(core): sanitizer typings
This is to fix patch builds
2026-05-05 17:07:03 -07:00
Sam Severance 335d8c04dc docs: clarify @for track expression scope to include properties and methods
(cherry picked from commit 2e0ca49f32)
2026-05-05 17:02:57 -07:00
Kam 161d98e7f2 docs: correct "Angular JS" to "AngularJS"
"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.

(cherry picked from commit 8a7f955f0f)
2026-05-05 12:42:45 -07:00
Leon Senft 03ad53863b fix(forms): prohibit concurrent submits in signal forms
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

(cherry picked from commit 708631f2c4)
2026-05-05 11:14:08 -07:00
Kam 929ec53578 fix(docs-infra): mask page content leak at mobile nav right edge
On phones, the page content behind the primary-nav drawer leaks 1-2px past its right edge. Mask it with a 2px var(--page-background) box-shadow.

(cherry picked from commit 1da396fd84)
2026-05-05 09:31:59 -07:00
Kam e6ab5eca57 fix(docs-infra): keep mobile nav drawers usable on small screens
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.

(cherry picked from commit 441a00d665)
2026-05-05 09:31:31 -07:00
Kristiyan Kostadinov 3430251fef fix(core): i18n flags leaking on errors
The i18n sub-system has the `changeMask` and `changeMaskCounter` flags which are set by i18n-related instructions and reset once the state is applied. The problem is that if something throws within the application logic, the flags would never be reset. This is currently causing flakes in our CI runs.

These changes resolve the issue by adding a try/finally around the flags.

(cherry picked from commit 6339d264eb)
2026-05-05 09:30:59 -07:00
Sam Severance ce7a43a5b6 refactor(forms): improve clarity in SelectMultipleControlValueAccessor.writeValue
Rename the _optionMap forEach parameter from `o` to `id` and tighten its
type from `any` to `string`, removing the now-redundant `.toString()` call.

(cherry picked from commit cd20dd07ce)
2026-05-01 16:02:40 -07:00
Nikolaos G. Ntaiko af74b420e1 Fix typo in computed signals section
(cherry picked from commit 429c665901)
2026-05-01 16:00:52 -07:00
tmpln c37f6ca42f fix(core): visit ng-let expression value in signal migration schematics
Before this fix, references to inputs inside @let statements were not
accounted for.

(cherry picked from commit 0ea27f4e65)
2026-05-01 15:59:20 -07:00
Kam aba59aac59 fix(docs-infra): exempt form validator names from API auto-linking
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.

(cherry picked from commit c2f7403774)
2026-05-01 15:58:48 -07:00
Matthew Beck c2b441af6d test: add NgModule compliance test with 'bootstrap' & local compilation
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.

(cherry picked from commit 0fa8f98f4f)
2026-05-01 15:58:10 -07:00
cexbrayat fe13bb669d fix(core): allow explicit read generic with signal input transforms
Using explicit single generic arguments with transforms (for example, input<boolean>(false, {transform: booleanAttribute})) previously failed overload resolution.

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

This change adds specialized overloads for explicit read generics.

(cherry picked from commit 1ab654cf28)
2026-05-01 15:54:01 -07:00
Angular Robot 08363f0f93 build: update dependency bazel_lib to v3.3.1
See associated pull request for more information.
2026-04-30 16:14:02 -07:00
Andrew Kushnir 05210ce2f1 ci: update PullApprove config
This commit updates the PullApprove config to keep myself as a reviewer, but do not auto-assign PR reviews.

(cherry picked from commit 2b624580e5)
2026-04-30 16:13:23 -07:00
Matthieu Riegler 3db96a5983 docs: add section about variable scopes
This is mostly a copy of the section we had on aio.

(cherry picked from commit 8f94892a71)
2026-04-30 16:10:33 -07:00
Angular Robot c2c869bbe5 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-04-30 16:09:55 -07:00
Angular Robot 7a6f4c2b4f build: update all github actions
See associated pull request for more information.
2026-04-30 16:09:31 -07:00
Matthieu Riegler 30cf85f71c refactor(common): update deprecation message
The old control flow is very much not recommended but we're not ready to remove it in v22.

(cherry picked from commit 28d38b582c)
2026-04-30 16:07:02 -07:00
Alan Agius 7a05a9a71a fix(core): validate security-sensitive attributes in i18n bindings
Ensures that security-sensitive attributes (e.g., sandbox, allow) are correctly validated when applied through i18n-* dynamic attribute bindings, preventing potential policy bypasses.

Closes #68418

(cherry picked from commit 9d7a609458)
2026-04-30 15:47:17 -07:00
Andrew Scott dc9b40ebb5 refactor: attempt stronger automatic comment blocking
Updates the PR review skill to have stronger language against automatic comment posting
without explicit approval

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

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

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

Fixes #67928

(cherry picked from commit 4c9afb68a3)
2026-04-29 23:09:18 +00:00
Alon Mishne ef9669c1f8 release: cut the v21.2.11 release 2026-04-29 15:38:40 -07:00
Kam 6c6db5b604 docs(docs-infra): open update guide external links in new tabs
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.

(cherry picked from commit 13c0422029)
2026-04-29 20:59:46 +00:00
Kam 185862ef76 docs: document allowedHosts SSR requirement in v21 update guide
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.

(cherry picked from commit 2101b13653)
2026-04-29 20:59:17 +00:00
Bhuvansh855 631e303dd9 docs: improve clarity in dependency injection guide
(cherry picked from commit 9f7d41f296)
2026-04-29 20:38:21 +00:00
Alan Agius 41e4851928 docs: update documentation for platform server URL token options
This `baseUrl` option is not available.

(cherry picked from commit 0f7086add4)
2026-04-29 20:37:04 +00:00
Andrew Scott a24dcfd1ec refactor(compiler-cli): remove reflectionhost from environment
all necessary info is already available in the tcb meta objects. environments without full ts program no longer need a reflectionhost for tcb generation

(cherry picked from commit c70625e806)
2026-04-29 20:36:25 +00:00
Ben Hong 1dde3827e9 docs: add debouncing section to signal forms async operations
Co-authored-by: Matthieu Riegler <kyro38@gmail.com>

Co-authored-by: Matthieu Riegler <kyro38@gmail.com>

Co-authored-by: Matthieu Riegler <kyro38@gmail.com>
(cherry picked from commit 18826de489)
2026-04-29 20:35:22 +00:00
Andrew Scott b40b67cdc1 fix(vscode-extension): Look for tsdk override in the new js/ts.tsdk.path setting
recent versions of vscode use js/ts.tsdk.path rather than typescript.tsdk

relates to #68423
2026-04-29 13:32:02 -07:00
Angular Robot 4900e453e1 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-04-29 13:29:44 -07:00
Matthieu Riegler 42d57c3578 refactor(common): fix viewport tests
10ad3c0 broke the 21.2.x branch
2026-04-28 16:38:11 -07:00
SkyZeroZx 10ad3c0692 fix(common): prevent focus from scrollToAnchor
Focus the target element using `focus({preventScroll: true})` after scrolling, so the browser doesn’t adjust the scroll position when applying focus.

Fixes #65938

(cherry picked from commit 97cac1cf4d)
2026-04-28 19:39:31 +00:00
Denis Balan d07f502946 docs: Fix links to Firebase AI Logic Angular example
(cherry picked from commit 5dfe37df8e)
2026-04-28 19:10:52 +00:00
Suraj Yadav 600da64ba4 docs(forms): add NG01902 error reference and link to docs
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.

(cherry picked from commit f2c6445681)
2026-04-28 19:07:50 +00:00
Matthieu Riegler a40e2cebc8 fix(core): fix ordering of view queries metadata in JIT mode
AOT was generating an array that was ordered as signal queries first, then the decorator queries.
Aligning JIT with AOT fixes the issue illustrated by the test.

fixes #68404

(cherry picked from commit 8c11816490)
2026-04-28 19:03:45 +00:00
Kam 9ed1b6c045 docs: use contentChildren() in component harness example
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.

(cherry picked from commit a6eb55642c)
2026-04-28 19:03:13 +00:00
Angular Robot 2b9b27e882 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-04-28 12:00:21 -07:00
Angular Robot 85f1c0a268 build: lock file maintenance
See associated pull request for more information.
2026-04-28 11:59:30 -07:00
Kam fb7e67ca9d docs: use inject() in @Self example in hierarchical DI guide
The surrounding @SkipSelf and @Host examples already use inject(),
and the section intro recommends it. Align the @Self example to match.

(cherry picked from commit 273ff07469)
2026-04-28 17:31:02 +00:00
Herdiyan IT Dev 316d49a8ae refactor(dev-infra): use shell: false and quote args in benchmark-compare workflow
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.

(cherry picked from commit f219e65841)
2026-04-28 17:29:28 +00:00
Matthieu Riegler 9bcbf37641 refactor(core): fix bundling symbol test
The golden needed an update.
2026-04-28 09:44:58 -07:00
Simon a3d14fc11b docs: remove duplicated text
(cherry picked from commit c8aad6acc6)
2026-04-28 00:10:24 +00:00
Simon 0612c8c53b docs: remove spaces to correct the indentation
(cherry picked from commit 38c352766a)
2026-04-28 00:09:50 +00:00
Kristiyan Kostadinov 4f5d8a2c0b fix(compiler): let declaration span not including end character
Fixes that the span for `@let` declarations didn't include the end token.

(cherry picked from commit 6bd1721662)
2026-04-28 00:09:19 +00:00
Alan Agius be1f80a253 fix(platform-server): ensure origin has a trailing slash when parsing url
The origin did not have a trailing slash, which caused parsing issues for relative URLs.

Fixes #68322

(cherry picked from commit 2a6b6fafb0)
2026-04-28 00:08:40 +00:00
aparziale 76cf531002 docs: Fix typo in doc
Fix typo in documentation. Changed "create workspace" to "create a workspace"

Fixed #68375

(cherry picked from commit 982e3cce52)
2026-04-28 00:08:06 +00:00
Sonu Kapoor 885a1a1d97 fix(core): guard against non-object events and avoid listener wrapper identity mismatch
Two issues caused browser test failures after the event replay fix:

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

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

   Replaced the `domListener` wrapper with a property (`__ngNativeEl__`) stored
   directly on `wrappedListener`. `wrapListenerIn_markDirtyAndPreventDefault` reads
   this property and calls `markEventHandledForElement` when the listener fires,
   while `renderer.listen` receives the same `wrappedListener` function that
   Angular stores in `lCleanup`, preserving the dedup invariant.

(cherry picked from commit 3583c01bf9)
2026-04-28 00:07:41 +00:00
Sonu Kapoor 7a64aff9b5 fix(core): prevent event replay double-invocation when element hydrates before app stability
When `withEventReplay()` is enabled and a component hydrates before the
application becomes stable (e.g. while a pending HTTP request is in
flight), a user interaction on the hydrated element triggers both the
real DOM listener registered by Angular and the jsaction replay path.
This causes the event handler to be invoked twice.

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

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

Fixes #67328

(cherry picked from commit d5fd51e956)
2026-04-28 00:07:40 +00:00
Kam cbaba8afe6 docs: document moduleResolution bundler change in v20 update guide
The v20 update guide doesn't flag that `ng update` switches
`moduleResolution` to `'bundler'`. Add a checklist item so manual
upgrades don't miss it.

(cherry picked from commit 67a5f00cd8)
2026-04-28 00:06:39 +00:00
Andrew Scott fbe080f829 docs(router): Fix method name for retrieving stored handles
method name was documented incorrectly. this fixes the name

(cherry picked from commit f17f32c351)
2026-04-28 00:03:25 +00:00
aparziale 1be52ad880 docs: Align Router API docs with inject based DI
Updates Router documentation examples to reflect modern inject based dependency injection instead of constructor injection.

Fixed #68378

(cherry picked from commit ded5a0ed62)
2026-04-28 00:02:32 +00:00
SkyZeroZx fa4eff36cb docs(docs-infra): Validate case-sensitive API symbol links in @link
Adds build-time validation for case-sensitive API symbols in `@link`. Avoid broken links

(cherry picked from commit d2c7b4e111)
2026-04-28 00:01:44 +00:00
Andrew Scott 27da56ee9d refactor: use stronger language for adev writing guide
use stronger language to improve skill usage hits for adev writing.

(cherry picked from commit 357cb15208)
2026-04-27 22:29:08 +00:00
Angular Robot 7b8faccc34 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-04-27 15:27:28 -07:00
Kam 6662724c99 docs(docs-infra): improve Playground card on installation page
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.

(cherry picked from commit 29081f7765)
2026-04-24 17:34:42 +00:00
Angular Robot 8ce8b9342a build: update pnpm to v10.33.2
See associated pull request for more information.
2026-04-24 10:11:20 -07:00
Angular Robot 131c422da2 build: update devinfra digest to c4d0c37
See associated pull request for more information.
2026-04-24 10:06:35 -07:00
Alan Agius fa33854d24 docs: document trustProxyHeaders and update X-Forwarded-Prefix validation
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.

(cherry picked from commit 0399115a82)
2026-04-24 17:04:00 +00:00
Angular Robot f3308dc1f7 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-04-23 14:14:19 -07:00
Angular Robot f9b70a0887 docs: update cross-repo adev docs
Updated Angular adev cross repo docs files.
2026-04-23 12:41:14 -07:00
Kam a8dd801856 docs: link Angular CLI in installation prerequisites
Links the "Angular CLI" mention in the Terminal prerequisite to the CLI
overview page.

(cherry picked from commit 6120d3196a)
2026-04-23 18:39:42 +00:00
Angular Robot 2ec753cb77 build: update devinfra digest to e9c1452
See associated pull request for more information.
2026-04-23 11:13:23 -07:00
Leon Senft 90cc755a56 release: cut the v21.2.10 release 2026-04-22 16:28:45 -07:00
Savio Dsouza 4fd1a08699 build: pin firebase-tools version and disable credential persistence in preview deploy workflow
(cherry picked from commit 8f5e0e09e9)
2026-04-22 14:38:27 -07:00
Angular Robot 750af5b123 build: update cross-repo angular dependencies to v21.2.8
See associated pull request for more information.
2026-04-22 11:03:02 -07:00
Rishabhdeep Singh 5533ab4f56 fix(migrations): fix NgClass leaving trailing comma after removal
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`.

(cherry picked from commit b395173cf2)
2026-04-22 09:59:54 -07:00
Rishabhdeep Singh 2b9954fd3d fix(migrations): fix NgClass leaving trailing comma after removal
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`.

(cherry picked from commit 27f021248d)
2026-04-22 09:59:54 -07:00
Angular Robot 4dc7bf5a75 build: lock file maintenance
See associated pull request for more information.
2026-04-21 10:23:48 -07:00
Joel Kesler 0d5ee9ae1b fix(docs): link formatting in "Animating your Application with CSS"
One of the links in `Animating your Application with CSS` page has a formatting bug for one of it's links.

(cherry picked from commit b24b4cb699)
2026-04-21 10:20:11 -07:00
Nikhil Bachani 6a02320575 docs: fix tracking expression reference in NG0955.md
Corrected the tracking expression reference from 'item.key' to 'item.value' in the explanation of duplicate keys.

(cherry picked from commit ac92a8aae8)
2026-04-21 10:14:53 -07:00
Angular Robot 751e4af80b build: update cross-repo angular dependencies
See associated pull request for more information.
2026-04-21 09:04:23 -07:00
Matthieu Riegler da346bf696 docs: update builder docs
We use `@angular/build` today.

(cherry picked from commit fa6a3d208d)
2026-04-21 09:02:37 -07:00
SkyZeroZx 580212c995 fix(router): restore internal URL on popstate when browserUrl is used
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

(cherry picked from commit 6eff439546)
2026-04-20 16:46:30 -07:00
Kam a9ddc5d40a docs: warn against storing secrets in environment files
Add a CRITICAL callout warning that files in `src/environments/`
ship to the client and should not hold secrets like API keys.

(cherry picked from commit d27e2c24e1)
2026-04-20 13:29:18 -07:00
Kam 0d08d9cc82 docs(docs-infra): guard sandbox reset before initialization in playground
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.

(cherry picked from commit c04c0b977a)
2026-04-20 13:17:22 -07:00
Kam 4c7ec66807 docs(docs-infra): adjust close button spacing in mobile navigation
Use relative positioning to offset the close button from the top edge without affecting the layout of surrounding elements.

(cherry picked from commit 2dc3ab596b)
2026-04-20 13:14:40 -07:00
Matthieu Riegler 62266eee8b ci: remove disabled side-effects integration tests
This test was disabled 5+ years ago, we probably don't need it anymore.

(cherry picked from commit 13be2961f6)
2026-04-20 13:13:28 -07:00
Bhuvansh855 2a50dceef5 docs: improve wording and consistency in forms documentation
(cherry picked from commit 74a7d6b8f9)
2026-04-20 13:12:35 -07:00
Andrew Scott c9215b3539 Revert "refactor(core): complete removal of deprecated createNgModuleRef alias"
This reverts commit d88d6ed69e.
Depended on a PR that was not merged to 21.2.x
2026-04-20 12:55:55 -07:00
SkyZeroZx d88d6ed69e refactor(core): complete removal of deprecated createNgModuleRef alias
Finalize the cleanup by removing the remaining `createNgModuleRef` alias.

(cherry picked from commit 3ae40e6685)
2026-04-20 12:09:51 -07:00
Bhuvansh855 e5b93ea4ca docs: fix wording in reactive forms guide
(cherry picked from commit c610425310)
2026-04-20 09:51:47 -07:00
Joey Perrott ce883d95ef build: update peer dependencies and bump version
Update peer dependencies to support Angular 21 instead of 22-next and bump the patch version to 0.21.1.
2026-04-20 09:39:10 -07:00
Bhuvansh855 be7490964a docs: improve clarity in dynamic forms guide
(cherry picked from commit a718e188c6)
2026-04-20 09:30:50 -07:00
Angular Robot 810fb7382f build: update cross-repo angular dependencies
See associated pull request for more information.
2026-04-17 14:34:29 -07:00
aparziale b24ead5571 refactor: Improve hydration mismatch errors for third-party scripts
Improves error messages shown during hydration mismatches to better
surface cases where third-party scripts or browser extensions have
modified the DOM outside of Angular's control.

Fixed #59224

(cherry picked from commit d771a65ac0)
2026-04-17 14:33:15 -07:00
pravintargaryen 6d10b8bb95 docs: add inject to structural directive imports
(cherry picked from commit da6c92eccd)
2026-04-17 14:25:09 -07:00
Angular Robot c738d45fa5 build: update all github actions
See associated pull request for more information.
2026-04-17 10:53:19 -07:00
Angular Robot b2fe2c2474 build: update bazel dependencies
See associated pull request for more information.
2026-04-17 10:51:47 -07:00
Michael Small 9577b49666 docs: capitalize FormField in form-logic.md imports: [...]
(cherry picked from commit 0850e20a83)
2026-04-17 10:50:57 -07:00
Michael Small 50f88e1887 docs: fix rxResource example of validateAsync
(cherry picked from commit 4da3f6c432)
2026-04-17 10:49:56 -07:00
Christian Oliff a57a6496fa docs: Fix typo in menubar.md
manubar > menubar

(cherry picked from commit bf4faed626)
2026-04-17 10:49:20 -07:00
Kam 8d22beb22c docs: fix typo in what-is-angular page
Change "language services powers" to "language service powers".

(cherry picked from commit 9c30e74349)
2026-04-17 10:48:35 -07:00
kirjs e14d5eadd5 release: cut the v21.2.9 release 2026-04-16 00:34:03 +03:00
arturovt 528a93a5da docs(router): document .. traversal and relativeTo pitfalls in router.navigate()
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

(cherry picked from commit 79c981840f)
2026-04-15 15:40:47 -04:00
Ben Hong 32a830231e docs: add new signal forms - form submission guide
(cherry picked from commit 50a3b0e1ba)
2026-04-15 12:38:40 -04:00
Angular Robot 0d1a5b80c2 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-04-15 19:37:18 +03:00
Matthieu Riegler 17cae6ae5f docs: fix bootstraping link
fixes #68212

(cherry picked from commit a46c64758e)
2026-04-15 12:25:40 -04:00
Suleiman Yunus 4f65bb34b2 docs: correct "What to learn more about Angular?" to "Want to learn more about Angular?"
(cherry picked from commit e32159b5c5)
2026-04-15 10:33:30 -04:00
arturovt eddca4280b fix(zone.js): allow draining microtasks in Promise.then (through flag)
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

(cherry picked from commit fc6a7eea68)
2026-04-15 10:31:33 -04:00
Kam 175343dfdb docs(docs-infra): add background to playground template dropdown
The template dropdown menu had no background color on the container,
causing page content to bleed through behind menu items.

(cherry picked from commit b2cff7918d)
2026-04-15 10:26:10 -04:00
Alan Agius e0b5078cf2 fix(platform-server): prevent SSRF bypasses via protocol-relative and backslash URLs
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);
});
```

(cherry picked from commit ede7c58a2a)
2026-04-15 10:23:57 -04:00
Ben Hong 1e474f7cfa docs: add new signal forms schema guide
(cherry picked from commit 3eba900d3f)
2026-04-15 10:22:40 -04:00
Matthieu Riegler 63a857b874 fix(http): Don't on Passthru outside of reactive context
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.

(cherry picked from commit d1cd97648a)
2026-04-15 10:20:53 -04:00
Kam c3d69aeaaa fix(docs-infra): prevent inline code wrapping in CLI reference table
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.

(cherry picked from commit c8e23d3a9d)
2026-04-14 18:29:30 +03:00
arturovt 684e9fd53d fix(router): normalize multiple leading slashes in URL parser
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

(cherry picked from commit c90b6b398e)
2026-04-14 12:34:08 +03:00
Andrew Scott ff0af64ced refactor(compiler-cli): decouple SymbolReference from AST nodes in template checker
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.

(cherry picked from commit c2f4b2af7c)
2026-04-14 12:32:54 +03:00
Angular Robot bb8cdd9566 build: lock file maintenance
See associated pull request for more information.
2026-04-14 12:20:59 +03:00
AleksanderBodurri 17ffa19a2d docs(devtools): create router tree documentation
(cherry picked from commit cb19c69ea6)
2026-04-13 21:16:07 +03:00
Michael Small 6c341347b2 docs: add "Using Agent Skills" + command to skills README.md
(cherry picked from commit bb03878ae0)
2026-04-13 21:12:30 +03:00
Ben Hong 8c32f577f1 docs: add new signal forms cross field logic guide
(cherry picked from commit c879cecb45)
2026-04-13 21:07:51 +03:00
Jessica Janiuk aa5d23799b docs: draft PR spam policy addendum
This updates the spam policy to be clear about draft pull requests with regards to the 3 PR limit

(cherry picked from commit eb2b06f3d9)
2026-04-13 20:54:28 +03:00
YooLCD 540536c386 fix(http): add CSP nonce support to JsonpClientBackend
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.

(cherry picked from commit 39e382a756)
2026-04-13 16:01:16 +03:00
Jessica Janiuk f603d4714f fix(core): escape forward slashes in transfer state to prevent crawler indexing
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

(cherry picked from commit 3c7641151c)
2026-04-13 13:55:00 +03:00
kirjs b72b6b4710 docs(forms): update signal forms migration guide
(cherry picked from commit f25c7ce6a6)
2026-04-13 13:25:44 +03:00
aparziale 3ed14c6354 refactor: Mobile layout api reference
Fix mobile layout shift in API reference

fix #67650

(cherry picked from commit 973ede6ccc)
2026-04-13 11:24:46 +03:00
Angular Robot 236b80b6f9 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-04-13 11:22:33 +03:00
Michael Small ca5b3c4d3e docs: add dev-app section to contributing docs
docs: link directly to dev-app `README.md`

(cherry picked from commit 59513b740d)
2026-04-13 11:18:37 +03:00
Kam 245bcdd607 docs(docs-infra): fix card container overflow on mobile viewports
Override h2 min-width in docs-card-container-header for small screens
and add docs-content container query fallback to hide SVG illustrations.

(cherry picked from commit c3d4be4a61)
2026-04-13 11:09:54 +03:00
Kam e2e7211530 docs(docs-infra): consolidate tab menu margins for phone breakpoint
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.

(cherry picked from commit b5b8631198)
2026-04-13 11:01:47 +03:00
Kam b351d493ea docs(docs-infra): fix essentials next-step navigation pills
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.

(cherry picked from commit fda8d201bb)
2026-04-13 10:51:03 +03:00
Kam 096a5c2105 docs(docs-infra): add external links to W3C specs in Angular Aria overview
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.

(cherry picked from commit e8eb179477)
2026-04-13 10:50:00 +03:00
Alan Agius b1407e1add build: update rules_angular setup in MODULE.bazel
Migrate from using use_repo_rule and override_repo directly to using the rules_angular.setup module extension for configuring configurable dependencies.

(cherry picked from commit a268547368)
2026-04-10 20:14:11 +03:00
Kam b4a747a94c docs(docs-infra): fix homepage nav overlay and banner visibility between 701–900px
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.

(cherry picked from commit 843f425ec8)
2026-04-10 17:39:36 +03:00
Angular Robot 3ae69406cc build: update cross-repo angular dependencies
See associated pull request for more information.
2026-04-10 17:36:09 +03:00
Doug Parker b52a6264ac refactor: add flaky tests workflow
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.

(cherry picked from commit 337e6e7d6e)
2026-04-10 16:45:37 +03:00
arturovt dc9581469f docs: add documentation for NG1002
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.

(cherry picked from commit 030422850b)
2026-04-10 10:54:46 +03:00
Angular Robot 05d9b97cf9 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-04-09 14:17:44 +03:00
Andrew Scott 6aafd87038 release: cut the v21.2.8 release 2026-04-08 12:31:46 -07:00
Andrew Scott d4c8a9a887 refactor(compiler-cli): decouple SymbolBuilder from BoundTarget and minimize adapter surface
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
2026-04-08 11:59:42 -07:00
N. Coury 057cc6d09d fix(core): remove obsolete iOS cursor pointer hack in event delegation
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.

(cherry picked from commit a24179e125)
2026-04-08 18:31:34 +00:00
Angular Robot dea76c7a6e build: update cross-repo angular dependencies
See associated pull request for more information.
2026-04-08 10:06:53 -07:00
Alan Agius a07d64b406 docs: fix typos and formatting in spam policy and saved replies
- 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`

(cherry picked from commit c70b4fec8c)
2026-04-08 16:41:27 +00:00
Kam a6d6842467 docs: fix typos and grammar errors across documentation
Fix various typos, misspellings, and grammar issues across contributing
docs, adev content guides, and agent skills documentation.

- "an minimum" → "a minimum" (CONTRIBUTING.md)
- "GitHub accounts" → "GitHub account" (CONTRIBUTING.md)
- "decendants" → "descendants" (components/styling.md)
- "templates are using" → "templates is using" (hydration.md)
- "A automated" → "An automated" (branches-and-versioning.md)
- "Github" → "GitHub" (branches-and-versioning.md, commit-message-guidelines.md)
- "practices makes" → "practice makes" (caretaking.md)
- "corresponds" → "correspond" (triage-and-labelling.md)
- "one a line" → "a line" (documentation-authoring.md)
- "straight forward" → "straightforward" (using-fixup-commits.md)
- "or you decide" → "or you can decide" (anatomy-of-components.md)
- "whenver" → "whenever" (angular-new-app/SKILL.md)

(cherry picked from commit 4739bde9fb)
2026-04-08 16:40:51 +00:00
Andrew Scott 33a30e0e03 refactor(compiler-cli): Fix regressions caused by ts.typechecker removal
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

(cherry picked from commit 30c950f133)
2026-04-08 15:14:48 +00:00
Angular Robot a385743983 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-04-07 16:42:35 -07:00
Andrew Scott c9f8f3afb6 test(core): add missing import of ChangeDetectionStrategy in query_spec
Add missing import of ChangeDetectionStrategy in query_spec.ts to fix compilation error.
2026-04-07 14:51:37 -07:00
Andrew Scott 910dcb6d6a refactor(compiler-cli): decouple TemplateSymbolBuilder from ts.TypeChecker
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.
2026-04-07 14:51:37 -07:00
Andrew Scott de12bc7e02 refactor(compiler-cli): tag host directives in TCB
Add HOST_DIRECTIVE expression identifier to TCB comments to identify host directives.
2026-04-07 14:51:37 -07:00
Kristiyan Kostadinov a4f312060c refactor(compiler): require a reference in DirectiveMeta
Requires the `DirectiveMeta` to have a `ref` so that we can find duplicates easily.
2026-04-07 14:51:37 -07:00
Kristiyan Kostadinov de533fe491 refactor(compiler-cli): move ClassPropertyMapping into compiler
Moves the `ClassPropertyMapping` into the compiler, rather than having to pass around the limited `InputOutputPropertySet` interface that is only implemented by `ClassPropertyMapping`.
2026-04-07 14:51:37 -07:00
Kristiyan Kostadinov ea1e34c4dd refactor(compiler): move matchSource into base metadata
Moves the `matchSource` into the base metadata so the binder can use it.
2026-04-07 14:51:37 -07:00
Kristiyan Kostadinov 304222014a refactor(compiler-cli): pre-compute key
Updates the TCB metadata to pre-compute and store the `TcbReferenceKey`, instead of computing it on the fly.
2026-04-07 14:51:37 -07:00
splincode 82192deda9 fix(core): handle missing serialized container hydration data
Simplify the hydration regression test by removing conditional early-return branches and relying on direct Jasmine expectations while keeping strict typing and OnPush configuration.

(cherry picked from commit 77f1ca08e4)
2026-04-07 18:22:07 +00:00
Angular Robot e8265f4593 build: lock file maintenance
See associated pull request for more information.
2026-04-07 09:49:43 -07:00
Kam c0496c1f39 docs(docs-infra): fix v21 event video not responsive on mobile
Replace raw iframe with docs-video component to fix YouTube embed
overflowing on mobile viewports.

(cherry picked from commit 1c9c4536d6)
2026-04-07 16:47:54 +00:00
Stephen Fluin 2d2ba938da docs(docs-infra): warning about upgrading to v21
(cherry picked from commit 64b52c1a30)
2026-04-07 16:47:17 +00:00
Kam ff8911fe52 docs(docs-infra): preserve navigation origin when clicking cross-category links
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.

(cherry picked from commit 8132a96884)
2026-04-07 16:46:23 +00:00
Doug Parker 72d7a47dfd docs: add spam policy
This defines an initial policy with regard to issue / PR spam as well as a saved reply for bulk-closing large issue / PR counts at once.

(cherry picked from commit 19ce90fe9b)
2026-04-07 16:32:19 +00:00
Kristiyan Kostadinov 2c6781071f fix(compiler-cli): error for type parameter declarations
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.

(cherry picked from commit ab061a7610)
2026-04-07 16:29:37 +00:00
Kristiyan Kostadinov e40d378f3e fix(compiler): handle nested brackets in host object bindings
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.

(cherry picked from commit 2ce0e98f79)
2026-04-06 20:21:54 +00:00
Kristiyan Kostadinov d715c366d9 refactor(compiler-cli): fix failing tests
Fixes some tests that started failing after recent changes.

(cherry picked from commit fd95735594)
2026-04-06 12:33:09 -07:00
Savio Dsouza c91bd074c0 ci: use immutable sha for checkout
Change to immutable SHA for checkout reference.

(cherry picked from commit 6e1e9766a5)
2026-04-06 11:47:06 -07:00
Angular Robot 2ec9ff087f docs: update cross-repo adev docs
Updated Angular adev cross repo docs files.
2026-04-06 11:35:04 -07:00
Doug Parker 8102331f82 test(http): disable XSRF and mock location in HttpClient tests to avoid Domino failures and state leakage
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.

(cherry picked from commit 1ef503e18e)
2026-04-06 18:05:58 +00:00
SkyZeroZx 44fc79b7f7 docs(docs-infra): Adds anchor links to class member headers for linking
Adds anchor links to class member headers for direct linking.
Add test to ensure anchors render correctly.

Fixes angular#67970
2026-04-06 11:05:20 -07:00
funsaized 39827a08fe fix(docs-infra): align search result icon with text on mobile
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

(cherry picked from commit d95e856a25)
2026-04-06 17:57:13 +00:00
Doug Parker 04f5841eed test(platform-server): fix race condition in incremental hydration test
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.

(cherry picked from commit 4a174b89c8)
2026-04-03 23:47:00 +00:00
Doug Parker 958fc6ab8a test(platform-server): replace fixed timeout with polling in event replay test
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.

(cherry picked from commit b4a3abd095)
2026-04-03 13:50:09 -07:00
Angular Robot cbfd1ee571 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-04-03 12:45:01 -07:00
Harmeet Singh b0dc2fbfcb docs(forms): clarify disabled FormArray value behavior
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

(cherry picked from commit 789c2cd9fb)
2026-04-03 18:22:37 +00:00
Angular Robot ef204bdf7a build: update bazel dependencies
See associated pull request for more information.
2026-04-03 10:59:22 -07:00
Angular Robot 4441a95119 build: update cross-repo angular dependencies to v21.2.5
See associated pull request for more information.
2026-04-02 15:50:14 -07:00
SkyZeroZx d150e2672e docs(docs-infra): Enhances update guide layout responsiveness
The version dropdown width now uses `clamp()` for better responsiveness.

(cherry picked from commit 164cf98879)
2026-04-02 22:49:32 +00:00
Kam 59f9912dc1 feat(docs-infra): update Stack Overflow icon to new logo
Updated the Stack Overflow icon in the navigation social menu to use the new Stack Overflow logo.

(cherry picked from commit a6a5e8a4a5)
2026-04-02 22:48:15 +00:00
Kam bce82bdc34 feat(docs-infra): add Stack Overflow link to navigation social menu
Added Stack Overflow icon and link to the navigation component.

(cherry picked from commit ba70e8ba0c)
2026-04-02 22:48:15 +00:00
Jessica Janiuk 2ae0912eea refactor(core): address review comments on NG0750 error message
This commit addresses review comments from AndrewKushnir regarding conditional formatting of error messages and updating tests.

(cherry picked from commit 30f63fc1c2)
2026-04-02 21:55:47 +00:00
Jessica Janiuk e583f4c808 refactor(core): Add more detail to NG0750 error message
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.

(cherry picked from commit 8218d2e34a)
2026-04-02 21:55:47 +00:00
Angular Robot 05bcc601ac build: update all github actions
See associated pull request for more information.
2026-04-02 13:00:00 -07:00
Angular Robot 9f61910923 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-04-01 14:36:13 -07:00
Andrew Scott 7797671257 fix(language-service): get quick info at local var location to align with TS semantics and support type narrowing
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

(cherry picked from commit 75ac120493)
2026-04-01 19:22:11 +00:00
SkyZeroZx 0b08e29f26 test(core): refactors test to use timeout utility
Replaces direct `setTimeout` wrapped in a Promise with the `timeout` helper from `@angular/private/testing`

(cherry picked from commit c15e3a005d)
2026-04-01 20:46:05 +02:00
Pawel Kozlowski 50761c8be4 release: cut the v21.2.7 release 2026-04-01 20:36:00 +02:00
Matthieu Riegler 8d56b17b95 ci: exclude test files from primitives review
Those files aren't synced into G3 and shouldn't require external reviews

(cherry picked from commit bf8105ef76)
2026-04-01 20:27:31 +02:00
Angular Robot 4ad6d582d2 build: update cross-repo angular dependencies to v21.2.6
See associated pull request for more information.
2026-04-01 18:25:52 +02:00
Angular Robot f363ab41f1 build: update cross-repo angular dependencies to 616a50d
See associated pull request for more information.
2026-04-01 13:21:58 +02:00
Andrew Scott 0960592d3d fix(router): pass outlet context to split to fix empty path named outlets
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

(cherry picked from commit daa9b2a9d6)
2026-04-01 11:48:47 +02:00
Alan Agius d04ddd73df fix(core): prevent binding unsafe attributes on SVG animation elements (#67797)
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
2026-04-01 11:43:59 +02:00
Alan Agius b682c62873 fix(core): treat object[data] as resource URL context (#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
2026-04-01 11:43:59 +02:00
Alan Agius fea25d1a60 fix(compiler): register SVG animation attributes in URL security context (#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
2026-04-01 11:43:59 +02:00
Kam f916531ee1 docs(docs-infra): improve angular-new-app skill
Consolidate duplicate persona intro, add commonly useful ng new flags
and missing generators to scaffolding guidelines.

(cherry picked from commit f257f54967)
2026-04-01 09:26:41 +02:00
tomer953 8fd896e99a fix(core): resolve component import by exact specifier in route lazy-loading schematic
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.

(cherry picked from commit 8fa6617352)
2026-04-01 09:24:13 +02:00
Kam 895c576d49 refactor(forms): use strict equality for pending status getter
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.

(cherry picked from commit ef7679b7a5)
2026-03-31 13:52:00 +02:00
Angular Robot 5fd4f0f854 build: lock file maintenance
See associated pull request for more information.
2026-03-31 13:42:53 +02:00
Angular Robot 429513bed0 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-03-31 12:02:18 +02:00
Alan Agius f22d9a7098 docs: modernize CLI reference for build and test
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.

(cherry picked from commit 1a6785874e)
2026-03-31 11:56:07 +02:00
Angular Robot cf7846bd62 build: update pnpm to v10.33.0
See associated pull request for more information.
2026-03-30 12:47:07 +02:00
Matthieu Riegler 9ea8cb6eea docs(docs-infra): sanitize markdown tooltip in Code editor
(cherry picked from commit 0f960a5514)
2026-03-30 12:16:16 +02:00
Alan Agius 3c41e74fdd fix(localize): validate locale in getOutputPathFn to prevent path traversal
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

(cherry picked from commit 7871093822)
2026-03-30 12:15:31 +02:00
Shuaib Hasan Akib efbba945bc docs: align list formatting and improve emphasis
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.
2026-03-30 11:12:29 +02:00
SkyZeroZx 7d54952e85 docs: update signal form tutorial
(cherry picked from commit 713eca74e7)
2026-03-30 11:11:28 +02:00
SkyZeroZx 94b1b530dc docs: update url from <base href>
(cherry picked from commit c6f73f4127)
2026-03-30 10:44:20 +02:00
marktechson 0c9c270552 docs: add agent skills documentation and new readme
(cherry picked from commit 86bbc9474c)
2026-03-27 11:39:57 -07:00
Georgi Serev 9b48cb2989 docs(docs-infra): introduce a custom UrlSerializer
The custom serializer should handle Adev-specific behavior like decoding encoded forward slash similarly to the app host.

(cherry picked from commit 9d79ec6866)
2026-03-27 17:17:55 +01:00
Andrei Chmelev bba5ed8e64 fix(compiler-cli): prevent recursive scope checks for invalid NgModule imports
Avoid recursive local scope lookups when invalid NgModule imports create import cycles.

(cherry picked from commit fcd0bb0db8)
2026-03-27 16:10:08 +01:00
Angular Robot 56c872dacc docs: update cross-repo adev docs
Updated Angular adev cross repo docs files.
2026-03-27 14:13:13 +01:00
Angular Robot c8902deb00 build: update all github actions
See associated pull request for more information.
2026-03-27 14:02:11 +01:00
Angular Robot 4b2008d0f2 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-03-27 14:00:33 +01:00
Andrew Scott b453c0ce67 refactor(language-service): Update getTcbNodesOfTemplateAtPosition to be usable without compiler (#67898)
updates getTcbNodesOfTemplateAtPosition to be usable without ngCompiler instance
so it can be shared with more compiler types

PR Close #67898
2026-03-26 21:32:20 +00:00
Andrew Scott a9ca90fc11 refactor: fix types extraction for private (#67898)
fixes types extraction for private entrypoint of language service

PR Close #67898
2026-03-26 21:32:20 +00:00
Jessica Janiuk 807cabd9e1 fix(dev-infra): improve PR review skill handling of git worktrees
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.
2026-03-26 18:45:39 +01:00
Doug Parker 13f050d220 test: construct local Date objects to fix timezone flakiness
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)
```

(cherry picked from commit 61ee183fa7)
2026-03-26 18:34:13 +01:00
Doug Parker d0cf2995a2 test: remove unsupported timezone from formatDate tests
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.

(cherry picked from commit a1385ad977)
2026-03-26 18:34:13 +01:00
SkyZeroZx a35d572b22 docs: fix indentation that breaks roadmap rendering
(cherry picked from commit ecc616b94b)
2026-03-26 18:33:06 +01:00
cexbrayat 80fd08bcc8 docs: remove private utils from testing skills
(cherry picked from commit 9bb1e78969)
2026-03-26 18:29:24 +01:00
Leon Senft d8239c7836 release: cut the v21.2.6 release 2026-03-25 15:42:09 -07:00
Alan Agius c1579163b7 build: consolidate domino bundling in platform-server
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
```

(cherry picked from commit b40d11eec4)
2026-03-25 13:31:10 -07:00
Angular Robot dbb15ebab2 build: update dependency node to v22.22.2
See associated pull request for more information.
2026-03-25 13:29:38 -07:00
Andrew Scott a6c49e0ea9 refactor(language-service): Export template target from API
allows template target to be used in other tooling

(cherry picked from commit eecfa4c909)
2026-03-25 13:07:47 -07:00
Michael Small 2c12339ab8 docs(forms): replace rxResource request w/ params
(cherry picked from commit 89629d8ac1)
2026-03-25 13:04:57 -07:00
Angular Robot a3048f231c build: update cross-repo angular dependencies
See associated pull request for more information.
2026-03-25 12:59:42 -07:00
Alan Agius ae2f2497d3 docs: reword allowedHosts security warning
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.

(cherry picked from commit 6f20fb513c)
2026-03-25 12:56:46 -07:00
Alan Agius 2c7d3b5704 build: re-sync file
Fixes patch CI due to missing synced file.
2026-03-25 10:53:09 +01:00
guidettj 6bd2121817 docs: fix incorrect getHarnesses() method to getAllHarnesses and broken link
(cherry picked from commit 050b14bd7f)
2026-03-24 15:35:36 -07:00
SkyZeroZx e8c047bd8d docs: update defer section to Markdown and fix absolute URL to relative in adev
(cherry picked from commit 098553bfe4)
2026-03-24 15:35:02 -07:00
hawkgs a0ca5a50b2 docs(docs-infra): redefine /guide/pipes redirect
Update the definition of the `/guide/pipes` redirect in order to avoid breaking the `a.dev/guide` redirect to Not Found page.

(cherry picked from commit 78c2d0aa19)
2026-03-24 15:17:15 -07:00
Fausto Davila 1cdb322600 docs: fix typo in end-to-end.md regarding e2e command
(cherry picked from commit c9f7a7f649)
2026-03-24 15:15:14 -07:00
Jens Kuehlers c9585b7159 docs: update release date to not clash with Google I/O 2026
(cherry picked from commit b4ae9cf040)
2026-03-24 15:14:38 -07:00
Angular Robot 238b07fe90 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-03-24 15:13:56 -07:00
Angular Robot 3b3ab8b626 build: lock file maintenance
See associated pull request for more information.
2026-03-24 15:08:55 -07:00
weedorflow e731bbdd14 docs: clarify size budget configuration
(cherry picked from commit 37b1c5d0fe)
2026-03-24 14:49:38 -07:00
Aleksander Bodurri c7a18924a6 fix(devtools): fix incorrect logic in destroy function for ChromeMessageBus
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.

(cherry picked from commit 36edf4870f)
2026-03-23 14:51:32 -07:00
Joey Perrott 244e0b0b59 ci: correct capitalization of MarkTechson in pullapprove
Correct the capitalization of MarkTechson's username to match their GitHub profile, ensuring proper evaluation by PullApprove.

(cherry picked from commit 543753f551)
2026-03-23 14:50:23 -07:00
Alan Agius 9bfe1a6065 docs: remove redundant ng command from npx instructions in Angular Developer skill
(cherry picked from commit b89af3c8da)
2026-03-23 14:49:30 -07:00
Modeste ASSIONGBON b658accf1f docs: fix js doc of signal forms ignoreValidators option.
(cherry picked from commit 2615f35da9)
2026-03-23 11:21:21 -07:00
Pushkar-Mahajan4 9be5e2c211 docs: fix typo in Input decorator
(cherry picked from commit 1128e78913)
2026-03-23 11:19:51 -07:00
SkyZeroZx 8818095a82 docs(docs-infra): fix aria-label parsing breaking headings
Strip all HTML tags and escape quotes in aria-label to avoid breakage

(cherry picked from commit 6d2eed61a1)
2026-03-23 10:33:19 -07:00
splincode 80c85ec8a5 refactor(devtools): improve test descriptions by fixing spelling
Fixed misspellings in test descriptions in devtools/projects/shell-browser/src/app/tab_manager_spec.ts: recieved/recieves → received/receives in three it(...) titles.

(cherry picked from commit 25dad82e43)
2026-03-23 10:32:44 -07:00
splincode fb7a10fb18 docs: fix typos in ssr-benchmarks README.md
Corrected typos in modules/ssr-benchmarks/README.md: mesure→measure, Struture→Structure, render→renders, benckmark→benchmark, capitalized DevTools, and clarified the flame chart instruction.

(cherry picked from commit 13c198ae63)
2026-03-23 10:27:43 -07:00
SkyZeroZx 1af0db5742 docs(docs-infra): replace non-interactive buttons with spans
These elements are not interactive, so using <button> is misleading for accessibility
(screen readers and keyboard navigation expect an action).

(cherry picked from commit ad3991cd0b)
2026-03-23 10:24:13 -07:00
Alan Agius a821e06e33 ci: support publishing dev-skills to snapshot repository
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.

(cherry picked from commit 293ac66a9f)
2026-03-23 09:49:15 -07:00
Matthieu Riegler a21be36e15 refactor: prepare for required changeDetection prop on G3.
We'll make this a G3 only change to prevent backsliding during the transition period.

(cherry picked from commit d2054c7c1a)
2026-03-20 15:52:42 -07:00
Angular Robot 7aaa8b9b39 docs: update cross-repo adev docs
Updated Angular adev cross repo docs files.
2026-03-20 15:39:47 -07:00
Angular Robot d0481860bf build: update cross-repo angular dependencies
See associated pull request for more information.
2026-03-20 15:23:08 -07:00
Matt Lewis 880a57d4b3 fix(compiler): prevent shimCssText from adding extra blank lines per CSS comment
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.

(cherry picked from commit 5a712d42d1)
2026-03-20 15:17:35 -07:00
Angular Robot 1ba89d1128 build: lock file maintenance
See associated pull request for more information.
2026-03-20 15:14:25 -07:00
Matthieu Riegler 831746eff1 docs: Add callout about the Component interface.
(cherry picked from commit e01573fbca)
2026-03-19 16:14:22 -07:00
Jaime Burgos 9182b62b96 docs(forms): add section on managing validators dynamically in form validation guide
(cherry picked from commit eb53392b10)
2026-03-19 16:07:54 -07:00
Angular Robot 4d2a9394c3 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-03-19 16:03:49 -07:00
Jessica Janiuk ad0156e056 fix(core): fixes a regression with animate.leave and reordering
PATCH PR for #67765

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
2026-03-19 15:52:35 -07:00
Angular Robot aa3220a4b5 build: update dependency aspect_rules_ts to v3.8.7
See associated pull request for more information.
2026-03-19 15:23:54 -07:00
SkyZeroZx b4ab6ba2e8 fix(common): avoid redundant image fetch on destroy with auto sizes
prevents browsers from re-fetch image during DOM teardown
when using `sizes="auto"` with lazy loading.

Fixes angular#67055

(cherry picked from commit c1312da183)
2026-03-19 15:21:20 -07:00
aparziale 73d6b01b47 fix(migrations): inject migration not work in multi-project workspace with option path
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
(cherry picked from commit a73b4b7c30)
2026-03-19 15:20:46 -07:00
Angular Robot 3838554503 build: update cross-repo angular dependencies to v21.2.3
See associated pull request for more information.
2026-03-19 15:04:08 -07:00
Angular Robot 1148c93834 build: update all github actions
See associated pull request for more information.
2026-03-19 15:02:54 -07:00
Matthieu Riegler 9f92312cde docs(docs-infra): fix deprecation style for light theme
(cherry picked from commit cc07d46e49)
2026-03-19 15:00:31 -07:00
Doug Parker 04b16dee8f refactor: ignore pnpm-lock.yaml in Gemini code reviews
It can't give much useful feedback so this just introduces noise into Renovate PRs.

(cherry picked from commit 12ea6efc9d)
2026-03-19 14:56:00 -07:00
Matthew Beck 57ce2b64ef release: cut the v21.2.5 release 2026-03-18 17:33:53 -06:00
Angular Robot 5393d8ea2c docs: update cross-repo adev docs
Updated Angular adev cross repo docs files.
2026-03-18 14:08:01 -06:00
SkyZeroZx 675d4fb489 docs: update import and note formatting in guides
(cherry picked from commit a8bf957086)
2026-03-18 13:04:21 -07:00
Jessica Janiuk 851ef77318 Revert "refactor(core): Ensure determineLongestAnimation is run synchronously after style applies"
This reverts commit 318ade062e.

(cherry picked from commit 890c97301f)
2026-03-18 10:30:40 -07:00
Yenya030 5800f17e19 refactor(service-worker): remove unnecessary cast in mock redirect check
Use the typed Response.redirected property directly in the service-worker test mock instead of casting to any.

(cherry picked from commit 57a07d0058)
2026-03-18 10:26:26 -07:00
Yenya030 e19150d2b5 fix(service-worker): preserve redirect policy on reconstructed asset requests
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.

(cherry picked from commit 07abfbcc6c)
2026-03-18 10:26:25 -07:00
SkyZeroZx 0e496c1d85 docs(docs-infra): improve semantic HTML in update guide
Improves update guide's semantic HTML
2026-03-18 09:42:32 -06:00
kirjs 737777ef72 docs: add Angular Developer Skill updates
Includes:

- Imports and setup instructions

- Validation examples (sync, async, conditional)

- FieldState vs FormField distinction

- Common pitfalls and best practices

- Full-featured example application

(cherry picked from commit ed150e52d1)
2026-03-17 17:39:44 -07:00
marktechson fa26e7271f docs: adds angular-developer skill
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.

(cherry picked from commit 8291b16a36)
2026-03-17 17:39:43 -07:00
aparziale 076d41c3f6 fix(migrations): prevent trailing comma syntax errors after removing NgStyle
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`.

(cherry picked from commit 730684b9ce)
2026-03-17 17:01:28 -07:00
JoostK a8f80c1f99 refactor(core): declare explicit reactive node prototypes types
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`.

(cherry picked from commit 1eaf92077f)
2026-03-17 13:00:15 -07:00
JoostK bf948be4c2 fix(core): run linked signal equality check without reactive consumer
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.

(cherry picked from commit 523d69a768)
2026-03-17 12:59:42 -07:00
yogeshwaran-c 23ea431c4e fix(compiler): parse named HTML entities containing digits
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. &sup1;, &frac12;, &blk34;)
to be treated as plain text instead of decoded to their corresponding
Unicode characters.

Fixes #51323

(cherry picked from commit 75560ce43d)
2026-03-17 12:54:45 -07:00
Alan Agius 2fb767b139 build: remove redundant Bazel lockfile update workarounds
Renovate now natively supports updating Bazel lockfiles.

This change removes the `postUpgradeTasks` workaround in Renovate config

(cherry picked from commit a37dd59fc4)
2026-03-17 12:53:11 -07:00
Angular Robot b10e305ccc build: update cross-repo angular dependencies
See associated pull request for more information.
2026-03-17 13:52:37 -06:00
Alan Agius f0d19b88b1 docs: clarify X-Forwarded-Prefix header validation rules
(cherry picked from commit d0086e493b)
2026-03-17 12:50:15 -07:00
Kristiyan Kostadinov 67e0ba7e03 fix(compiler-cli): generic types not filled out correctly in type check block
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.

(cherry picked from commit 9769560da7)
2026-03-17 12:21:31 -07:00
Angular Robot ca328eab8f docs: update cross-repo adev docs
Updated Angular adev cross repo docs files.
2026-03-16 14:47:18 -06:00
Andrew Scott faeeef678a feat(dev-infra): add PR review agent skill
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.

(cherry picked from commit 2e34924647)
2026-03-16 13:25:51 -07:00
Angular Robot 4d786517d3 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-03-16 10:54:17 -06:00
Kristiyan Kostadinov 26c43d14ba fix(compiler-cli): escape template literal in TCB
Fixes a regression introduced by #67381 where we weren't escaping backticks in template literals.

Fixes #67675.

(cherry picked from commit 2bd708fb6b)
2026-03-16 09:47:29 -07:00
Max Millien 1890c3008b fix(core): clean up dehydrated views during HMR component replacement
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

(cherry picked from commit dc0446552a)
2026-03-16 09:04:11 -07:00
hawkgs cbb2266984 test(devtools): fix and update flaky component-tree tests
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.

(cherry picked from commit 77d7378ffd)
2026-03-16 09:03:47 -07:00
SkyZeroZx ea4847aae5 docs(docs-infra): add spacing between reference option and description
Add a spacing class to `docs-reference-option` to prevent the text from appearing too close together.

(cherry picked from commit 3720b2de0f)
2026-03-16 09:00:50 -07:00
Akash Patel 5fa3052ed1 docs: update uninstallation commands for Karma packages
Added 'jasmine-core' to the list of packages to uninstall when migrating to Vitest.

(cherry picked from commit b9ff865b49)
2026-03-16 08:59:38 -07:00
SkyZeroZx 86718fbbe1 docs: fix type code block language
fix type code block language

(cherry picked from commit acd6f690bd)
2026-03-16 08:59:13 -07:00
guidettj de5fbb7deb docs: use lighter lodash isEqual import in equality example
(cherry picked from commit 7d483f28a4)
2026-03-16 08:58:44 -07:00
Angular Robot f39896da99 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-03-13 16:25:45 -06:00
ibrahim-hussien-dev 21cab20dae docs: combine multiple documentation typo fixes
(cherry picked from commit e127927807)
2026-03-13 12:10:59 -07:00
Angular Robot 2d28e9b392 build: update pnpm to v10.32.1
See associated pull request for more information.
2026-03-13 13:08:54 -06:00
Alan Agius 5b46a63c08 build: update rules_angular dependency commit hash
Update rules_angular to latest sha
2026-03-13 13:07:06 -06:00
Alan Agius 03fb3cd463 refactor: ensure modules with 'declare global' are correctly handled by Rollup
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.
2026-03-13 13:07:06 -06:00
SkyZeroZx 67a73192bf docs(docs-infra): remove tap highlight for API reference list filter
Prevents the default translucent highlight from appearing on touch devices when interacting with the API reference list filter.

(cherry picked from commit 7cd474d1d6)
2026-03-13 12:04:06 -07:00
Jessica Janiuk e5ed276f27 refactor(core): Ensure determineLongestAnimation is run synchronously after style applies
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.

(cherry picked from commit 318ade062e)
2026-03-13 12:03:15 -07:00
Kristiyan Kostadinov 334ae10168 fix(compiler): ensure generated code compiles
Initial pass to make sure some common cases produce code that compiles.
2026-03-13 12:53:47 -06:00
Kristiyan Kostadinov 1f2dc72e8a refactor(compiler-cli): update ast factories to account for type nodes
Updates the Babel and TypeScript AST factories to account to produce type nodes.
2026-03-13 12:53:47 -06:00
Kristiyan Kostadinov e3b0e5a0b3 refactor(compiler-cli): add type nodes to translator
Updates the translator and AST factories to account for type nodes.
2026-03-13 12:53:47 -06:00
Kristiyan Kostadinov 10b0dd94e9 refactor(compiler-cli): add generic for type nodes to AST factories
Updates the type factories and various usage sites to add a generic for type nodes.
2026-03-13 12:53:47 -06:00
Jessica Janiuk 6f41efc689 refactor(core): Update determineLongestAnimation to account for playback rate
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.

(cherry picked from commit 17d8a88ddc)
2026-03-12 16:36:54 -07:00
Kristiyan Kostadinov bfb8b177ac refactor(compiler-cli): remove more unused code
Cleans up some more usages of TS factory APIs and some unused functions.
2026-03-12 16:21:50 -06:00
Kristiyan Kostadinov 2feced366a refactor(compiler-cli): replace typescript usage in type reference emits
Replaces our usage of TypeScript APIs in several places that emit references to type nodes. Also deletes some unused code.
2026-03-12 16:21:50 -06:00
Alan Agius 5d755be01c refactor: ensure modules with 'declare global' are correctly handled by Rollup
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`.

(cherry picked from commit bb628d8b50)
2026-03-12 13:58:03 -07:00
603 changed files with 31474 additions and 20894 deletions
-1
View File
@@ -1 +0,0 @@
../.gemini/skills
@@ -1,6 +1,6 @@
---
name: adev-writing-guide
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`.
---
# Angular Documentation (adev) Writing Guide
+134
View File
@@ -0,0 +1,134 @@
---
name: PR Review
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.
### GitHub MCP Tools (Preferred)
- `mcp_github-mcp-server_pull_request_review_write`
- `mcp_github-mcp-server_add_comment_to_pending_review`
### Custom Bash Scripts (Fallback)
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.
**Usage:**
```bash
.agent/skills/pr_review/scripts/determine_review_type.sh <PR_NUMBER>
```
### `get_pr_comments.sh`
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.
**Usage:**
```bash
.agent/skills/pr_review/scripts/get_pr_comments.sh <PR_NUMBER>
```
### `reply_pr_comment.sh`
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.
**Usage:**
```bash
.agent/skills/pr_review/scripts/reply_pr_comment.sh <PR_NUMBER> <COMMENT_ID> <REPLY_BODY>
```
### `post_inline_comment.sh`
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`.
**Usage:**
```bash
.agent/skills/pr_review/scripts/post_inline_comment.sh <PR_NUMBER> <FILE_PATH> <LINE_NUMBER> <COMMENT_BODY>
```
**Example:**
```bash
.agent/skills/pr_review/scripts/post_inline_comment.sh 12345 "packages/core/src/render3/instructions/element.ts" 42 "AGENT: Consider the performance implications here."
```
### `submit_pr_review.sh`
Submits all locally staged inline comments as a single batched review via the GitHub Pull Request Reviews API.
**Usage:**
```bash
.agent/skills/pr_review/scripts/submit_pr_review.sh <PR_NUMBER> <EVENT_TYPE> [BODY]
```
**Options:**
- `EVENT_TYPE`: Must be `COMMENT`, `APPROVE`, or `REQUEST_CHANGES`. Never use `APPROVE` for external PRs.
- `BODY`: (Optional) A general summary comment for the review.
**Example:**
```bash
.agent/skills/pr_review/scripts/submit_pr_review.sh 12345 COMMENT "AGENT: I have left a few inline suggestions for your consideration."
```
@@ -0,0 +1,7 @@
# Router PR Review Guidelines
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.
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
set -euo pipefail
# determine_review_type.sh <PR_NUMBER>
# Determines if the PR should be reviewed locally or remotely based on author.
if [ -z "$1" ]; then
echo "Usage: determine_review_type.sh <PR_NUMBER>"
exit 1
fi
PR_NUMBER=$1
# Get current authenticated user
CURRENT_USER=$(gh api user -q .login 2>/dev/null)
if [ $? -ne 0 ]; then
echo "Error: Could not determine current GitHub user. Are you logged in to gh?"
exit 1
fi
# Get PR author
PR_AUTHOR=$(gh pr view "$PR_NUMBER" --json author -q .author.login 2>/dev/null)
if [ $? -ne 0 ]; then
echo "Error: Could not retrieve PR information for $PR_NUMBER."
exit 1
fi
if [ "$CURRENT_USER" = "$PR_AUTHOR" ]; then
echo "local"
else
echo "remote"
fi
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -euo pipefail
# get_pr_comments.sh
# Fetches existing inline comments on a PR to avoid duplicate reviews.
# Usage: ./get_pr_comments.sh <PR_NUMBER>
if [ "$#" -lt 1 ]; then
echo "Usage: $0 <PR_NUMBER>"
exit 1
fi
PR_NUMBER="$1"
# Ensure gh cli is installed
if ! command -v gh &> /dev/null; then
echo "Error: gh CLI could not be found. Please install and authenticate."
exit 1
fi
# Get the current repository (e.g., angular/angular)
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
# Fetch comments
gh api \
--paginate \
-H "Accept: application/vnd.github+json" \
"/repos/${REPO}/pulls/${PR_NUMBER}/comments" \
--jq '.[] | {id: .id, path: .path, line: .line, body: .body, user: .user.login}'
+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -euo pipefail
# post_inline_comment.sh
# Adds an inline comment to a specific line in a PR via the GitHub API.
# Usage: ./post_inline_comment.sh <PR_NUMBER> <FILE_PATH> <LINE_NUMBER> <COMMENT_BODY>
if [ "$#" -lt 4 ]; then
echo "Usage: $0 <PR_NUMBER> <FILE_PATH> <LINE_NUMBER> <COMMENT_BODY>"
exit 1
fi
PR_NUMBER="$1"
FILE_PATH="$2"
LINE="$3"
BODY="$4"
# Ensure gh cli is installed
if ! command -v gh &> /dev/null; then
echo "Error: gh CLI could not be found. Please install and authenticate."
exit 1
fi
# Get the current repository (e.g., angular/angular)
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
echo "Staging inline comment for PR #${PR_NUMBER} on ${FILE_PATH}:${LINE}..."
COMMENT_FILE="/tmp/angular_pr_${PR_NUMBER}_comments.json"
if [ ! -f "$COMMENT_FILE" ]; then
echo "[]" > "$COMMENT_FILE"
fi
# Append the new comment to the JSON array
jq --arg path "${FILE_PATH}" --argjson line "${LINE}" --arg body "${BODY}" \
'. += [{"path": $path, "line": $line, "body": $body}]' "$COMMENT_FILE" > "${COMMENT_FILE}.tmp" && mv "${COMMENT_FILE}.tmp" "$COMMENT_FILE"
echo "Comment successfully staged locally. Remember to call submit_pr_review.sh when finished to publish all comments as a single review!"
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -euo pipefail
# reply_pr_comment.sh <PR_NUMBER> <COMMENT_ID> <REPLY_BODY>
# Replies to an existing PR comment thread. Note: COMMENT_ID must be the ID of the top-level comment in the thread you are replying to.
if [ "$#" -lt 3 ]; then
echo "Usage: reply_pr_comment.sh <PR_NUMBER> <COMMENT_ID> <REPLY_BODY>"
exit 1
fi
PR_NUMBER="$1"
COMMENT_ID="$2"
BODY="$3"
# Ensure gh cli is installed
if ! command -v gh &> /dev/null; then
echo "Error: gh CLI could not be found. Please install and authenticate."
exit 1
fi
# Get the current repository (e.g., angular/angular)
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
# Reply to the thread using the provided comment ID
gh api \
--silent \
--method POST \
-H "Accept: application/vnd.github+json" \
"/repos/${REPO}/pulls/${PR_NUMBER}/comments/${COMMENT_ID}/replies" \
-f body="$BODY"
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
set -euo pipefail
# submit_pr_review.sh
# Submits a batched PR review using comments previously staged by post_inline_comment.sh
# Usage: ./submit_pr_review.sh <PR_NUMBER> <EVENT_TYPE> [BODY]
# EVENT_TYPE must be COMMENT, APPROVE, or REQUEST_CHANGES
if [ "$#" -lt 2 ]; then
echo "Usage: $0 <PR_NUMBER> <EVENT_TYPE> [BODY]"
echo "EVENT_TYPE must be COMMENT, APPROVE, or REQUEST_CHANGES"
exit 1
fi
PR_NUMBER="$1"
EVENT="$2"
BODY="${3:-}"
COMMENT_FILE="/tmp/angular_pr_${PR_NUMBER}_comments.json"
if ! command -v gh &> /dev/null; then
echo "Error: gh CLI could not be found. Please install and authenticate."
exit 1
fi
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
# Check if there are staged comments
COMMENTS="[]"
if [ -f "$COMMENT_FILE" ]; then
COMMENTS=$(cat "$COMMENT_FILE")
fi
echo "Submitting review for PR #${PR_NUMBER}..."
# Create the payload
PAYLOAD_FILE="/tmp/angular_pr_${PR_NUMBER}_payload.json"
jq -n --arg event "$EVENT" --arg body "$BODY" --argjson comments "$COMMENTS" \
'{event: $event, body: $body, comments: $comments}' > "$PAYLOAD_FILE"
# Post the review using the GitHub Pull Request Reviews API
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/${REPO}/pulls/${PR_NUMBER}/reviews" \
--input "$PAYLOAD_FILE"
echo "Review submitted successfully!"
rm -f "$COMMENT_FILE"
rm -f "$PAYLOAD_FILE"
+56
View File
@@ -0,0 +1,56 @@
---
description: Find and fix flaky tests in the repository
---
Investigate flaky tests in the repo and propose fixes to improve stability.
High-level process:
1. Run tests in the repo to look for flakes.
- Consider using Bazel's `--runs_per_test` flag to easily find
flakes.
- Be cognizant of not exhausting all the resources on the current
machine, run a subset of tests at a time such as
`bazel test //packages/core/...`.
2. Once you find some flakes, focus on one at a time.
3. Create a new branch named `flakes/${relevantNameFromTest}`.
4. Reproduce the flake to the best of your ability.
- Consider using `--test_env JASMINE_RANDOM_SEED=1234` to
replicate the broken test ordering.
5. Debug the test to understand the failure mode.
- Consider temporarily disabling / skipping other tests with `xit`
and `fit` to narrow down where the flake might be coming from if
multiple tests are influencing each other.
- Consider temporarily ignoring Firefox tests with
`--test_tag_filters -firefox` if the flake does not appear to be
browser specific.
- Consider using `--test_sharding_strategy disabled` to run the
test in a single shard.
- Try to understand why the test was _flaky_, not just why it
_failed_. Understanding the inconsistency is important to
finding the correct fix.
6. Attempt a fix and validate with `--runs_per_test`.
- Iterate on the fix until you have something which appears to
work.
- If you find yourself stuck and not making meaningful progress,
note down what you've learned/where you're struggling, commit
what you have, look for another flake to fix, and continue. At
the end, surface to the user what you failed to fix.
- Don't try to make significant changes to Angular's runtime
behavior, focus just on making the test pass/fail consistently.
7. Commit the change with relevant details in the commit message and
move on to the next test.
- Be sure to include your theory of why the test was flaky and
how this fix eliminates or reduces that flakiness.
8. Iterate as many times as the user requests you to (default 5
branches if not otherwise specified).
9. Once you can't find any flaky tests or have iterated as many times
as requested, stop and inform the user what you found and fixed.
Additional notes:
- Multiple fixes including the same/related files can go in the same
commit or multiple commits on the same branch.
- Distinct test fixes should go in different branches, make a new one
for each investigation.
- You may push these branches to `origin`, but do not create PRs for
them.
+2 -1
View File
@@ -7,4 +7,5 @@ code_review:
help: false
summary: false
code_review: false
ignore_patterns: []
ignore_patterns:
- pnpm-lock.yaml
+136 -36
View File
@@ -10481,7 +10481,7 @@ var JSONStringify = (value, replacer, space) => {
const convertedToCustomJSON = originalStringify(
value,
(key, value2) => {
const isNoise = typeof value2 === "string" && Boolean(value2.match(noiseValue));
const isNoise = typeof value2 === "string" && noiseValue.test(value2);
if (isNoise)
return value2.toString() + "n";
if (typeof value2 === "bigint")
@@ -10501,12 +10501,29 @@ var JSONStringify = (value, replacer, space) => {
const denoisedJSON = processedJSON.replace(noiseStringify, "$1$2$3");
return denoisedJSON;
};
var isContextSourceSupported = () => JSON.parse("1", (_, __, context3) => !!context3 && context3.source === "1");
var featureCache = /* @__PURE__ */ new Map();
var isContextSourceSupported = () => {
const parseFingerprint = JSON.parse.toString();
if (featureCache.has(parseFingerprint)) {
return featureCache.get(parseFingerprint);
}
try {
const result = JSON.parse(
"1",
(_, __, context3) => !!context3?.source && context3.source === "1"
);
featureCache.set(parseFingerprint, result);
return result;
} catch {
featureCache.set(parseFingerprint, false);
return false;
}
};
var convertMarkedBigIntsReviver = (key, value, context3, userReviver) => {
const isCustomFormatBigInt = typeof value === "string" && value.match(customFormat);
const isCustomFormatBigInt = typeof value === "string" && customFormat.test(value);
if (isCustomFormatBigInt)
return BigInt(value.slice(0, -1));
const isNoiseValue = typeof value === "string" && value.match(noiseValue);
const isNoiseValue = typeof value === "string" && noiseValue.test(value);
if (isNoiseValue)
return value.slice(0, -1);
if (typeof userReviver !== "function")
@@ -10538,7 +10555,7 @@ var JSONParse = (text, reviver) => {
stringsOrLargeNumbers,
(text2, digits, fractional, exponential) => {
const isString = text2[0] === '"';
const isNoise = isString && Boolean(text2.match(noiseValueWithQuotes));
const isNoise = isString && noiseValueWithQuotes.test(text2);
if (isNoise)
return text2.substring(0, text2.length - 1) + 'n"';
const isFractionalOrExponential = fractional || exponential;
@@ -19231,7 +19248,7 @@ var ChildProcess = class {
return new Promise((resolve5, reject) => {
const commandText = `${command2} ${args.join(" ")}`;
Log.debug(`Executing command: ${commandText}`);
const childProcess = _spawn(command2, args, { ...options, shell: true, stdio: "inherit" });
const childProcess = _spawn(command2, args, { ...options, stdio: "inherit" });
childProcess.on("close", (status) => status === 0 ? resolve5() : reject(status));
});
}
@@ -19239,7 +19256,7 @@ var ChildProcess = class {
const commandText = `${command2} ${args.join(" ")}`;
const env22 = getEnvironmentForNonInteractiveCommand(options.env);
Log.debug(`Executing command: ${commandText}`);
const { status: exitCode, signal, stdout, stderr } = _spawnSync(command2, args, { ...options, env: env22, encoding: "utf8", shell: true, stdio: "pipe" });
const { status: exitCode, signal, stdout, stderr } = _spawnSync(command2, args, { ...options, env: env22, encoding: "utf8", stdio: "pipe" });
const status = statusFromExitCodeAndSignal(exitCode, signal);
if (status === 0 || options.suppressErrorOnFailingExitCode) {
return { status, stdout, stderr };
@@ -19249,7 +19266,7 @@ var ChildProcess = class {
static spawn(command2, args, options = {}) {
const commandText = `${command2} ${args.join(" ")}`;
const env22 = getEnvironmentForNonInteractiveCommand(options.env);
return processAsyncCmd(commandText, options, _spawn(command2, args, { ...options, env: env22, shell: true, stdio: "pipe" }));
return processAsyncCmd(commandText, options, _spawn(command2, args, { ...options, env: env22, stdio: "pipe" }));
}
static exec(command2, options = {}) {
const env22 = getEnvironmentForNonInteractiveCommand(options.env);
@@ -19304,7 +19321,7 @@ ${logOutput}`);
});
}
function determineRepoBaseDirFromCwd() {
const { stdout, stderr, status } = ChildProcess.spawnSync("git", ["rev-parse --show-toplevel"]);
const { stdout, stderr, status } = ChildProcess.spawnSync("git", ["rev-parse", "--show-toplevel"]);
if (status !== 0) {
throw Error(`Unable to find the path to the base directory of the repository.
Was the command run from inside of the repo?
@@ -22961,6 +22978,7 @@ var require_stringify = __commonJS2({
nullStr: "null",
simpleKeys: false,
singleQuote: null,
trailingComma: false,
trueStr: "true",
verifyAliasOrder: true
}, doc.schema.toStringOptions, options);
@@ -23466,12 +23484,19 @@ ${indent}${line}` : "\n";
if (comment)
reqNewline = true;
let str = stringify.stringify(item, itemCtx, () => comment = null);
if (i < items.length - 1)
reqNewline || (reqNewline = lines.length > linesAtValue || str.includes("\n"));
if (i < items.length - 1) {
str += ",";
} else if (ctx.options.trailingComma) {
if (ctx.options.lineWidth > 0) {
reqNewline || (reqNewline = lines.reduce((sum, line) => sum + line.length + 2, 2) + (str.length + 2) > ctx.options.lineWidth);
}
if (reqNewline) {
str += ",";
}
}
if (comment)
str += stringifyComment.lineComment(str, itemIndent, commentString(comment));
if (!reqNewline && (lines.length > linesAtValue || str.includes("\n")))
reqNewline = true;
lines.push(str);
linesAtValue = lines.length;
}
@@ -26401,17 +26426,22 @@ var require_compose_node = __commonJS2({
case "block-map":
case "block-seq":
case "flow-collection":
node = composeCollection.composeCollection(CN, ctx, token, props, onError);
if (anchor)
node.anchor = anchor.source.substring(1);
try {
node = composeCollection.composeCollection(CN, ctx, token, props, onError);
if (anchor)
node.anchor = anchor.source.substring(1);
} catch (error2) {
const message = error2 instanceof Error ? error2.message : String(error2);
onError(token, "RESOURCE_EXHAUSTION", message);
}
break;
default: {
const message = token.type === "error" ? token.message : `Unsupported token (type: ${token.type})`;
onError(token, "UNEXPECTED_TOKEN", message);
node = composeEmptyNode(ctx, token.offset, void 0, null, props, onError);
isSrcToken = false;
}
}
node ?? (node = composeEmptyNode(ctx, token.offset, void 0, null, props, onError));
if (anchor && node.anchor === "")
onError(anchor, "BAD_ALIAS", "Anchor cannot be an empty string");
if (atKey && ctx.options.stringKeys && (!identity.isScalar(node) || typeof node.value !== "string" || node.tag && node.tag !== "tag:yaml.org,2002:str")) {
@@ -29176,7 +29206,7 @@ var JSONStringify2 = (value, replacer, space) => {
const convertedToCustomJSON = originalStringify2(
value,
(key, value2) => {
const isNoise = typeof value2 === "string" && Boolean(value2.match(noiseValue2));
const isNoise = typeof value2 === "string" && noiseValue2.test(value2);
if (isNoise)
return value2.toString() + "n";
if (typeof value2 === "bigint")
@@ -29196,12 +29226,29 @@ var JSONStringify2 = (value, replacer, space) => {
const denoisedJSON = processedJSON.replace(noiseStringify2, "$1$2$3");
return denoisedJSON;
};
var isContextSourceSupported2 = () => JSON.parse("1", (_, __, context3) => !!context3 && context3.source === "1");
var featureCache2 = /* @__PURE__ */ new Map();
var isContextSourceSupported2 = () => {
const parseFingerprint = JSON.parse.toString();
if (featureCache2.has(parseFingerprint)) {
return featureCache2.get(parseFingerprint);
}
try {
const result = JSON.parse(
"1",
(_, __, context3) => !!context3?.source && context3.source === "1"
);
featureCache2.set(parseFingerprint, result);
return result;
} catch {
featureCache2.set(parseFingerprint, false);
return false;
}
};
var convertMarkedBigIntsReviver2 = (key, value, context3, userReviver) => {
const isCustomFormatBigInt = typeof value === "string" && value.match(customFormat2);
const isCustomFormatBigInt = typeof value === "string" && customFormat2.test(value);
if (isCustomFormatBigInt)
return BigInt(value.slice(0, -1));
const isNoiseValue = typeof value === "string" && value.match(noiseValue2);
const isNoiseValue = typeof value === "string" && noiseValue2.test(value);
if (isNoiseValue)
return value.slice(0, -1);
if (typeof userReviver !== "function")
@@ -29233,7 +29280,7 @@ var JSONParse2 = (text, reviver) => {
stringsOrLargeNumbers2,
(text2, digits, fractional, exponential) => {
const isString = text2[0] === '"';
const isNoise = isString && Boolean(text2.match(noiseValueWithQuotes2));
const isNoise = isString && noiseValueWithQuotes2.test(text2);
if (isNoise)
return text2.substring(0, text2.length - 1) + 'n"';
const isFractionalOrExponential = fractional || exponential;
@@ -32535,6 +32582,54 @@ var types = (
return types2;
}()
);
async function invokeWithRetry(fn, retries = 3, delay = 1e3) {
let attempt = 0;
while (attempt < retries) {
try {
return await fn();
} catch (e) {
attempt++;
if (attempt >= retries) {
throw e;
}
if (isGithubApiError(e) && e.status < 500) {
throw e;
}
if (e instanceof GraphqlResponseError2) {
if (!e.errors) {
throw e;
}
if (e.errors.every((err) => ["NOT_FOUND", "FORBIDDEN", "BAD_USER_INPUT", "UNAUTHENTICATED"].includes(err.type))) {
throw e;
}
}
Log.warn(`GitHub API call failed (attempt ${attempt}/${retries}). Retrying in ${delay}ms...`);
await new Promise((resolve22) => setTimeout(resolve22, delay));
}
}
throw new Error("Unreachable");
}
function createRetryProxy(target) {
return new Proxy(target, {
get(targetObj, prop, receiver) {
const value = Reflect.get(targetObj, prop, receiver);
if (typeof value === "function") {
return new Proxy(value, {
apply(targetFn, thisArg, argArray) {
return invokeWithRetry(() => targetFn.apply(targetObj, argArray));
}
});
}
if (typeof value === "object" && value !== null) {
return createRetryProxy(value);
}
return value;
},
apply(targetFn, thisArg, argArray) {
return invokeWithRetry(() => targetFn.apply(thisArg, argArray));
}
});
}
var GithubClient = class {
constructor(_octokitOptions) {
this._octokitOptions = _octokitOptions;
@@ -32547,18 +32642,18 @@ var GithubClient = class {
},
...this._octokitOptions
});
this.pulls = this._octokit.pulls;
this.orgs = this._octokit.orgs;
this.repos = this._octokit.repos;
this.issues = this._octokit.issues;
this.git = this._octokit.git;
this.rateLimit = this._octokit.rateLimit;
this.teams = this._octokit.teams;
this.search = this._octokit.search;
this.rest = this._octokit.rest;
this.paginate = this._octokit.paginate;
this.checks = this._octokit.checks;
this.users = this._octokit.users;
this.pulls = createRetryProxy(this._octokit.pulls);
this.orgs = createRetryProxy(this._octokit.orgs);
this.repos = createRetryProxy(this._octokit.repos);
this.issues = createRetryProxy(this._octokit.issues);
this.git = createRetryProxy(this._octokit.git);
this.rateLimit = createRetryProxy(this._octokit.rateLimit);
this.teams = createRetryProxy(this._octokit.teams);
this.search = createRetryProxy(this._octokit.search);
this.rest = createRetryProxy(this._octokit.rest);
this.paginate = createRetryProxy(this._octokit.paginate);
this.checks = createRetryProxy(this._octokit.checks);
this.users = createRetryProxy(this._octokit.users);
}
};
var AuthenticatedGithubClient = class extends GithubClient {
@@ -32570,9 +32665,14 @@ var AuthenticatedGithubClient = class extends GithubClient {
});
}
async graphql(queryObject, params2 = {}) {
return await this._graphql(query(queryObject).toString(), params2);
return invokeWithRetry(async () => {
return await this._graphql(query(queryObject).toString(), params2);
});
}
};
function isGithubApiError(obj) {
return obj instanceof Error && obj.constructor.name === "RequestError" && obj.request !== void 0;
}
function isDryRun() {
return process.env["DRY_RUN"] !== void 0;
}
@@ -33495,7 +33595,7 @@ tmp/lib/tmp.js:
(* v8 ignore next -- @preserve *)
(* v8 ignore else -- @preserve *)
@angular/ng-dev/bundles/chunk-YN3IWAKJ.mjs:
@angular/ng-dev/bundles/chunk-G7GMCCSS.mjs:
(*! Bundled license information:
yargs-parser/build/lib/string-utils.js:
@@ -33536,7 +33636,7 @@ tmp/lib/tmp.js:
*)
*)
@angular/ng-dev/bundles/chunk-34WCNHIG.mjs:
@angular/ng-dev/bundles/chunk-PTDPQBIK.mjs:
(*! Bundled license information:
@octokit/request-error/dist-src/index.js:
+2 -2
View File
@@ -5,9 +5,9 @@ runs:
using: 'composite'
steps:
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Saucelabs Variables
uses: angular/dev-infra/github-actions/saucelabs@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/saucelabs@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Starting Saucelabs tunnel service
shell: bash
run: ./tools/saucelabs/sauce-service.sh run &
+4 -4
View File
@@ -21,17 +21,17 @@ jobs:
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'adev: preview'))
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Build adev
# `snapshot-build` config is used to stamp the exact version with sha in the footer.
run: pnpm bazel build //adev:build.production --config=snapshot-build
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
workflow-artifact-name: 'adev-preview'
pull-number: '${{github.event.pull_request.number}}'
+5 -3
View File
@@ -32,15 +32,17 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: '${{secrets.GITHUB_TOKEN}}'
persist-credentials: false
- name: Configure Firebase deploy target
working-directory: ./
run: |
# We can use `npx` as the Firebase deploy actions uses it too.
npx -y firebase-tools@latest target:clear --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs
npx -y firebase-tools@latest target:apply --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs ${{env.PREVIEW_SITE}}
# Use stable version release
npx -y firebase-tools@15.15.0 target:clear --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs
npx -y firebase-tools@15.15.0 target:apply --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs ${{env.PREVIEW_SITE}}
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
github-token: '${{secrets.GITHUB_TOKEN}}'
workflow-artifact-name: 'adev-preview'
@@ -17,6 +17,6 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: angular/dev-infra/github-actions/branch-manager@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
- uses: angular/dev-infra/github-actions/branch-manager@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
+5 -4
View File
@@ -25,7 +25,7 @@ jobs:
token: '${{secrets.BENCHMARK_POST_RESULTS_GITHUB_TOKEN}}'
reactions: 'rocket'
- uses: alessbell/pull-request-comment-branch@aad01d65d6982b8eacabed5e9a684cd8ceb98da6 # v1.1
- uses: alessbell/pull-request-comment-branch@653a7d5ca8bd91d3c5cb83286063314d0b063b8e # v1.4.0
id: comment-branch
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -34,11 +34,11 @@ jobs:
repository: ${{steps.comment-branch.outputs.head_owner}}/${{steps.comment-branch.outputs.head_repo}}
# Checkout the pull request and assume it being trusted given we've checked
# that the action was triggered by a team member.
ref: ${{steps.comment-branch.outputs.head_ref}}
ref: ${{steps.comment-branch.outputs.head_sha}}
- run: pnpm install --frozen-lockfile
- uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
- uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
bazelrc: ./.bazelrc.user
@@ -49,7 +49,8 @@ jobs:
COMMENT_BODY: ${{ github.event.comment.body }}
run: pnpm benchmarks prepare-for-github-action "$COMMENT_BODY"
- run: pnpm benchmarks run-compare ${{steps.info.outputs.compareSha}} ${{steps.info.outputs.benchmarkTarget}}
- run: pnpm benchmarks run-compare ${{steps.info.outputs.compareSha}} "${{steps.info.outputs.benchmarkTarget}}"
id: benchmark
name: Running benchmark
+26 -26
View File
@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Check code lint
@@ -41,13 +41,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
disable-package-manager-cache: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
@@ -57,7 +57,7 @@ jobs:
- name: Test build
run: pnpm devtools:build:chrome
- name: Cypress run
uses: cypress-io/github-action@bc22e01685c56e89e7813fd8e26f33dc47f87e15 # v7.1.5
uses: cypress-io/github-action@c495c3ddffba403ba11be95fffb67e25203b3799 # v7.1.10
with:
command: pnpm devtools:test:e2e
start: pnpm bazel run //devtools/src:devserver
@@ -69,11 +69,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
@@ -85,11 +85,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
@@ -102,11 +102,11 @@ jobs:
labels: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
@@ -121,11 +121,11 @@ jobs:
labels: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
@@ -138,11 +138,11 @@ jobs:
labels: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Install node modules
run: pnpm install --frozen-lockfile
- run: echo "https://${{secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN}}:@github.com" > ${HOME}/.git_credentials
@@ -154,11 +154,11 @@ jobs:
labels: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
@@ -208,11 +208,11 @@ jobs:
runs-on: ubuntu-latest-8core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Build adev
+1 -1
View File
@@ -37,7 +37,7 @@ jobs:
ANGULAR_READONLY_GITHUB_TOKEN: ${{ secrets.READONLY_GITHUB_TOKEN }}
- name: Create a PR (if necessary)
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
token: ${{ secrets.ANGULAR_ROBOT_ACCESS_TOKEN }}
push-to-fork: 'angular-robot/angular'
+3 -3
View File
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: angular/dev-infra/github-actions/labeling/pull-request@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
- uses: angular/dev-infra/github-actions/labeling/pull-request@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
labels: '{"requires: TGP": ["packages/core/primitives/**/{*,.*}"]}'
@@ -25,14 +25,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: angular/dev-infra/github-actions/post-approval-changes@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
- uses: angular/dev-infra/github-actions/post-approval-changes@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
issue_labels:
if: github.event_name == 'issues'
runs-on: ubuntu-latest
steps:
- uses: angular/dev-infra/github-actions/labeling/issue@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
- uses: angular/dev-infra/github-actions/labeling/issue@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
google-generative-ai-key: ${{ secrets.GOOGLE_GENERATIVE_AI_KEY }}
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: angular/dev-infra/github-actions/google-internal-tests@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
- uses: angular/dev-infra/github-actions/google-internal-tests@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
run-tests-guide-url: http://go/angular-g3sync-start
github-token: ${{ secrets.GITHUB_TOKEN }}
+4 -4
View File
@@ -13,15 +13,15 @@ jobs:
JOBS: 2
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Saucelabs Variables
uses: angular/dev-infra/github-actions/saucelabs@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/saucelabs@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Set up Sauce Tunnel Daemon
run: pnpm bazel run //tools/saucelabs-daemon/background-service -- $JOBS &
env:
+1 -1
View File
@@ -9,6 +9,6 @@ jobs:
status:
runs-on: ubuntu-latest
steps:
- uses: angular/dev-infra/github-actions/unified-status-check@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
- uses: angular/dev-infra/github-actions/unified-status-check@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
+3 -3
View File
@@ -21,7 +21,7 @@ jobs:
workflows: ${{ steps.workflows.outputs.workflows }}
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Install node modules
run: pnpm install --frozen-lockfile
- id: workflows
@@ -36,9 +36,9 @@ jobs:
workflow: ${{ fromJSON(needs.list.outputs.workflows) }}
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Install node modules
run: pnpm install --frozen-lockfile
# We utilize the google-github-actions/auth action to allow us to get an active credential using workflow
+21 -21
View File
@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Check code lint
@@ -39,7 +39,7 @@ jobs:
- name: Check code format
run: pnpm ng-dev format changed --check ${{ github.event.pull_request.base.sha }}
- name: Check Package Licenses
uses: angular/dev-infra/github-actions/linting/licenses@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/linting/licenses@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
allow-dependencies-licenses: 'pkg:npm/google-protobuf@'
@@ -47,13 +47,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
with:
disable-package-manager-cache: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Run unit tests
@@ -61,7 +61,7 @@ jobs:
- name: Test build
run: pnpm devtools:build:chrome
- name: Cypress run
uses: cypress-io/github-action@bc22e01685c56e89e7813fd8e26f33dc47f87e15 # v7.1.5
uses: cypress-io/github-action@c495c3ddffba403ba11be95fffb67e25203b3799 # v7.1.10
with:
command: pnpm devtools:test:e2e
start: pnpm bazel run //devtools/src:devserver
@@ -73,11 +73,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Run CI tests for framework
@@ -97,11 +97,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Run integration CI tests for framework
@@ -112,11 +112,11 @@ jobs:
labels: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Run tests
@@ -129,11 +129,11 @@ jobs:
labels: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Run tests
@@ -144,11 +144,11 @@ jobs:
labels: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
- name: Install node modules
run: pnpm install --frozen-lockfile
- run: |
+1 -1
View File
@@ -47,6 +47,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: 'Upload to code-scanning'
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
with:
sarif_file: results.sarif
+1 -1
View File
@@ -1 +1 @@
22.22.1
22.22.2
+10 -10
View File
@@ -99,7 +99,7 @@ groups:
reviewers:
users:
- ~alxhub
- AndrewKushnir
- ~AndrewKushnir
- atscott
- crisbeto
- devversion
@@ -145,7 +145,7 @@ groups:
reviewers:
users:
- ~alxhub
- AndrewKushnir
- ~AndrewKushnir
- atscott
- crisbeto
- devversion
@@ -200,7 +200,7 @@ groups:
users:
- ~JiaLiPassion
- ~alxhub
- AndrewKushnir
- ~AndrewKushnir
- atscott
- crisbeto
- devversion
@@ -250,7 +250,7 @@ groups:
users:
- alan-agius4
- ~alxhub
- AndrewKushnir
- ~AndrewKushnir
- atscott
- bencodezen
- crisbeto
@@ -372,7 +372,7 @@ groups:
])
reviewers:
users:
- AndrewKushnir
- ~AndrewKushnir
- ~alxhub
- atscott
- thePunderWoman
@@ -408,7 +408,7 @@ groups:
reviewers:
users:
- ~alxhub
- AndrewKushnir
- ~AndrewKushnir
- atscott
- kirjs
- thePunderWoman
@@ -434,7 +434,7 @@ groups:
])
reviewers:
users:
- marktechson
- MarkTechson
- kirjs
- ~JeanMeche
- ~dgp1130
@@ -456,7 +456,7 @@ groups:
reviewers:
users:
- ~alxhub
- AndrewKushnir
- ~AndrewKushnir
- andrewseguin
- dgp1130
- thePunderWoman
@@ -479,7 +479,7 @@ groups:
- ~pkozlowski-opensource # Pawel Kozlowski
- ~alxhub # Alex Rickabaugh
- thePunderWoman # Jessica Janiuk
- AndrewKushnir # Andrew Kushnir
- ~AndrewKushnir # Andrew Kushnir
- atscott # Andrew Scott
# External team required reviews
@@ -487,7 +487,7 @@ groups:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
contains_any_globs(files.exclude('packages/core/primitives/**/*spec.ts'), [
'packages/core/primitives/**/{*,.*}',
])
reviewers:
+178
View File
@@ -1,3 +1,181 @@
<a name="21.2.12"></a>
# 21.2.12 (2026-05-06)
### core
| Commit | Type | Description |
| -- | -- | -- |
| [fe13bb669d](https://github.com/angular/angular/commit/fe13bb669d2bfab4713623d17b41c430aa0a61d8) | fix | allow explicit read generic with signal input transforms |
| [3430251fef](https://github.com/angular/angular/commit/3430251fef93f6aec1fa9c7867e85df23f67c9a0) | fix | i18n flags leaking on errors |
| [1aeebbe304](https://github.com/angular/angular/commit/1aeebbe3048b5aa612dd0a5448de9883ed51e7e8) | fix | respect ngSkipHydration on components with projectable nodes in LContainers |
| [9e38ed7d57](https://github.com/angular/angular/commit/9e38ed7d5773a9193ba07afdba3f7a9f2fe02d18) | fix | sanitizer typings |
| [7a05a9a71a](https://github.com/angular/angular/commit/7a05a9a71a5ab75042ec5560c01526de6e61e062) | fix | validate security-sensitive attributes in i18n bindings |
| [c37f6ca42f](https://github.com/angular/angular/commit/c37f6ca42f263353cb9563fa90d7b31d3c7837ca) | fix | visit ng-let expression value in signal migration schematics |
### forms
| Commit | Type | Description |
| -- | -- | -- |
| [03ad53863b](https://github.com/angular/angular/commit/03ad53863bf3c368f0f02a4322d4141e8f70f674) | fix | prohibit concurrent submits in signal forms |
<!-- CHANGELOG SPLIT MARKER -->
<a name="21.2.11"></a>
# 21.2.11 (2026-04-29)
### common
| Commit | Type | Description |
| -- | -- | -- |
| [10ad3c0692](https://github.com/angular/angular/commit/10ad3c06923453ae0ec06b06e664ce05900a4ff6) | fix | prevent focus from scrollToAnchor |
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [4f5d8a2c0b](https://github.com/angular/angular/commit/4f5d8a2c0b5e38d4debc4293945270cea4a9590d) | fix | let declaration span not including end character |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [a40e2cebc8](https://github.com/angular/angular/commit/a40e2cebc878965c3e21bfb61658f3f80cbd2ebf) | fix | fix ordering of view queries metadata in JIT mode |
| [885a1a1d97](https://github.com/angular/angular/commit/885a1a1d9757adfa8766d9b369c848a277438c31) | fix | guard against non-object events and avoid listener wrapper identity mismatch |
| [7a64aff9b5](https://github.com/angular/angular/commit/7a64aff9b59999077ea915486a7fa0b97a286659) | fix | prevent event replay double-invocation when element hydrates before app stability |
### platform-server
| Commit | Type | Description |
| -- | -- | -- |
| [be1f80a253](https://github.com/angular/angular/commit/be1f80a253b8ee27ed7d8de2287d6895c4821909) | fix | ensure origin has a trailing slash when parsing url |
<!-- CHANGELOG SPLIT MARKER -->
<a name="21.2.10"></a>
# 21.2.10 (2026-04-22)
### docs
| Commit | Type | Description |
| -- | -- | -- |
| [0d5ee9ae1b](https://github.com/angular/angular/commit/0d5ee9ae1ba4b7acd8f27a059a778f0b4bd8a5bd) | fix | link formatting in "Animating your Application with CSS" |
### migrations
| Commit | Type | Description |
| -- | -- | -- |
| [5533ab4f56](https://github.com/angular/angular/commit/5533ab4f56f574bc9365cf0573c4a34a3ab5aaf1) | fix | fix NgClass leaving trailing comma after removal |
### router
| Commit | Type | Description |
| -- | -- | -- |
| [580212c995](https://github.com/angular/angular/commit/580212c995751c4bf4ce8a49df4167498743e0ea) | fix | restore internal URL on popstate when `browserUrl` is used |
<!-- CHANGELOG SPLIT MARKER -->
<a name="21.2.9"></a>
# 21.2.9 (2026-04-15)
### core
| Commit | Type | Description |
| -- | -- | -- |
| [f603d4714f](https://github.com/angular/angular/commit/f603d4714fa184aad34a6f7f9ea4e79c8af3afac) | fix | escape forward slashes in transfer state to prevent crawler indexing |
### http
| Commit | Type | Description |
| -- | -- | -- |
| [540536c386](https://github.com/angular/angular/commit/540536c386f2c735a700c2c9e2697a88dcb3d4ec) | fix | add CSP nonce support to JsonpClientBackend |
| [63a857b874](https://github.com/angular/angular/commit/63a857b874172766451aa75ed3347ba50f0ee229) | fix | Don't on Passthru outside of reactive context |
### platform-server
| Commit | Type | Description |
| -- | -- | -- |
| [e0b5078cf2](https://github.com/angular/angular/commit/e0b5078cf2ebe79a6de85e9123148ae948b3d81d) | fix | prevent SSRF bypasses via protocol-relative and backslash URLs |
### router
| Commit | Type | Description |
| -- | -- | -- |
| [684e9fd53d](https://github.com/angular/angular/commit/684e9fd53daacb9e910f42d98c6017f9e5cb4180) | fix | normalize multiple leading slashes in URL parser |
<!-- CHANGELOG SPLIT MARKER -->
<a name="21.2.8"></a>
# 21.2.8 (2026-04-08)
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [e40d378f3e](https://github.com/angular/angular/commit/e40d378f3e3e7e57a45c8fbd9565ee06a3a6a13f) | fix | handle nested brackets in host object bindings |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [2c6781071f](https://github.com/angular/angular/commit/2c6781071f52d6378a002fba6611bb283fbb2fde) | fix | error for type parameter declarations |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [82192deda9](https://github.com/angular/angular/commit/82192deda9c07113835e6c85af3f2c8c8218cda0) | fix | handle missing serialized container hydration data |
| [057cc6d09d](https://github.com/angular/angular/commit/057cc6d09d234f401a810cfdd3ad14127652b88b) | fix | remove obsolete iOS cursor pointer hack in event delegation |
### language-service
| Commit | Type | Description |
| -- | -- | -- |
| [7797671257](https://github.com/angular/angular/commit/7797671257350665e8b3ceb2bc6a0201829dd338) | fix | get quick info at local var location to align with TS semantics and support type narrowing |
<!-- CHANGELOG SPLIT MARKER -->
<a name="21.2.7"></a>
# 21.2.7 (2026-04-01)
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [fea25d1a60](https://github.com/angular/angular/commit/fea25d1a60ecaba1599d9cd9b8df27109ed195c5) | fix | register SVG animation attributes in URL security context ([#67797](https://github.com/angular/angular/pull/67797)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [bba5ed8e64](https://github.com/angular/angular/commit/bba5ed8e643b9c3f680e7e539c3d744ad6905e59) | fix | prevent recursive scope checks for invalid NgModule imports |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [d04ddd73df](https://github.com/angular/angular/commit/d04ddd73dfc03f420afbdde964c5119f338af135) | fix | prevent binding unsafe attributes on SVG animation elements ([#67797](https://github.com/angular/angular/pull/67797)) |
| [8fd896e99a](https://github.com/angular/angular/commit/8fd896e99a13855c6569f29efe7e578c301e13ee) | fix | resolve component import by exact specifier in route lazy-loading schematic |
| [b682c62873](https://github.com/angular/angular/commit/b682c628731b86a4884e50abb2f5fa73ac0ad057) | fix | treat `object[data]` as resource URL context ([#67797](https://github.com/angular/angular/pull/67797)) |
### localize
| Commit | Type | Description |
| -- | -- | -- |
| [3c41e74fdd](https://github.com/angular/angular/commit/3c41e74fdd279f683156b654699a9312a850add0) | fix | validate locale in getOutputPathFn to prevent path traversal |
### router
| Commit | Type | Description |
| -- | -- | -- |
| [0960592d3d](https://github.com/angular/angular/commit/0960592d3d4fad110d5598144fda9f2488520826) | fix | pass outlet context to split to fix empty path named outlets |
<!-- CHANGELOG SPLIT MARKER -->
<a name="21.2.6"></a>
# 21.2.6 (2026-03-25)
### common
| Commit | Type | Description |
| -- | -- | -- |
| [b4ab6ba2e8](https://github.com/angular/angular/commit/b4ab6ba2e84a18309b0bb5dd68311ff1776b1cb4) | fix | avoid redundant image fetch on destroy with auto sizes |
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [880a57d4b3](https://github.com/angular/angular/commit/880a57d4b34af5aa27cd5bee11fa218ade6444bb) | fix | prevent shimCssText from adding extra blank lines per CSS comment |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [ad0156e056](https://github.com/angular/angular/commit/ad0156e056e60ffebfeb804fda70dce88d9475a8) | fix | fixes a regression with animate.leave and reordering |
### migrations
| Commit | Type | Description |
| -- | -- | -- |
| [73d6b01b47](https://github.com/angular/angular/commit/73d6b01b47bb6762d182f1cd891f8ad4d7f688e1) | fix | inject migration not work in multi-project workspace with option path |
<!-- CHANGELOG SPLIT MARKER -->
<a name="21.2.5"></a>
# 21.2.5 (2026-03-18)
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [334ae10168](https://github.com/angular/angular/commit/334ae10168fdad15cd1390180e2994b4eb65349b) | fix | ensure generated code compiles |
| [23ea431c4e](https://github.com/angular/angular/commit/23ea431c4ec45cbb4a7db9839969e7cb23b07f58) | fix | parse named HTML entities containing digits |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [26c43d14ba](https://github.com/angular/angular/commit/26c43d14baad1a6b3629a77825e702a97a4f8482) | fix | escape template literal in TCB |
| [67e0ba7e03](https://github.com/angular/angular/commit/67e0ba7e03bb940639f0eafb3af45015e9727eac) | fix | generic types not filled out correctly in type check block |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [1890c3008b](https://github.com/angular/angular/commit/1890c3008bbb41b7143b7ede09bed1f7704744fb) | fix | clean up dehydrated views during HMR component replacement |
| [bf948be4c2](https://github.com/angular/angular/commit/bf948be4c2c88c604e428cba35e3b9e532bfe5b0) | fix | run linked signal equality check without reactive consumer |
### migrations
| Commit | Type | Description |
| -- | -- | -- |
| [076d41c3f6](https://github.com/angular/angular/commit/076d41c3f6496eb6c6f84b54e2d2ca85c1b35e64) | fix | prevent trailing comma syntax errors after removing NgStyle |
### service-worker
| Commit | Type | Description |
| -- | -- | -- |
| [e19150d2b5](https://github.com/angular/angular/commit/e19150d2b596e87c69bee61f478c3e9c7cbc8f67) | fix | preserve redirect policy on reconstructed asset requests |
<!-- CHANGELOG SPLIT MARKER -->
<a name="21.2.4"></a>
# 21.2.4 (2026-03-12)
### compiler
+2 -2
View File
@@ -71,7 +71,7 @@ You can file new issues by selecting from our [new issue templates](https://gith
### <a name="pr-quality"></a> Contribution Quality
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:
+24 -26
View File
@@ -5,41 +5,41 @@ module(
)
bazel_dep(name = "rules_pkg", version = "1.2.0")
bazel_dep(name = "rules_nodejs", version = "6.7.3")
bazel_dep(name = "aspect_rules_ts", version = "3.8.6")
bazel_dep(name = "rules_nodejs", version = "6.7.4")
bazel_dep(name = "aspect_rules_ts", version = "3.8.8")
bazel_dep(name = "aspect_rules_js", version = "3.0.3")
bazel_dep(name = "aspect_rules_esbuild", version = "0.25.1")
bazel_dep(name = "aspect_rules_jasmine", version = "2.0.4")
bazel_dep(name = "aspect_rules_rollup", version = "2.0.1")
bazel_dep(name = "bazel_skylib", version = "1.9.0")
bazel_dep(name = "bazel_lib", version = "3.2.2")
bazel_dep(name = "tar.bzl", version = "0.9.0")
bazel_dep(name = "yq.bzl", version = "0.3.5")
bazel_dep(name = "bazel_lib", version = "3.3.1")
bazel_dep(name = "tar.bzl", version = "0.10.1")
bazel_dep(name = "yq.bzl", version = "0.3.6")
bazel_dep(name = "rules_angular")
git_override(
module_name = "rules_angular",
commit = "804515937593ca742f5f119a20774f55a08e70ad",
commit = "b1d295334e70335dab7ac9984a989fae0a9c9dc2",
remote = "https://github.com/angular/rules_angular.git",
)
bazel_dep(name = "devinfra")
git_override(
module_name = "devinfra",
commit = "491fa7fc1803683748875b2b89d85700aca2b1f4",
commit = "48c48fa3848de5bb0ec1c3203558f099765165ab",
remote = "https://github.com/angular/dev-infra.git",
)
bazel_dep(name = "rules_sass")
git_override(
module_name = "rules_sass",
commit = "781c41bf7a48147bb20103e250f7215475e915a1",
commit = "a65d937fabd87672f7245aeaa5eb5a0c5a2abead",
remote = "https://github.com/angular/rules_sass.git",
)
bazel_dep(name = "rules_browsers")
git_override(
module_name = "rules_browsers",
commit = "7043f918640169063a6281ab4afb61389a0aad6d",
commit = "b03f09ef28a08f8ae07482851cf5ecbf6ac23a2a",
remote = "https://github.com/angular/rules_browsers.git",
)
@@ -49,15 +49,15 @@ use_repo(yq, "yq_toolchains")
node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node")
node.toolchain(
node_repositories = {
"22.22.1-darwin_arm64": ("node-v22.22.1-darwin-arm64.tar.gz", "node-v22.22.1-darwin-arm64", "679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"),
"22.22.1-darwin_amd64": ("node-v22.22.1-darwin-x64.tar.gz", "node-v22.22.1-darwin-x64", "07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"),
"22.22.1-linux_arm64": ("node-v22.22.1-linux-arm64.tar.xz", "node-v22.22.1-linux-arm64", "0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"),
"22.22.1-linux_ppc64le": ("node-v22.22.1-linux-ppc64le.tar.xz", "node-v22.22.1-linux-ppc64le", "a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"),
"22.22.1-linux_s390x": ("node-v22.22.1-linux-s390x.tar.xz", "node-v22.22.1-linux-s390x", "e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"),
"22.22.1-linux_amd64": ("node-v22.22.1-linux-x64.tar.xz", "node-v22.22.1-linux-x64", "9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"),
"22.22.1-windows_amd64": ("node-v22.22.1-win-x64.zip", "node-v22.22.1-win-x64", "877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"),
"22.22.2-darwin_arm64": ("node-v22.22.2-darwin-arm64.tar.gz", "node-v22.22.2-darwin-arm64", "db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"),
"22.22.2-darwin_amd64": ("node-v22.22.2-darwin-x64.tar.gz", "node-v22.22.2-darwin-x64", "12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"),
"22.22.2-linux_arm64": ("node-v22.22.2-linux-arm64.tar.xz", "node-v22.22.2-linux-arm64", "e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"),
"22.22.2-linux_ppc64le": ("node-v22.22.2-linux-ppc64le.tar.xz", "node-v22.22.2-linux-ppc64le", "14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"),
"22.22.2-linux_s390x": ("node-v22.22.2-linux-s390x.tar.xz", "node-v22.22.2-linux-s390x", "9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"),
"22.22.2-linux_amd64": ("node-v22.22.2-linux-x64.tar.xz", "node-v22.22.2-linux-x64", "88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"),
"22.22.2-windows_amd64": ("node-v22.22.2-win-x64.zip", "node-v22.22.2-win-x64", "7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"),
},
node_version = "22.22.1",
node_version = "22.22.2",
)
use_repo(node, "nodejs_toolchains")
use_repo(node, "nodejs_darwin_amd64")
@@ -71,8 +71,8 @@ use_repo(node, "nodejs_windows_amd64")
pnpm = use_extension("@aspect_rules_js//npm:extensions.bzl", "pnpm")
pnpm.pnpm(
name = "pnpm",
pnpm_version = "10.32.0",
pnpm_version_integrity = "sha512-myY0uz/tVgHDNjPy2SWT9QYnCjljuMUdKy1qgo2mFc5One6++WFMzrvBOsjTwPnJzM61g8achXhDb6R327INcA==",
pnpm_version = "10.33.2",
pnpm_version_integrity = "sha512-qQ+vb+6rca1sblf5Tg/hoS9dzCLNdU20CulZPraj4LaxLjVAIYuzeuCDQEsfLObbKkEh6XmCm0r/lLmfSdoc+A==",
)
use_repo(pnpm, "pnpm")
@@ -125,14 +125,12 @@ use_repo(rules_ts_ext, **{"npm_typescript": "angular_npm_typescript"})
# TODO: Figure out how to make ng_project update whenever the packages/core::pkg target changes.
rules_angular = use_extension("@rules_angular//setup:extensions.bzl", "rules_angular")
use_repo_rule("@rules_angular//setup:repositories.bzl", "configurable_deps_repo")(
name = "rules_angular_configurable_deps",
angular_compiler_cli = "@angular//:node_modules/@angular/compiler-cli",
typescript = "@angular//:node_modules/typescript",
rules_angular.setup(
name = "angular_rules_angular_configurable_deps",
angular_compiler_cli = "//:node_modules/@angular/compiler-cli",
typescript = "//:node_modules/typescript",
)
override_repo(rules_angular, "rules_angular_configurable_deps")
use_repo(rules_angular, rules_angular_configurable_deps = "angular_rules_angular_configurable_deps")
register_toolchains(
"@devinfra//bazel/git-toolchain:git_linux_toolchain",
+271 -277
View File
@@ -13,29 +13,23 @@
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.0.0/MODULE.bazel": "e118477db5c49419a88d78ebc7a2c2cea9d49600fe0f490c1903324a2c16ecd9",
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.11.0/MODULE.bazel": "cb1ba9f9999ed0bc08600c221f532c1ddd8d217686b32ba7d45b0713b5131452",
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.14.0/MODULE.bazel": "2b31ffcc9bdc8295b2167e07a757dbbc9ac8906e7028e5170a3708cecaac119f",
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.19.2/MODULE.bazel": "30dfabbfae0139b1f0036e01c201dd4c0167da3017f0b7ef3820d78e07622989",
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.19.3/MODULE.bazel": "253d739ba126f62a5767d832765b12b59e9f8d2bc88cc1572f4a73e46eb298ca",
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.22.5/MODULE.bazel": "004ba890363d05372a97248c37205ae64b6fa31047629cd2c0895a9d0c7779e8",
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.22.5/source.json": "ac2c3213df8f985785f1d0aeb7f0f73d5324e6e67d593d9b9470fb74a25d4a9b",
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.7.7/MODULE.bazel": "491f8681205e31bb57892d67442ce448cda4f472a8e6b3dc062865e29a64f89c",
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.8.1/MODULE.bazel": "812d2dd42f65dca362152101fbec418029cc8fd34cbad1a2fde905383d705838",
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.9.3/MODULE.bazel": "66baf724dbae7aff4787bf2245cc188d50cb08e07789769730151c0943587c14",
"https://bcr.bazel.build/modules/aspect_rules_esbuild/0.25.0/MODULE.bazel": "5fef5ec709c837312823f9bcf0f276661e2cb48ad52f17c4e01176bbf1e9bf58",
"https://bcr.bazel.build/modules/aspect_rules_esbuild/0.25.1/MODULE.bazel": "9b931b3e483bd8eedb6966bda6df07d801f70ccb4896231b4e5e711b5130f3aa",
"https://bcr.bazel.build/modules/aspect_rules_esbuild/0.25.1/source.json": "a0b72e23ed06113f3878cb635d586b4045ef37750983467af72fe0315c3a2fcd",
"https://bcr.bazel.build/modules/aspect_rules_jasmine/2.0.4/MODULE.bazel": "fbb819eb8b7e5d7f67fdd38f7cecb413e287594cd666ce192c72c8828527775a",
"https://bcr.bazel.build/modules/aspect_rules_jasmine/2.0.4/source.json": "81ffb708333cd98ec3c0b4cc004f4d5cf92a16914b5196a2892c45141bba7cff",
"https://bcr.bazel.build/modules/aspect_rules_js/2.0.0/MODULE.bazel": "b45b507574aa60a92796e3e13c195cd5744b3b8aff516a9c0cb5ae6a048161c5",
"https://bcr.bazel.build/modules/aspect_rules_js/2.4.2/MODULE.bazel": "0d01db38b96d25df7ed952a5e96eac4b3802723d146961974bf020f6dd07591d",
"https://bcr.bazel.build/modules/aspect_rules_js/3.0.2/MODULE.bazel": "c5d22d2db2a2f0cf41ec2028ded2e2543d7ff1ea9f6faf5d6b2791546ee1d6a9",
"https://bcr.bazel.build/modules/aspect_rules_js/3.0.3/MODULE.bazel": "28a30e8fc33bf64a67835d64d124f6e05a7d59648dcb27b110fb3502f761e503",
"https://bcr.bazel.build/modules/aspect_rules_js/3.0.3/source.json": "bb8fff9a304452e1042af9522ad1d54d6f1d1fdf71c5127deadb6fd156654193",
"https://bcr.bazel.build/modules/aspect_rules_rollup/2.0.1/MODULE.bazel": "296e3a053658c2af989ba9bd62a205e6d1fa84bdd6dd5249196546e6b84770ec",
"https://bcr.bazel.build/modules/aspect_rules_rollup/2.0.1/source.json": "2fe8ac1ccb4de74bf884761e070010280b272d94e3997205b361b91c75409726",
"https://bcr.bazel.build/modules/aspect_rules_ts/3.6.3/MODULE.bazel": "d09db394970f076176ce7bab5b5fa7f0d560fd4f30b8432ea5e2c2570505b130",
"https://bcr.bazel.build/modules/aspect_rules_ts/3.8.5/MODULE.bazel": "bcf8f0b6b9375f0f74451e2f70671efae9bb366acef8fdc04675305eaf137f06",
"https://bcr.bazel.build/modules/aspect_rules_ts/3.8.6/MODULE.bazel": "371bacab13c9c36323384b56c7cabfde1982b69674e78729e1ddd1edd54d984e",
"https://bcr.bazel.build/modules/aspect_rules_ts/3.8.6/source.json": "b87a583fa2aa5c546221e3c514c883b2344c9284f27347759a5ff700deceb012",
"https://bcr.bazel.build/modules/aspect_tools_telemetry/0.2.3/MODULE.bazel": "20f53b145f40957a51077ae90b37b7ce83582a1daf9350349f0f86179e19dd0d",
"https://bcr.bazel.build/modules/aspect_rules_ts/3.8.8/MODULE.bazel": "b52b929a948438665809d49af610f58d1b14f63d6d21ab748f47b6050be4c1f6",
"https://bcr.bazel.build/modules/aspect_rules_ts/3.8.8/source.json": "5414530b761a45ab7ca6c49f0a2a9cf8dc0da772f5037cf05ca18aaa64bb1b19",
"https://bcr.bazel.build/modules/aspect_tools_telemetry/0.2.6/MODULE.bazel": "cafb8781ad591bc57cc765dca5fefab08cf9f65af363d162b79d49205c7f8af7",
"https://bcr.bazel.build/modules/aspect_tools_telemetry/0.2.8/MODULE.bazel": "aa975a83e72bcaac62ee61ab12b788ea324a1d05c4aab28aadb202f647881679",
"https://bcr.bazel.build/modules/aspect_tools_telemetry/0.3.3/MODULE.bazel": "37c764292861c2f70314efa9846bb6dbb44fc0308903b3285da6528305450183",
@@ -59,13 +53,13 @@
"https://bcr.bazel.build/modules/bazel_lib/3.0.0-rc.0/MODULE.bazel": "d6e00979a98ac14ada5e31c8794708b41434d461e7e7ca39b59b765e6d233b18",
"https://bcr.bazel.build/modules/bazel_lib/3.0.0/MODULE.bazel": "22b70b80ac89ad3f3772526cd9feee2fa412c2b01933fea7ed13238a448d370d",
"https://bcr.bazel.build/modules/bazel_lib/3.2.2/MODULE.bazel": "e2c890c8a515d6bca9c66d47718aa9e44b458fde64ec7204b8030bf2d349058c",
"https://bcr.bazel.build/modules/bazel_lib/3.2.2/source.json": "9e84e115c20e14652c5c21401ae85ff4daa8702e265b5c0b3bf89353f17aa212",
"https://bcr.bazel.build/modules/bazel_lib/3.3.1/MODULE.bazel": "732a0d516cf6400d9b3136e4356258aef1bf91de8d5240f87f0112f098920c1d",
"https://bcr.bazel.build/modules/bazel_lib/3.3.1/source.json": "8e5175d7b4125a39b8941d01e38039934d058e03804f46a2b8fd7ae6316b1ce2",
"https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8",
"https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e",
"https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686",
"https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a",
"https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5",
"https://bcr.bazel.build/modules/bazel_skylib/1.4.0/MODULE.bazel": "2ab127ef8d56a739a99bb2ce00ec4c7d1ecc7977d4370c0ca6efd0d8f03d6d99",
"https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d",
"https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651",
"https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138",
@@ -88,7 +82,8 @@
"https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f",
"https://bcr.bazel.build/modules/jq.bzl/0.1.0/MODULE.bazel": "2ce69b1af49952cd4121a9c3055faa679e748ce774c7f1fda9657f936cae902f",
"https://bcr.bazel.build/modules/jq.bzl/0.4.0/MODULE.bazel": "a7b39b37589f2b0dad53fd6c1ccaabbdb290330caa920d7ef3e6aad068cd4ab2",
"https://bcr.bazel.build/modules/jq.bzl/0.4.0/source.json": "52ec7530c4618e03f634b30ff719814a68d7d39c235938b7aa2abbfe1eb1c52c",
"https://bcr.bazel.build/modules/jq.bzl/0.6.1/MODULE.bazel": "f30c46e0a08a9f7566a8bf60a43d48abea960cd7f57b315b01e2762f1537eb52",
"https://bcr.bazel.build/modules/jq.bzl/0.6.1/source.json": "9ca9e2f90baa6a5bb0a49626ed9528554ec83165adf47b39792673ecc7feda22",
"https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075",
"https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d",
"https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902",
@@ -165,10 +160,10 @@
"https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c",
"https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb",
"https://bcr.bazel.build/modules/rules_nodejs/6.2.0/MODULE.bazel": "ec27907f55eb34705adb4e8257952162a2d4c3ed0f0b3b4c3c1aad1fac7be35e",
"https://bcr.bazel.build/modules/rules_nodejs/6.3.0/MODULE.bazel": "45345e4aba35dd6e4701c1eebf5a4e67af4ed708def9ebcdc6027585b34ee52d",
"https://bcr.bazel.build/modules/rules_nodejs/6.5.0/MODULE.bazel": "546d0cf79f36f9f6e080816045f97234b071c205f4542e3351bd4424282a8810",
"https://bcr.bazel.build/modules/rules_nodejs/6.7.3/MODULE.bazel": "c22a48b2a0dbf05a9dc5f83837bbc24c226c1f6e618de3c3a610044c9f336056",
"https://bcr.bazel.build/modules/rules_nodejs/6.7.3/source.json": "a3f966f4415a8a6545e560ee5449eac95cc633f96429d08e87c87775c72f5e09",
"https://bcr.bazel.build/modules/rules_nodejs/6.7.4/MODULE.bazel": "e6a241a55c82e999145553d2e00a08fc6ebadf62b63d108fb5e984696ffd0bd2",
"https://bcr.bazel.build/modules/rules_nodejs/6.7.4/source.json": "34e7a8a3b4c8d630ac0e0492b3fed9dba41fe008a0edf220b7d88fa38ac53698",
"https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc",
"https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff",
"https://bcr.bazel.build/modules/rules_pkg/1.2.0/MODULE.bazel": "c7db3c2b407e673c7a39e3625dc05dc9f12d6682cbd82a3a5924a13b491eda7e",
@@ -200,17 +195,16 @@
"https://bcr.bazel.build/modules/stardoc/0.7.1/MODULE.bazel": "3548faea4ee5dda5580f9af150e79d0f6aea934fc60c1cc50f4efdd9420759e7",
"https://bcr.bazel.build/modules/stardoc/0.7.2/MODULE.bazel": "fc152419aa2ea0f51c29583fab1e8c99ddefd5b3778421845606ee628629e0e5",
"https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216",
"https://bcr.bazel.build/modules/tar.bzl/0.10.1/MODULE.bazel": "bf5fda5b5ccef8c3c4a5f4886144377386e0baa382972f257acb42dcf40ea908",
"https://bcr.bazel.build/modules/tar.bzl/0.10.1/source.json": "3f1beb35acf53c270a9de493cdc775a985551d7069cfcf24e136b42f683bbb10",
"https://bcr.bazel.build/modules/tar.bzl/0.2.1/MODULE.bazel": "52d1c00a80a8cc67acbd01649e83d8dd6a9dc426a6c0b754a04fe8c219c76468",
"https://bcr.bazel.build/modules/tar.bzl/0.5.1/MODULE.bazel": "7c2eb3dcfc53b0f3d6f9acdfd911ca803eaf92aadf54f8ca6e4c1f3aee288351",
"https://bcr.bazel.build/modules/tar.bzl/0.6.0/MODULE.bazel": "a3584b4edcfafcabd9b0ef9819808f05b372957bbdff41601429d5fd0aac2e7c",
"https://bcr.bazel.build/modules/tar.bzl/0.9.0/MODULE.bazel": "452a22d7f02b1c9d7a22ab25edf20f46f3e1101f0f67dc4bfbf9a474ddf02445",
"https://bcr.bazel.build/modules/tar.bzl/0.9.0/source.json": "c732760a374831a2cf5b08839e4be75017196b4d796a5aa55235272ee17cd839",
"https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43",
"https://bcr.bazel.build/modules/yq.bzl/0.1.1/MODULE.bazel": "9039681f9bcb8958ee2c87ffc74bdafba9f4369096a2b5634b88abc0eaefa072",
"https://bcr.bazel.build/modules/yq.bzl/0.2.0/MODULE.bazel": "6f3a675677db8885be4d607fde14cc51829715e3a879fb016eb9bf336786ce6d",
"https://bcr.bazel.build/modules/yq.bzl/0.3.2/MODULE.bazel": "0384efa70e8033d842ea73aa4b7199fa099709e236a7264345c03937166670b6",
"https://bcr.bazel.build/modules/yq.bzl/0.3.5/MODULE.bazel": "130c603e54be717bdf84100210f06598a0d2b4b4e01888fb01b70f50f41767ec",
"https://bcr.bazel.build/modules/yq.bzl/0.3.5/source.json": "1ae7bdc03cb26aaa8bd2bceadf65e90d90f0b2d03008ba9a0564da2e21396c39",
"https://bcr.bazel.build/modules/yq.bzl/0.3.6/MODULE.bazel": "985c2a0cb4ad9994bb0e33cc7fae931c91105eeefe3faa355b8f4c258d0607c0",
"https://bcr.bazel.build/modules/yq.bzl/0.3.6/source.json": "678aaf6e291164f3cd761bb3e872e8a151248f413dbb63c5524a50b82a5bc890",
"https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0",
"https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27",
"https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca",
@@ -221,7 +215,7 @@
"moduleExtensions": {
"@@aspect_rules_esbuild+//esbuild:extensions.bzl%esbuild": {
"general": {
"bzlTransitiveDigest": "GnYkDpVOnWnYv+xwyhEi0qjk3Lvp4Wei30PeSIQF5vM=",
"bzlTransitiveDigest": "3l5lERuIkp41OnB+ZcMQkXS5ttpwE3LfWmePbmwDofk=",
"usagesDigest": "6We6zwGoawD9YXqMI0KPaxEKJTnamXBsuOekhFS2D40=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
@@ -436,8 +430,8 @@
},
"@@aspect_rules_ts+//ts:extensions.bzl%ext": {
"general": {
"bzlTransitiveDigest": "0PprNyRYWkfOXKNvI8gaaD69N+xwJfjp1B9PAbgTdTI=",
"usagesDigest": "5Eyb0Kvg0CG7XCiKJ/v4cA5Rl7qXRtsRk7ZmepukdzQ=",
"bzlTransitiveDigest": "dhTbv9E6UfT1WJmmu3ORRPO6AKFJvgBjBxu+BO+u1RY=",
"usagesDigest": "wfAUu+hWfjbN8K5K5tnyIyhWKZOHe5xnDfeOD7CIZZ8=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
"envVariables": {},
@@ -455,8 +449,8 @@
"rules_angular_npm_typescript": {
"repoRuleId": "@@aspect_rules_ts+//ts/private:npm_repositories.bzl%http_archive_version",
"attributes": {
"version": "5.9.2",
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
"version": "6.0.3",
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
"urls": [
"https://registry.npmjs.org/typescript/-/typescript-{}.tgz"
]
@@ -465,8 +459,8 @@
"npm_typescript": {
"repoRuleId": "@@aspect_rules_ts+//ts/private:npm_repositories.bzl%http_archive_version",
"attributes": {
"version": "5.9.3",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"version": "6.0.3",
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
"urls": [
"https://registry.npmjs.org/typescript/-/typescript-{}.tgz"
]
@@ -475,8 +469,8 @@
"npm_rules_browsers_typescript": {
"repoRuleId": "@@aspect_rules_ts+//ts/private:npm_repositories.bzl%http_archive_version",
"attributes": {
"version": "5.8.2",
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
"version": "6.0.3",
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
"urls": [
"https://registry.npmjs.org/typescript/-/typescript-{}.tgz"
]
@@ -500,7 +494,7 @@
"@@aspect_tools_telemetry+//:extension.bzl%telemetry": {
"general": {
"bzlTransitiveDigest": "cl5A2O84vDL6Tt+Qga8FCj1DUDGqn+e7ly5rZ+4xvcc=",
"usagesDigest": "X9yWxTU9a+3PzHfKcQZZ8MzjmhcZcGinXvd3iA1e0Dw=",
"usagesDigest": "XReaXejedAKAFKyp+2mfnFkPWXBJzM/VxiOYB4nyseY=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
"envVariables": {},
@@ -509,7 +503,7 @@
"repoRuleId": "@@aspect_tools_telemetry+//:extension.bzl%tel_repository",
"attributes": {
"deps": {
"aspect_rules_ts": "3.8.6",
"aspect_rules_ts": "3.8.8",
"aspect_rules_js": "3.0.3",
"aspect_rules_esbuild": "0.25.1",
"aspect_rules_jasmine": "2.0.4",
@@ -568,24 +562,24 @@
},
"@@rules_angular+//setup:extensions.bzl%rules_angular": {
"general": {
"bzlTransitiveDigest": "fkaH7HMicL3g7/NDaFzlq39kcLopMyQ3KdbDn+5CRzA=",
"usagesDigest": "RWY3uqO/f0lDK8WZtS5QwE7S7IrkU3PrHr2/Vje4M3s=",
"bzlTransitiveDigest": "aS7Uud1IzoU7PPLzH3s6IfFS4b2fa0SRWDi2/fS4bQU=",
"usagesDigest": "PaJB/TvnSzJTbqGUeIfiFAEjGkG4FEW7es6f6MFMtq8=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
"envVariables": {},
"generatedRepoSpecs": {
"angular_rules_angular_configurable_deps": {
"repoRuleId": "@@rules_angular+//setup:repositories.bzl%configurable_deps_repo",
"attributes": {
"angular_compiler_cli": "@@//:node_modules/@angular/compiler-cli",
"typescript": "@@//:node_modules/typescript"
}
},
"rules_angular_configurable_deps": {
"repoRuleId": "@@rules_angular+//setup:repositories.bzl%configurable_deps_repo",
"attributes": {
"angular_compiler_cli": "@@rules_angular+//:node_modules/@angular/compiler-cli",
"typescript": "@@rules_angular+//:node_modules/typescript-local"
}
},
"dev_infra_rules_angular_configurable_deps": {
"repoRuleId": "@@rules_angular+//setup:repositories.bzl%configurable_deps_repo",
"attributes": {
"angular_compiler_cli": "@@rules_angular+//:node_modules/@angular/compiler-cli",
"typescript": "@@rules_angular+//:node_modules/typescript"
"angular_compiler_cli": "@@//:node_modules/@angular/compiler-cli",
"typescript": "@@//:node_modules/typescript"
}
}
},
@@ -953,8 +947,8 @@
},
"@@rules_nodejs+//nodejs:extensions.bzl%node": {
"general": {
"bzlTransitiveDigest": "4pUxCNc22K4I+6+4Nxu52Hur12tFRfa1JMsN5mdDv60=",
"usagesDigest": "b5S0m/ld5GaUSiR4bWVkvCiiWcK33vg+ynakv0PZl+o=",
"bzlTransitiveDigest": "oZFClfRhTTwsYzpxVPkOpOt/r0+OzEfEV37au0jFZ0s=",
"usagesDigest": "dp2HPl9Y2BFhrnM0JALIsJHz02rKnRBpISBHQX4qV7E=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
"envVariables": {},
@@ -964,46 +958,46 @@
"attributes": {
"node_download_auth": {},
"node_repositories": {
"22.22.1-darwin_arm64": [
"node-v22.22.1-darwin-arm64.tar.gz",
"node-v22.22.1-darwin-arm64",
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
"22.22.2-darwin_arm64": [
"node-v22.22.2-darwin-arm64.tar.gz",
"node-v22.22.2-darwin-arm64",
"db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
],
"22.22.1-darwin_amd64": [
"node-v22.22.1-darwin-x64.tar.gz",
"node-v22.22.1-darwin-x64",
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
"22.22.2-darwin_amd64": [
"node-v22.22.2-darwin-x64.tar.gz",
"node-v22.22.2-darwin-x64",
"12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
],
"22.22.1-linux_arm64": [
"node-v22.22.1-linux-arm64.tar.xz",
"node-v22.22.1-linux-arm64",
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
"22.22.2-linux_arm64": [
"node-v22.22.2-linux-arm64.tar.xz",
"node-v22.22.2-linux-arm64",
"e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
],
"22.22.1-linux_ppc64le": [
"node-v22.22.1-linux-ppc64le.tar.xz",
"node-v22.22.1-linux-ppc64le",
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
"22.22.2-linux_ppc64le": [
"node-v22.22.2-linux-ppc64le.tar.xz",
"node-v22.22.2-linux-ppc64le",
"14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
],
"22.22.1-linux_s390x": [
"node-v22.22.1-linux-s390x.tar.xz",
"node-v22.22.1-linux-s390x",
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
"22.22.2-linux_s390x": [
"node-v22.22.2-linux-s390x.tar.xz",
"node-v22.22.2-linux-s390x",
"9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
],
"22.22.1-linux_amd64": [
"node-v22.22.1-linux-x64.tar.xz",
"node-v22.22.1-linux-x64",
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
"22.22.2-linux_amd64": [
"node-v22.22.2-linux-x64.tar.xz",
"node-v22.22.2-linux-x64",
"88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
],
"22.22.1-windows_amd64": [
"node-v22.22.1-win-x64.zip",
"node-v22.22.1-win-x64",
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
"22.22.2-windows_amd64": [
"node-v22.22.2-win-x64.zip",
"node-v22.22.2-win-x64",
"7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
]
},
"node_urls": [
"https://nodejs.org/dist/v{version}/{filename}"
],
"node_version": "22.22.1",
"node_version": "22.22.2",
"include_headers": false,
"platform": "linux_amd64"
}
@@ -1013,46 +1007,46 @@
"attributes": {
"node_download_auth": {},
"node_repositories": {
"22.22.1-darwin_arm64": [
"node-v22.22.1-darwin-arm64.tar.gz",
"node-v22.22.1-darwin-arm64",
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
"22.22.2-darwin_arm64": [
"node-v22.22.2-darwin-arm64.tar.gz",
"node-v22.22.2-darwin-arm64",
"db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
],
"22.22.1-darwin_amd64": [
"node-v22.22.1-darwin-x64.tar.gz",
"node-v22.22.1-darwin-x64",
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
"22.22.2-darwin_amd64": [
"node-v22.22.2-darwin-x64.tar.gz",
"node-v22.22.2-darwin-x64",
"12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
],
"22.22.1-linux_arm64": [
"node-v22.22.1-linux-arm64.tar.xz",
"node-v22.22.1-linux-arm64",
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
"22.22.2-linux_arm64": [
"node-v22.22.2-linux-arm64.tar.xz",
"node-v22.22.2-linux-arm64",
"e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
],
"22.22.1-linux_ppc64le": [
"node-v22.22.1-linux-ppc64le.tar.xz",
"node-v22.22.1-linux-ppc64le",
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
"22.22.2-linux_ppc64le": [
"node-v22.22.2-linux-ppc64le.tar.xz",
"node-v22.22.2-linux-ppc64le",
"14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
],
"22.22.1-linux_s390x": [
"node-v22.22.1-linux-s390x.tar.xz",
"node-v22.22.1-linux-s390x",
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
"22.22.2-linux_s390x": [
"node-v22.22.2-linux-s390x.tar.xz",
"node-v22.22.2-linux-s390x",
"9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
],
"22.22.1-linux_amd64": [
"node-v22.22.1-linux-x64.tar.xz",
"node-v22.22.1-linux-x64",
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
"22.22.2-linux_amd64": [
"node-v22.22.2-linux-x64.tar.xz",
"node-v22.22.2-linux-x64",
"88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
],
"22.22.1-windows_amd64": [
"node-v22.22.1-win-x64.zip",
"node-v22.22.1-win-x64",
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
"22.22.2-windows_amd64": [
"node-v22.22.2-win-x64.zip",
"node-v22.22.2-win-x64",
"7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
]
},
"node_urls": [
"https://nodejs.org/dist/v{version}/{filename}"
],
"node_version": "22.22.1",
"node_version": "22.22.2",
"include_headers": false,
"platform": "linux_arm64"
}
@@ -1062,46 +1056,46 @@
"attributes": {
"node_download_auth": {},
"node_repositories": {
"22.22.1-darwin_arm64": [
"node-v22.22.1-darwin-arm64.tar.gz",
"node-v22.22.1-darwin-arm64",
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
"22.22.2-darwin_arm64": [
"node-v22.22.2-darwin-arm64.tar.gz",
"node-v22.22.2-darwin-arm64",
"db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
],
"22.22.1-darwin_amd64": [
"node-v22.22.1-darwin-x64.tar.gz",
"node-v22.22.1-darwin-x64",
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
"22.22.2-darwin_amd64": [
"node-v22.22.2-darwin-x64.tar.gz",
"node-v22.22.2-darwin-x64",
"12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
],
"22.22.1-linux_arm64": [
"node-v22.22.1-linux-arm64.tar.xz",
"node-v22.22.1-linux-arm64",
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
"22.22.2-linux_arm64": [
"node-v22.22.2-linux-arm64.tar.xz",
"node-v22.22.2-linux-arm64",
"e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
],
"22.22.1-linux_ppc64le": [
"node-v22.22.1-linux-ppc64le.tar.xz",
"node-v22.22.1-linux-ppc64le",
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
"22.22.2-linux_ppc64le": [
"node-v22.22.2-linux-ppc64le.tar.xz",
"node-v22.22.2-linux-ppc64le",
"14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
],
"22.22.1-linux_s390x": [
"node-v22.22.1-linux-s390x.tar.xz",
"node-v22.22.1-linux-s390x",
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
"22.22.2-linux_s390x": [
"node-v22.22.2-linux-s390x.tar.xz",
"node-v22.22.2-linux-s390x",
"9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
],
"22.22.1-linux_amd64": [
"node-v22.22.1-linux-x64.tar.xz",
"node-v22.22.1-linux-x64",
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
"22.22.2-linux_amd64": [
"node-v22.22.2-linux-x64.tar.xz",
"node-v22.22.2-linux-x64",
"88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
],
"22.22.1-windows_amd64": [
"node-v22.22.1-win-x64.zip",
"node-v22.22.1-win-x64",
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
"22.22.2-windows_amd64": [
"node-v22.22.2-win-x64.zip",
"node-v22.22.2-win-x64",
"7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
]
},
"node_urls": [
"https://nodejs.org/dist/v{version}/{filename}"
],
"node_version": "22.22.1",
"node_version": "22.22.2",
"include_headers": false,
"platform": "linux_s390x"
}
@@ -1111,46 +1105,46 @@
"attributes": {
"node_download_auth": {},
"node_repositories": {
"22.22.1-darwin_arm64": [
"node-v22.22.1-darwin-arm64.tar.gz",
"node-v22.22.1-darwin-arm64",
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
"22.22.2-darwin_arm64": [
"node-v22.22.2-darwin-arm64.tar.gz",
"node-v22.22.2-darwin-arm64",
"db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
],
"22.22.1-darwin_amd64": [
"node-v22.22.1-darwin-x64.tar.gz",
"node-v22.22.1-darwin-x64",
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
"22.22.2-darwin_amd64": [
"node-v22.22.2-darwin-x64.tar.gz",
"node-v22.22.2-darwin-x64",
"12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
],
"22.22.1-linux_arm64": [
"node-v22.22.1-linux-arm64.tar.xz",
"node-v22.22.1-linux-arm64",
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
"22.22.2-linux_arm64": [
"node-v22.22.2-linux-arm64.tar.xz",
"node-v22.22.2-linux-arm64",
"e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
],
"22.22.1-linux_ppc64le": [
"node-v22.22.1-linux-ppc64le.tar.xz",
"node-v22.22.1-linux-ppc64le",
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
"22.22.2-linux_ppc64le": [
"node-v22.22.2-linux-ppc64le.tar.xz",
"node-v22.22.2-linux-ppc64le",
"14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
],
"22.22.1-linux_s390x": [
"node-v22.22.1-linux-s390x.tar.xz",
"node-v22.22.1-linux-s390x",
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
"22.22.2-linux_s390x": [
"node-v22.22.2-linux-s390x.tar.xz",
"node-v22.22.2-linux-s390x",
"9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
],
"22.22.1-linux_amd64": [
"node-v22.22.1-linux-x64.tar.xz",
"node-v22.22.1-linux-x64",
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
"22.22.2-linux_amd64": [
"node-v22.22.2-linux-x64.tar.xz",
"node-v22.22.2-linux-x64",
"88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
],
"22.22.1-windows_amd64": [
"node-v22.22.1-win-x64.zip",
"node-v22.22.1-win-x64",
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
"22.22.2-windows_amd64": [
"node-v22.22.2-win-x64.zip",
"node-v22.22.2-win-x64",
"7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
]
},
"node_urls": [
"https://nodejs.org/dist/v{version}/{filename}"
],
"node_version": "22.22.1",
"node_version": "22.22.2",
"include_headers": false,
"platform": "linux_ppc64le"
}
@@ -1160,46 +1154,46 @@
"attributes": {
"node_download_auth": {},
"node_repositories": {
"22.22.1-darwin_arm64": [
"node-v22.22.1-darwin-arm64.tar.gz",
"node-v22.22.1-darwin-arm64",
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
"22.22.2-darwin_arm64": [
"node-v22.22.2-darwin-arm64.tar.gz",
"node-v22.22.2-darwin-arm64",
"db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
],
"22.22.1-darwin_amd64": [
"node-v22.22.1-darwin-x64.tar.gz",
"node-v22.22.1-darwin-x64",
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
"22.22.2-darwin_amd64": [
"node-v22.22.2-darwin-x64.tar.gz",
"node-v22.22.2-darwin-x64",
"12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
],
"22.22.1-linux_arm64": [
"node-v22.22.1-linux-arm64.tar.xz",
"node-v22.22.1-linux-arm64",
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
"22.22.2-linux_arm64": [
"node-v22.22.2-linux-arm64.tar.xz",
"node-v22.22.2-linux-arm64",
"e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
],
"22.22.1-linux_ppc64le": [
"node-v22.22.1-linux-ppc64le.tar.xz",
"node-v22.22.1-linux-ppc64le",
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
"22.22.2-linux_ppc64le": [
"node-v22.22.2-linux-ppc64le.tar.xz",
"node-v22.22.2-linux-ppc64le",
"14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
],
"22.22.1-linux_s390x": [
"node-v22.22.1-linux-s390x.tar.xz",
"node-v22.22.1-linux-s390x",
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
"22.22.2-linux_s390x": [
"node-v22.22.2-linux-s390x.tar.xz",
"node-v22.22.2-linux-s390x",
"9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
],
"22.22.1-linux_amd64": [
"node-v22.22.1-linux-x64.tar.xz",
"node-v22.22.1-linux-x64",
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
"22.22.2-linux_amd64": [
"node-v22.22.2-linux-x64.tar.xz",
"node-v22.22.2-linux-x64",
"88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
],
"22.22.1-windows_amd64": [
"node-v22.22.1-win-x64.zip",
"node-v22.22.1-win-x64",
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
"22.22.2-windows_amd64": [
"node-v22.22.2-win-x64.zip",
"node-v22.22.2-win-x64",
"7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
]
},
"node_urls": [
"https://nodejs.org/dist/v{version}/{filename}"
],
"node_version": "22.22.1",
"node_version": "22.22.2",
"include_headers": false,
"platform": "darwin_amd64"
}
@@ -1209,46 +1203,46 @@
"attributes": {
"node_download_auth": {},
"node_repositories": {
"22.22.1-darwin_arm64": [
"node-v22.22.1-darwin-arm64.tar.gz",
"node-v22.22.1-darwin-arm64",
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
"22.22.2-darwin_arm64": [
"node-v22.22.2-darwin-arm64.tar.gz",
"node-v22.22.2-darwin-arm64",
"db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
],
"22.22.1-darwin_amd64": [
"node-v22.22.1-darwin-x64.tar.gz",
"node-v22.22.1-darwin-x64",
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
"22.22.2-darwin_amd64": [
"node-v22.22.2-darwin-x64.tar.gz",
"node-v22.22.2-darwin-x64",
"12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
],
"22.22.1-linux_arm64": [
"node-v22.22.1-linux-arm64.tar.xz",
"node-v22.22.1-linux-arm64",
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
"22.22.2-linux_arm64": [
"node-v22.22.2-linux-arm64.tar.xz",
"node-v22.22.2-linux-arm64",
"e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
],
"22.22.1-linux_ppc64le": [
"node-v22.22.1-linux-ppc64le.tar.xz",
"node-v22.22.1-linux-ppc64le",
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
"22.22.2-linux_ppc64le": [
"node-v22.22.2-linux-ppc64le.tar.xz",
"node-v22.22.2-linux-ppc64le",
"14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
],
"22.22.1-linux_s390x": [
"node-v22.22.1-linux-s390x.tar.xz",
"node-v22.22.1-linux-s390x",
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
"22.22.2-linux_s390x": [
"node-v22.22.2-linux-s390x.tar.xz",
"node-v22.22.2-linux-s390x",
"9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
],
"22.22.1-linux_amd64": [
"node-v22.22.1-linux-x64.tar.xz",
"node-v22.22.1-linux-x64",
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
"22.22.2-linux_amd64": [
"node-v22.22.2-linux-x64.tar.xz",
"node-v22.22.2-linux-x64",
"88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
],
"22.22.1-windows_amd64": [
"node-v22.22.1-win-x64.zip",
"node-v22.22.1-win-x64",
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
"22.22.2-windows_amd64": [
"node-v22.22.2-win-x64.zip",
"node-v22.22.2-win-x64",
"7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
]
},
"node_urls": [
"https://nodejs.org/dist/v{version}/{filename}"
],
"node_version": "22.22.1",
"node_version": "22.22.2",
"include_headers": false,
"platform": "darwin_arm64"
}
@@ -1258,46 +1252,46 @@
"attributes": {
"node_download_auth": {},
"node_repositories": {
"22.22.1-darwin_arm64": [
"node-v22.22.1-darwin-arm64.tar.gz",
"node-v22.22.1-darwin-arm64",
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
"22.22.2-darwin_arm64": [
"node-v22.22.2-darwin-arm64.tar.gz",
"node-v22.22.2-darwin-arm64",
"db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
],
"22.22.1-darwin_amd64": [
"node-v22.22.1-darwin-x64.tar.gz",
"node-v22.22.1-darwin-x64",
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
"22.22.2-darwin_amd64": [
"node-v22.22.2-darwin-x64.tar.gz",
"node-v22.22.2-darwin-x64",
"12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
],
"22.22.1-linux_arm64": [
"node-v22.22.1-linux-arm64.tar.xz",
"node-v22.22.1-linux-arm64",
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
"22.22.2-linux_arm64": [
"node-v22.22.2-linux-arm64.tar.xz",
"node-v22.22.2-linux-arm64",
"e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
],
"22.22.1-linux_ppc64le": [
"node-v22.22.1-linux-ppc64le.tar.xz",
"node-v22.22.1-linux-ppc64le",
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
"22.22.2-linux_ppc64le": [
"node-v22.22.2-linux-ppc64le.tar.xz",
"node-v22.22.2-linux-ppc64le",
"14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
],
"22.22.1-linux_s390x": [
"node-v22.22.1-linux-s390x.tar.xz",
"node-v22.22.1-linux-s390x",
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
"22.22.2-linux_s390x": [
"node-v22.22.2-linux-s390x.tar.xz",
"node-v22.22.2-linux-s390x",
"9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
],
"22.22.1-linux_amd64": [
"node-v22.22.1-linux-x64.tar.xz",
"node-v22.22.1-linux-x64",
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
"22.22.2-linux_amd64": [
"node-v22.22.2-linux-x64.tar.xz",
"node-v22.22.2-linux-x64",
"88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
],
"22.22.1-windows_amd64": [
"node-v22.22.1-win-x64.zip",
"node-v22.22.1-win-x64",
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
"22.22.2-windows_amd64": [
"node-v22.22.2-win-x64.zip",
"node-v22.22.2-win-x64",
"7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
]
},
"node_urls": [
"https://nodejs.org/dist/v{version}/{filename}"
],
"node_version": "22.22.1",
"node_version": "22.22.2",
"include_headers": false,
"platform": "windows_amd64"
}
@@ -1307,46 +1301,46 @@
"attributes": {
"node_download_auth": {},
"node_repositories": {
"22.22.1-darwin_arm64": [
"node-v22.22.1-darwin-arm64.tar.gz",
"node-v22.22.1-darwin-arm64",
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
"22.22.2-darwin_arm64": [
"node-v22.22.2-darwin-arm64.tar.gz",
"node-v22.22.2-darwin-arm64",
"db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
],
"22.22.1-darwin_amd64": [
"node-v22.22.1-darwin-x64.tar.gz",
"node-v22.22.1-darwin-x64",
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
"22.22.2-darwin_amd64": [
"node-v22.22.2-darwin-x64.tar.gz",
"node-v22.22.2-darwin-x64",
"12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
],
"22.22.1-linux_arm64": [
"node-v22.22.1-linux-arm64.tar.xz",
"node-v22.22.1-linux-arm64",
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
"22.22.2-linux_arm64": [
"node-v22.22.2-linux-arm64.tar.xz",
"node-v22.22.2-linux-arm64",
"e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
],
"22.22.1-linux_ppc64le": [
"node-v22.22.1-linux-ppc64le.tar.xz",
"node-v22.22.1-linux-ppc64le",
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
"22.22.2-linux_ppc64le": [
"node-v22.22.2-linux-ppc64le.tar.xz",
"node-v22.22.2-linux-ppc64le",
"14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
],
"22.22.1-linux_s390x": [
"node-v22.22.1-linux-s390x.tar.xz",
"node-v22.22.1-linux-s390x",
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
"22.22.2-linux_s390x": [
"node-v22.22.2-linux-s390x.tar.xz",
"node-v22.22.2-linux-s390x",
"9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
],
"22.22.1-linux_amd64": [
"node-v22.22.1-linux-x64.tar.xz",
"node-v22.22.1-linux-x64",
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
"22.22.2-linux_amd64": [
"node-v22.22.2-linux-x64.tar.xz",
"node-v22.22.2-linux-x64",
"88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
],
"22.22.1-windows_amd64": [
"node-v22.22.1-win-x64.zip",
"node-v22.22.1-win-x64",
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
"22.22.2-windows_amd64": [
"node-v22.22.2-win-x64.zip",
"node-v22.22.2-win-x64",
"7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
]
},
"node_urls": [
"https://nodejs.org/dist/v{version}/{filename}"
],
"node_version": "22.22.1",
"node_version": "22.22.2",
"include_headers": false,
"platform": "windows_arm64"
}
@@ -4113,7 +4107,7 @@
},
"@@rules_sass+//src/toolchain:extensions.bzl%sass": {
"general": {
"bzlTransitiveDigest": "RA58Nyrsn03Z5YmQnpmBw3mqlVck++XIrx34amsqU/E=",
"bzlTransitiveDigest": "mOfuR8PsNuUWEq7JZ4MpIRbwyAGAqrCvkXXGaRNnlPQ=",
"usagesDigest": "R0KshhzIouLWuexMUCrl4HY+FUDwlVVgF9Z7UnwyUWA=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
@@ -4170,7 +4164,7 @@
"@@yq.bzl+//yq:extensions.bzl%yq": {
"general": {
"bzlTransitiveDigest": "UfFMy8CWK4/dVo/tfaSAIYUiDGNAPes5eRllx9O9Q9Q=",
"usagesDigest": "263D9xYtKhXWWCVTxT66bpT89HuZpdkB1AqEir45vbY=",
"usagesDigest": "5cUmZOEOibp2h65JoFppstHiXcjDFil/AG+HgD3avRk=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
"envVariables": {},
+1 -1
View File
@@ -67,7 +67,7 @@ Install the Angular CLI globally:
npm install -g @angular/cli
```
Create workspace:
Create a workspace:
```
ng new [PROJECT NAME]
+6 -6
View File
@@ -5,21 +5,21 @@
"@algolia/requester-browser-xhr": "5.48.0",
"@algolia/requester-node-http": "5.48.0",
"@angular/animations": "workspace:*",
"@angular/aria": "21.2.0",
"@angular/build": "21.2.0",
"@angular/cdk": "21.2.0",
"@angular/cli": "21.2.0",
"@angular/aria": "21.2.9",
"@angular/build": "21.2.9",
"@angular/cdk": "21.2.9",
"@angular/cli": "21.2.9",
"@angular/common": "workspace:*",
"@angular/compiler": "workspace:*",
"@angular/compiler-cli": "workspace:*",
"@angular/core": "workspace:*",
"@angular/docs": "workspace:*",
"@angular/forms": "workspace:*",
"@angular/material": "21.2.0",
"@angular/material": "21.2.9",
"@angular/platform-browser": "workspace:*",
"@angular/platform-server": "workspace:*",
"@angular/router": "workspace:*",
"@angular/ssr": "21.2.0",
"@angular/ssr": "21.2.9",
"@codemirror/autocomplete": "6.20.0",
"@codemirror/commands": "6.10.1",
"@codemirror/lang-angular": "0.1.4",
@@ -53,7 +53,7 @@
matrixParams: 'ignored',
fragment: 'ignored',
}"
(click)="emitClickOnLink()"
(click)="emitClickOnLink(item)"
[matTooltip]="item.label"
[matTooltipDisabled]="itemLabel.length < 27"
matTooltipPosition="after"
@@ -6,7 +6,7 @@
list-style: none;
overflow-y: auto;
overflow-x: hidden;
height: 100vh;
height: 100dvh;
padding: 0;
margin: 0;
padding-block: 1.5rem;
@@ -153,5 +153,6 @@ describe('NavigationList', () => {
class FakeNavigationListState {
isOpened = signal(true);
activeNavigationItem = signal(navigationItems.at(1));
crossCategoryOrigin = signal<NavigationItem | undefined>(undefined);
toggleItem(item: NavigationItem) {}
}
@@ -40,6 +40,7 @@ export class NavigationList {
readonly linkClicked = output<void>();
private readonly navigationState = inject(NavigationState);
private readonly crossCategoryOrigin = this.navigationState.crossCategoryOrigin;
readonly activeItem = this.navigationState.activeNavigationItem;
@@ -51,10 +52,19 @@ export class NavigationList {
) {
return;
}
const prevParentItem = this.crossCategoryOrigin();
if (prevParentItem) {
this.crossCategoryOrigin.set(undefined);
this.navigationState.toggleItem(prevParentItem);
return;
}
this.navigationState.toggleItem(item);
}
emitClickOnLink(): void {
emitClickOnLink(item: NavigationItem): void {
if (item.isCrossReferenced) {
this.crossCategoryOrigin.set(item.parent);
}
this.linkClicked.emit();
}
@@ -27,14 +27,16 @@
</i>
</span>
<!-- Page title -->
<span [innerHtml]="result.labelHtml"></span>
@if (result.package) {
<span
[innerHTML]="result.package"
class="docs-search-result__label__package"
></span>
}
<!-- Page title and package badge -->
<span class="docs-search-result__label__text">
<span [innerHtml]="result.labelHtml"></span>
@if (result.package) {
<span
[innerHTML]="result.package"
class="docs-search-result__label__package"
></span>
}
</span>
</p>
@if (result.subLabelHtml) {
@@ -46,6 +46,7 @@ dialog {
.docs-search-result-icon {
display: inline-block;
flex-shrink: 0;
i {
display: flex;
@@ -91,7 +92,20 @@ dialog {
&__label {
font-weight: 600;
flex-wrap: wrap;
&__text {
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 0.25rem 0.5rem;
flex: 1;
min-width: 0;
overflow-wrap: break-word;
> * {
min-width: 0;
}
}
&__package {
font-size: 0.75rem;
@@ -17,5 +17,6 @@ export interface NavigationItem {
contentPath?: string;
status?: 'new' | 'updated';
category?: string;
isCrossReferenced?: boolean;
preserveOtherCategoryOrder?: boolean; // true by default
}
@@ -59,10 +59,16 @@ export function ClassMember(props: {member: MemberEntryRenderable}) {
const memberName = member.name;
const displayName = member.displayName;
const returnType = getMemberType(member);
const label = displayName ?? memberName;
return (
<div id={memberName} className={REFERENCE_MEMBER_CARD}>
<header className={REFERENCE_MEMBER_CARD_HEADER}>
<h3>{displayName ?? memberName}</h3>
<h3>
<a class="docs-anchor" href={'#' + memberName}>
{label}
</a>
</h3>
{isClassMethodEntry(member) && member.signatures.length > 1 ? (
<span>{member.signatures.length} overloads</span>
) : returnType ? (
@@ -27,14 +27,14 @@ export function CliCommandReference(entry: CliCommandRenderable) {
<div className={'shiki line cli'}>
ng {commandName(entry, command)}
{entry.argumentsLabel && (
<button member-id={'Arguments'} className="shiki-ln-line-argument">
<span member-id={'Arguments'} className="shiki-ln-line-argument">
{entry.argumentsLabel}
</button>
</span>
)}
{entry.optionsLabel && (
<button member-id={'Options'} className="shiki-ln-line-option">
<span member-id={'Options'} className="shiki-ln-line-option">
{entry.optionsLabel}
</button>
</span>
)}
</div>
</code>
@@ -13,6 +13,8 @@ import {setSymbols} from '../symbol-context.mjs';
import {resolve} from 'path';
import {initHighlighter} from '../../../shared/shiki.mjs';
import {setHighlighterInstance} from '../shiki/shiki.mjs';
import {renderEntry} from '../rendering.mjs';
import {JSDOM} from 'jsdom';
// Note: The tests will probably break if the schema of the api extraction changes.
// All entries in the fake-entries are extracted from Angular's api.
@@ -60,4 +62,21 @@ describe('renderable', () => {
expect(linkedSignal!.experimental).toBe(undefined);
expect(linkedSignal!.stable).toBe(undefined);
});
it('should render docs-anchor links in class member card headers', () => {
const viewRef = entries.get('ViewRef')!;
expect(viewRef).toBeDefined();
const html = renderEntry(viewRef);
const fragment = JSDOM.fragment(html);
const memberCards = fragment.querySelectorAll('.docs-reference-member-card');
expect(memberCards.length).toBeGreaterThan(0);
for (const card of Array.from(memberCards)) {
const id = card.getAttribute('id')!;
const anchor = card.querySelector('h3 a.docs-anchor') as HTMLAnchorElement;
expect(anchor.getAttribute('href')).toBe(`#${id}`);
}
});
});
@@ -199,6 +199,23 @@ describe('jsdoc transforms', () => {
expect(entryFn).toThrowError(/Forbidden relative link: cli\/build ng build/);
});
it('should throw on a miscased absolute @link to a known API symbol', () => {
setSymbols({RouterModule: 'router'});
const entryFn = () =>
addHtmlAdditionalLinks({
jsdocTags: [
{
name: 'see',
comment: '{@link /api/router/routerModule#forRoot forRoot}',
},
],
moduleName: 'test',
});
expect(entryFn).toThrowError(/Broken @link.*Did you mean \/api\/router\/RouterModule/);
});
});
describe('addHtmlDescription', () => {
@@ -95,6 +95,7 @@ export async function addRenderableCodeToc<T extends DocEntry & HasModuleName>(
{
language: 'typescript',
apiEntries: getSymbolsAsApiEntries(),
removeWhitespace: false,
},
);
@@ -223,6 +223,27 @@ function parseAtLink(link: string): {label: string; url: string} | undefined {
);
}
// Validate absolute `/api/...` links against the known symbol registry. This catches
// miscased symbol names (e.g. `/api/router/routerModule` instead of
// `/api/router/RouterModule`) at build time.
if (rawSymbol.startsWith('/api/')) {
const [pathPart] = rawSymbol.split('#');
const segments = pathPart.split('/').filter((s) => s.length > 0);
const symbolName = segments[segments.length - 1];
// Case-insensitive lookup: find the canonical symbol name in the registry.
const knownSymbols = Object.keys(getSymbolsAsApiEntries());
const canonicalSymbol = knownSymbols.find(
(s) => s.toLowerCase() === symbolName.toLowerCase(),
);
if (canonicalSymbol && canonicalSymbol !== symbolName) {
const expectedUrl = getSymbolUrl(canonicalSymbol);
throw Error(
`Broken @link: ${link}. Did you mean ${expectedUrl}? ` +
`Symbol names in API URLs are case-sensitive.`,
);
}
}
return {
url: rawSymbol,
label: description ?? rawSymbol.split('/').pop()!,
@@ -32,6 +32,13 @@ const LINK_EXEMPT = new Set([
'type',
'Host',
'filter',
'required',
'pattern',
'min',
'max',
'minLength',
'maxLength',
'query',
]);
export function shouldLinkSymbol(symbol: string): boolean {
@@ -18,6 +18,7 @@ interface DocsCardToken extends Tokens.Generic {
href?: string;
imgSrc?: string;
iconImgSrc?: string; // Need image since icons are custom
titleInline?: boolean;
tokens: Token[];
}
@@ -30,6 +31,7 @@ const linkRule = /link="([^"]*)"/;
const hrefRule = /href="([^"]*)"/;
const imgSrcRule = /imgSrc="([^"]*)"/;
const iconImgSrcRule = /iconImgSrc="([^"]*)"/;
const titleInlineRule = /(?:^|\s)titleInline(?=\s|$|=)/;
export const docsCardExtension = {
name: 'docs-card',
@@ -47,6 +49,7 @@ export const docsCardExtension = {
const href = hrefRule.exec(attr);
const imgSrc = imgSrcRule.exec(attr);
const iconImgSrc = iconImgSrcRule.exec(attr);
const titleInline = titleInlineRule.test(attr);
const body = match[2].trim();
@@ -59,6 +62,7 @@ export const docsCardExtension = {
link: link ? link[1] : undefined,
imgSrc: imgSrc ? imgSrc[1] : undefined,
iconImgSrc: iconImgSrc ? iconImgSrc[1] : undefined,
titleInline,
tokens: [],
};
this.lexer.blockTokens(token.body, token.tokens);
@@ -79,12 +83,14 @@ function getStandardCard(renderer: AdevDocsRenderer, token: DocsCardToken) {
// We need to read svg content, instead of renering svg with `img`,
// cause we would like to use CSS variables to support dark and light mode.
const icon = loadWorkspaceRelativeFile(token.iconImgSrc);
const header = token.titleInline
? `<div class="docs-card-header-inline">${icon}<h3>${token.title}</h3></div>`
: `${icon}<h3>${token.title}</h3>`;
return `
<a href="${token.href}" ${anchorTarget(token.href)} class="docs-card">
<div>
${icon}
<h3>${token.title}</h3>
${header}
${renderer.parser.parse(token.tokens)}
</div>
<span>${token.link ? token.link : 'Learn more'}</span>
@@ -135,4 +135,29 @@ describe('markdown to html', () => {
// We ensure that we still style the heading content
expect(markdownDocument.querySelector('strong')).toBeDefined();
});
it('should strip all HTML tags from the aria-label attribute', () => {
const markdownDocument = JSDOM.fragment(
parseMarkdown(
'## **Phase 5: Experimental Signal Forms (⚠️ WARNING: Subject to Change)**',
rendererContext,
),
);
const h2Anchor = markdownDocument.querySelector('h2 > a');
expect(h2Anchor!.innerHTML).toBe(
'<strong><span class="docs-emoji">Phase 5: Experimental Signal Forms (⚠️ WARNING: Subject to Change)</span></strong>',
);
expect(h2Anchor!.getAttribute('aria-label')).toBe(
'Link to Phase 5: Experimental Signal Forms (⚠️ WARNING: Subject to Change)',
);
});
it('should escape double quotes from the aria-label attribute', () => {
const markdownDocument = JSDOM.fragment(parseMarkdown('## "Special" heading', rendererContext));
const h2Anchor = markdownDocument.querySelector('h2 > a');
expect(h2Anchor!.innerHTML).toBe('"Special" heading');
expect(h2Anchor!.getAttribute('aria-label')).toBe('Link to "Special" heading');
});
});
@@ -31,7 +31,7 @@ export function headingRender(
// Replace code backticks and remove custom ID syntax from the displayed label
let label = parsedText.replace(/`(.*?)`/g, '<code>$1</code>');
label = label.replace(/{#\s*[\w-]+\s*}/g, '').trim();
const normalizedLabel = label.replace(/<\/?code>/g, '');
const normalizedLabel = label.replace(/<[^>]+>/g, '').replace(/"/g, '&quot;');
return `
<h${depth} id="${link}">
+2 -1
View File
@@ -42,6 +42,7 @@ export function codeToHtml(
apiEntries?: ApiEntries;
language?: string;
highlight?: Set<number>;
removeWhitespace?: boolean;
},
): string {
const html = highlighter.codeToHtml(code, {
@@ -53,7 +54,7 @@ export function codeToHtml(
cssVariablePrefix: '--shiki-',
defaultColor: false,
transformers: [
removeWhitespaceTransformer(),
...(config.removeWhitespace ? [removeWhitespaceTransformer()] : []),
highlightTransformer(config.highlight),
linkApiEntriesTransformer(config.apiEntries),
],
@@ -21,6 +21,7 @@ export class NavigationState {
private readonly _isMobileNavVisible = signal<boolean>(false);
private readonly _level = linkedSignal(() => this._expandedItems().length);
readonly crossCategoryOrigin = signal<NavigationItem | undefined>(undefined);
readonly primaryActiveRouteItem = signal<string | null>(null);
activeNavigationItem = this._activeNavigationItem.asReadonly();
expandedItems = this._expandedItems.asReadonly();
+8
View File
@@ -426,6 +426,14 @@
.docs-ref-content {
padding: 1rem 0;
.docs-ref-option-and-description {
.docs-reference-option {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
}
&:not(:first-child) {
border-block-start: 1px solid var(--senary-contrast);
}
+33 -2
View File
@@ -1,6 +1,8 @@
// Card Grid
@mixin docs-card() {
$compact-breakpoint: 550px;
.docs-card-container-wrapper {
border: 1px solid var(--senary-contrast);
border-radius: 0.25rem;
@@ -15,6 +17,11 @@
h2 {
padding: 2.5rem 1rem 2.5rem 2.5rem;
min-width: 350px;
@container docs-content (max-width: $compact-breakpoint) {
min-width: auto;
padding: 1.5rem;
}
}
.theme-fill-bg {
@@ -57,7 +64,11 @@
svg {
fill-opacity: 1;
@container header (max-width: 550px) {
@container header (max-width: $compact-breakpoint) {
display: none;
}
@container docs-content (max-width: $compact-breakpoint) {
display: none;
}
@@ -71,6 +82,11 @@
margin: 1rem;
padding: 1.5rem;
@container docs-content (max-width: $compact-breakpoint) {
margin: 0.5rem;
padding: 0.75rem;
}
.docs-card {
margin: 0;
@@ -143,6 +159,21 @@
margin-block: 1.5rem;
}
.docs-card-header-inline {
display: flex;
align-items: center;
gap: 0.5rem;
svg {
margin-block-end: 0;
flex-shrink: 0;
}
h3 {
margin-block: 0;
}
}
&.docs-card-with-svg {
padding: 0;
@@ -252,7 +283,7 @@
.docs-nav-card-svg {
width: 350px;
@container header (max-width: 550px) {
@container header (max-width: $compact-breakpoint) {
display: none;
}
}
+9 -1
View File
@@ -36,6 +36,15 @@ $code-font-size: 0.875rem;
}
}
.shiki.line.cli {
span {
color: var(--quaternary-contrast);
font-family: var(--inter-font);
font-weight: 600;
font-size: 13px;
}
}
.docs-light-mode .shiki {
color: var(--shiki-light);
background-color: var(--shiki-light-bg);
@@ -46,7 +55,6 @@ $code-font-size: 0.875rem;
/* Optional, if you also want font styles */
font-style: var(--shiki-light-font-style);
font-weight: var(--shiki-light-font-weight);
text-decoration: var(--shiki-light-text-decoration);
}
.shiki-ln-line-highlighted,
+3
View File
@@ -35,6 +35,9 @@
vertical-align: top;
min-width: 10ch;
}
td:has(code) {
min-width: 8ch;
}
&:not(:last-child) {
border-block-end: 1px solid var(--senary-contrast);
}
@@ -41,3 +41,6 @@ export const setCookieConsent = (state: 'denied' | 'granted'): void => {
}
}
};
// This fixes the RollupError: Exported variable "global" is not defined.
export {};
+7
View File
@@ -40,6 +40,13 @@
}
}
// Lock the page behind the mobile primary-nav drawer. `clip` preserves the primary nav's sticky context.
@include mq.for-phone-only {
&:has(.adev-nav-primary--open) {
overflow: clip;
}
}
&:has(.adev-home) {
.adev-nav {
width: 0;
+6
View File
@@ -15,6 +15,7 @@ import {
provideZonelessChangeDetection,
provideEnvironmentInitializer,
} from '@angular/core';
import {UrlSerializer} from '@angular/router';
import {
DOCS_CONTENT_LOADER,
ENVIRONMENT,
@@ -33,6 +34,7 @@ import {CustomErrorHandler} from './core/services/errors-handling/error-handler'
import {ExampleContentLoader} from './core/services/example-content-loader.service';
import {routerProviders} from './routing/router_providers';
import {TYPESCRIPT_VFS_WORKER_PROVIDER} from './editor/code-editor/workers/factory-provider';
import {AdevUrlSerializer} from './core/services/routing/adev-url-serializer';
export const appConfig: ApplicationConfig = {
providers: [
@@ -53,5 +55,9 @@ export const appConfig: ApplicationConfig = {
deps: [DOCUMENT],
},
TYPESCRIPT_VFS_WORKER_PROVIDER,
{
provide: UrlSerializer,
useClass: AdevUrlSerializer,
},
],
};
@@ -436,6 +436,28 @@
</svg>
</a>
</li>
<li>
<a
[href]="ngLinks.STACKOVERFLOW"
cdkMenuItem
title="Angular Stack Overflow"
target="_blank"
rel="noopener"
>
<!-- Stack Overflow Icon -->
<svg
width="20"
height="20"
viewBox="0 0 26 31"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="m22.18 16.32.05.02-.02.01za19 19 0 0 0-2.45 4.14l-.03.07q-.94 2.19-1.29 4.6v.03a18 18 0 0 0-.05 4.85H.01v-4.88h15.94l.1-.6L.69 20.48l1.28-4.7 15.55 4.1.22-.46-13.96-7.96 2.47-4.22 14.16 8.07.34-.4L9.15 3.47 12.65 0l11.78 11.64 1.25 1.23q-1.97 1.5-3.5 3.44"
/>
</svg>
</a>
</li>
</ul>
</ng-template>
</div>
@@ -94,6 +94,7 @@
width: 100%;
padding-inline: calc(var(--layout-padding) - 1.25rem);
height: auto;
scrollbar-width: none;
padding-block: 0;
}
@@ -139,7 +140,7 @@
position: absolute;
top: 0;
background-color: var(--page-background);
box-shadow: 10px 4px 3px 0 rgba(0, 0, 0, 0.001);
box-shadow: 2px 0 0 0 var(--page-background);
transform: translateX(-100%);
// primary nav: exit delayed
@@ -169,6 +170,7 @@
@include mq.for-tablet {
flex-direction: row;
padding-block-start: 0;
}
// version dropdown button
@@ -233,7 +235,9 @@
@include mq.for-tablet {
flex-direction: row !important;
align-items: center;
margin-inline-end: 1.25rem;
margin-top: 0.25rem;
gap: 0.75rem;
}
@@ -289,6 +293,8 @@
@include mq.for-phone-only {
display: block;
position: relative;
top: 1rem;
}
}
@@ -35,6 +35,7 @@
@include mq.for-tablet-landscape-down {
position: absolute;
height: 100dvh;
}
@media (prefers-reduced-motion: no-preference) {
@@ -0,0 +1,25 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {DefaultUrlSerializer, UrlTree} from '@angular/router';
/**
* Custom URL serializer extending the default behavior
* with Adev-specific behavior.
*/
export class AdevUrlSerializer extends DefaultUrlSerializer {
override parse(url: string): UrlTree {
// Since the app host/server is decoding encoded forward slashes,
// we perform this on the client as well in order to maintain
// a consistent behavior between the two environments and
// avoid opening a different page on client hydration (presumably, 404).
url = url.replaceAll(/%2(F|f)/g, '/');
return super.parse(url);
}
}
@@ -0,0 +1,36 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {TestBed} from '@angular/core/testing';
import {UrlSerializer} from '@angular/router';
import {AdevUrlSerializer} from './adev-url-serializer';
describe('AdevUrlSerializer', () => {
let serializer: UrlSerializer;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
{
provide: UrlSerializer,
useClass: AdevUrlSerializer,
},
],
});
serializer = TestBed.inject(UrlSerializer);
});
it('should decode encoded forward slash (%2F)', () => {
// Uppercase hex
expect(serializer.parse('page%2Fabout').toString()).toBe('/page/about');
// Lowercase hex
expect(serializer.parse('page%2fabout').toString()).toBe('/page/about');
});
});
@@ -19,6 +19,8 @@ import {NodeRuntimeSandbox} from '../node-runtime-sandbox.service';
import {TypingsLoader} from '../typings-loader.service';
import {FileAndContentRecord} from '@angular/docs';
import {DomSanitizer} from '@angular/platform-browser';
import {NodeRuntimeState} from '../node-runtime-state.service';
import {CODE_EDITOR_EXTENSIONS} from './constants/code-editor-extensions';
import {LANGUAGES} from './constants/code-editor-languages';
import {getAutocompleteExtension} from './extensions/autocomplete';
@@ -26,10 +28,9 @@ import {getDiagnosticsExtension} from './extensions/diagnostics';
import {getTooltipExtension} from './extensions/tooltip';
import {DiagnosticsState} from './services/diagnostics-state.service';
import {TsVfsWorkerActions} from './workers/enums/actions';
import {TYPESCRIPT_VFS_WORKER_FACTORY} from './workers/factory-provider';
import {CodeChangeRequest} from './workers/interfaces/code-change-request';
import {ActionMessage} from './workers/interfaces/message';
import {NodeRuntimeState} from '../node-runtime-state.service';
import {TYPESCRIPT_VFS_WORKER_FACTORY} from './workers/factory-provider';
export interface EditorFile {
filename: string;
@@ -81,6 +82,7 @@ export class CodeMirrorEditor {
private readonly typingsLoader = inject(TypingsLoader);
private readonly destroyRef = inject(DestroyRef);
private readonly diagnosticsState = inject(DiagnosticsState);
private readonly domSanitizer = inject(DomSanitizer);
private readonly tsVfsWorkerFactory = inject(TYPESCRIPT_VFS_WORKER_FACTORY);
private tsVfsWorker: Worker | null = null;
@@ -448,7 +450,12 @@ export class CodeMirrorEditor {
this.sendRequestToTsVfs,
this.diagnosticsState,
),
getTooltipExtension(this.eventManager$, this.currentFile, this.sendRequestToTsVfs),
getTooltipExtension(
this.eventManager$,
this.currentFile,
this.sendRequestToTsVfs,
this.domSanitizer,
),
];
}
@@ -0,0 +1,41 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {DomSanitizer} from '@angular/platform-browser';
import {TestBed} from '@angular/core/testing';
import {getMarkedHtmlFromString, getTagsHtml} from './tooltip';
describe('getMarkedHtmlFromString', () => {
it('sanitizes markdown HTML content before assigning to innerHTML', () => {
const markdownContent = 'hello <img src=x onerror="alert(1)" />';
const domSanitizer = TestBed.inject(DomSanitizer);
const result = getMarkedHtmlFromString(markdownContent, domSanitizer);
expect(result.innerHTML.trim()).toBe('<p>hello <img src="x"></p>');
expect(result.innerHTML).not.toContain('onerror');
});
});
describe('getTagsHtml', () => {
it('sanitizes JSDoc tag content before assigning to innerHTML', () => {
const tags = [
{
name: 'example',
text: [{text: 'hello <img src=x onerror="alert(1)" />'}],
},
] as any[];
const domSanitizer = TestBed.inject(DomSanitizer);
const result = getTagsHtml(tags, domSanitizer);
expect(result.innerHTML).toContain('@example');
expect(result.innerHTML).not.toContain('onerror');
});
});
@@ -6,7 +6,9 @@
* found in the LICENSE file at https://angular.dev/license
*/
import {Signal} from '@angular/core';
import {SecurityContext, Signal} from '@angular/core';
import {DomSanitizer} from '@angular/platform-browser';
import {Tooltip, hoverTooltip} from '@codemirror/view';
import {marked} from 'marked';
import {Subject, filter, take} from 'rxjs';
@@ -23,6 +25,7 @@ export const getTooltipExtension = (
emitter: Subject<ActionMessage<DisplayTooltipResponse>>,
currentFile: Signal<EditorFile>,
sendRequestToTsVfs: (request: ActionMessage<DisplayTooltipRequest>) => void,
domSanitizer: DomSanitizer,
) => {
return hoverTooltip(
async (_, pos: number): Promise<Tooltip | null> => {
@@ -58,9 +61,9 @@ export const getTooltipExtension = (
// use documentation if available as it's more informative than tags
if (documentation?.[0]?.text) {
tooltip.appendChild(getMarkedHtmlFromString(documentation[0]?.text));
tooltip.appendChild(getMarkedHtmlFromString(documentation[0]?.text, domSanitizer));
} else if (tags?.length) {
tooltip.appendChild(getTagsHtml(tags));
tooltip.appendChild(getTagsHtml(tags, domSanitizer));
}
return {
@@ -91,9 +94,13 @@ function forceTooltipScrollTop() {
}
}
function getMarkedHtmlFromString(content: string): HTMLDivElement {
export function getMarkedHtmlFromString(
content: string,
domSanitizer: DomSanitizer,
): HTMLDivElement {
const wrapper = document.createElement('div');
wrapper.innerHTML = marked(content) as string;
const sanitizedHtml = renderAndSanitizeMarkdownToHtml(content, domSanitizer);
wrapper.innerHTML = sanitizedHtml;
return wrapper;
}
@@ -123,7 +130,7 @@ function getHtmlFromDisplayParts(displayParts: ts.SymbolDisplayPart[]): HTMLDivE
return wrapper;
}
function getTagsHtml(tags: ts.JSDocTagInfo[]): HTMLDivElement {
export function getTagsHtml(tags: ts.JSDocTagInfo[], domSanitizer: DomSanitizer): HTMLDivElement {
const tagsWrapper = document.createElement('div');
let contentString = '';
@@ -138,7 +145,14 @@ function getTagsHtml(tags: ts.JSDocTagInfo[]): HTMLDivElement {
}
}
tagsWrapper.innerHTML = marked(contentString) as string;
const sanitizedHtml = renderAndSanitizeMarkdownToHtml(contentString, domSanitizer);
tagsWrapper.innerHTML = sanitizedHtml;
return tagsWrapper;
}
function renderAndSanitizeMarkdownToHtml(content: string, domSanitizer: DomSanitizer): string {
const markedHtml = marked(content) as string;
const sanitizedHtml = domSanitizer.sanitize(SecurityContext.HTML, markedHtml) ?? '';
return sanitizedHtml;
}
@@ -160,7 +160,7 @@
<section class="explore-section" id="learn-more">
<div class="title">
<h2>What to learn more about Angular?</h2>
<h2>Want to learn more about Angular?</h2>
<div class="pattern"></div>
</div>
+12 -3
View File
@@ -28,8 +28,12 @@
left: calc(var(--layout-padding) + var(--primary-nav-width));
z-index: 1;
@include mq.for-tablet-down {
justify-content: flex-start;
@include mq.for-tablet-landscape-down {
justify-content: center;
margin-top: 4rem;
}
@include mq.for-phone-only {
margin-top: 1rem;
}
}
@@ -182,7 +186,7 @@ section {
}
.search-field {
@include mq.for-tablet-down() {
@include mq.for-tablet-landscape-down() {
display: none;
}
}
@@ -269,6 +273,11 @@ section {
width: fit-content;
margin: 0 auto 2rem;
@include mq.for-phone-only {
width: auto;
margin: 0 0.5rem 1rem;
}
.tab-background {
position: absolute;
top: 4px;
@@ -69,6 +69,7 @@
border-radius: 0.25rem;
padding: 0;
transform: translateY(-0.7rem);
background: var(--page-background);
li {
list-style: none;
@@ -33,6 +33,7 @@ describe('TutorialPlayground', () => {
class FakeNodeRuntimeSandbox {
init() {}
reset() {}
}
TestBed.configureTestingModule({
@@ -56,4 +57,22 @@ describe('TutorialPlayground', () => {
it('should create', () => {
expect(component).toBeTruthy();
});
it('should not call reset on the sandbox before it is initialized', async () => {
const fakeSandbox = {reset: jasmine.createSpy('reset')} as any;
component['nodeRuntimeSandbox'] = fakeSandbox;
component['isSandboxReady'].set(false);
spyOn<any>(component, 'loadTemplate').and.resolveTo();
await component.changeTemplate(component.templates[1]);
expect(fakeSandbox.reset).not.toHaveBeenCalled();
});
it('should call reset on the sandbox after it is initialized', async () => {
const fakeSandbox = {reset: jasmine.createSpy('reset')} as any;
component['nodeRuntimeSandbox'] = fakeSandbox;
component['isSandboxReady'].set(true);
spyOn<any>(component, 'loadTemplate').and.resolveTo();
await component.changeTemplate(component.templates[1]);
expect(fakeSandbox.reset).toHaveBeenCalled();
});
});
@@ -14,6 +14,7 @@ import {
DestroyRef,
EnvironmentInjector,
PLATFORM_ID,
signal,
Type,
effect,
inject,
@@ -55,6 +56,7 @@ export default class PlaygroundComponent {
protected nodeRuntimeSandbox?: NodeRuntimeSandbox;
protected embeddedEditorComponent?: Type<unknown>;
protected selectedTemplate: PlaygroundTemplate = this.defaultTemplate;
private readonly isSandboxReady = signal(false);
constructor() {
if (this.isServer) {
@@ -84,6 +86,7 @@ export default class PlaygroundComponent {
.subscribe(() => {
this.changeDetectorRef.markForCheck();
this.nodeRuntimeSandbox?.init();
this.isSandboxReady.set(true);
});
}
@@ -99,7 +102,9 @@ export default class PlaygroundComponent {
});
this.selectedTemplate = template;
await this.loadTemplate(template.path);
await this.nodeRuntimeSandbox?.reset();
if (this.isSandboxReady()) {
await this.nodeRuntimeSandbox?.reset();
}
}
private async loadTemplate(tutorialPath: string) {
@@ -25,12 +25,14 @@
border-block-end: 1px solid var(--senary-contrast);
padding-block-end: 2rem;
margin-block-end: 1rem;
-webkit-tap-highlight-color: transparent;
.adev-reference-list-type-filter-label {
margin-block: 2.5rem 1rem;
margin-block: 1rem;
}
.adev-reference-list-type-filter {
box-sizing: border-box;
display: grid;
grid-template-columns: repeat(6, 1fr);
margin-block: 0;
@@ -44,6 +46,7 @@
}
@container api-ref-page (max-width: 600px) {
grid-template-columns: repeat(4, 1fr);
max-width: 500px;
}
@container api-ref-page (max-width: 500px) {
grid-template-columns: repeat(3, 1fr);
@@ -87,16 +90,70 @@
.adev-reference-list-query-filter {
display: flex;
gap: 1.5rem;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
justify-content: space-between;
* {
box-sizing: border-box;
}
docs-text-field,
docs-select {
width: 100%;
max-width: 350px;
}
@container api-ref-page (max-width: 600px) {
flex-direction: column;
align-items: stretch;
docs-text-field,
docs-select {
width: 100%;
max-width: 500px;
}
}
}
.adev-reference-list-status {
display: flex;
align-items: center;
margin-top: 1rem;
::ng-deep .mat-mdc-chip-listbox {
@container api-ref-page (max-width: 600px) {
width: 100%;
max-width: 500px;
.mdc-evolution-chip-set__chips {
display: grid !important;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
margin-left: 0;
}
.mat-mdc-chip-option {
min-width: 0;
width: 100%;
margin: 0;
}
}
@container api-ref-page (max-width: 350px) {
.mdc-evolution-chip-set__chips {
grid-template-columns: 1fr;
}
}
}
}
}
.adev-reference-list-empty {
text-align: center;
margin-block-start: 2rem;
flex-basis: 100%;
p {
font-size: 1rem;
@@ -107,28 +164,3 @@
width: 100%;
}
}
.adev-reference-list-empty {
flex-basis: 100%;
p {
font-size: 1rem;
}
}
.docs-api-item-label-full {
white-space: nowrap;
}
.map-chip-option {
min-width: 190px;
}
.adev-reference-list-status {
display: flex;
align-items: center;
margin-top: 12px;
label {
margin-right: 8px;
}
}
+56 -35
View File
@@ -14,6 +14,12 @@ export enum ApplicationComplexity {
export interface Step {
step: string;
/**
* Action text rendered as Markdown. Use Markdown link syntax `[text](url)`
* for any links — raw `<a>` HTML tags bypass the custom link renderer in
* `update.component.ts` and will not pick up `target="_blank"` or the
* external-link icon.
*/
action: string;
possibleIn: number;
necessaryAsOf: number;
@@ -155,7 +161,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Advanced,
step: 'gendir',
action:
'Do not rely on `gendir`, instead look at using `skipTemplateCodeGen`. <a href=https://github.com/angular/angular/issues/19339#issuecomment-332607471" target="_blank">Read More</a>',
'Do not rely on `gendir`, instead look at using `skipTemplateCodeGen`. [Read More](https://github.com/angular/angular/issues/19339#issuecomment-332607471)',
},
{
possibleIn: 220,
@@ -239,7 +245,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: 'node 8',
action:
'Make sure you are using <a href="http://www.hostingadvice.com/how-to/update-node-js-latest-version/" target="_blank">Node 8 or later</a>',
'Make sure you are using [Node 8 or later](http://www.hostingadvice.com/how-to/update-node-js-latest-version/)',
},
{
possibleIn: 600,
@@ -248,7 +254,7 @@ export const RECOMMENDATIONS: Step[] = [
windows: false,
step: 'Update to CLI v6',
action:
'Update your Angular CLI, and migrate the configuration to the <a href="https://github.com/angular/angular-cli/wiki/angular-workspace" target="_blank">new angular.json format</a> by running the following:<br/><br/>`NG_DISABLE_VERSION_CHECK=1 npx @angular/cli@6 update @angular/cli@6`<br/>',
'Update your Angular CLI, and migrate the configuration to the [new angular.json format](https://github.com/angular/angular-cli/wiki/angular-workspace) by running the following:<br/><br/>`NG_DISABLE_VERSION_CHECK=1 npx @angular/cli@6 update @angular/cli@6`<br/>',
},
{
possibleIn: 600,
@@ -257,7 +263,7 @@ export const RECOMMENDATIONS: Step[] = [
windows: true,
step: 'Update to CLI v6',
action:
'Update your Angular CLI, and migrate the configuration to the <a href="https://github.com/angular/angular-cli/wiki/angular-workspace" target="_blank">new angular.json format</a> by running the following:<br/><br/>`cmd /C "set "NG_DISABLE_VERSION_CHECK=1" && npx @angular/cli@6 update @angular/cli@6 @angular/core@6"`<br/>',
'Update your Angular CLI, and migrate the configuration to the [new angular.json format](https://github.com/angular/angular-cli/wiki/angular-workspace) by running the following:<br/><br/>`cmd /C "set "NG_DISABLE_VERSION_CHECK=1" && npx @angular/cli@6 update @angular/cli@6 @angular/core@6"`<br/>',
},
{
possibleIn: 600,
@@ -343,7 +349,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Medium,
step: 'strictPropertyInitializer',
action:
'If you have TypeScript configured to be strict (if you have set `strict` to `true` in your `tsconfig.json` file), update your `tsconfig.json` to disable `strictPropertyInitialization` or move property initialization from `ngOnInit` to your constructor. You can learn more about this flag on the <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#strict-class-initialization">TypeScript 2.7 release notes</a>.',
'If you have TypeScript configured to be strict (if you have set `strict` to `true` in your `tsconfig.json` file), update your `tsconfig.json` to disable `strictPropertyInitialization` or move property initialization from `ngOnInit` to your constructor. You can learn more about this flag on the [TypeScript 2.7 release notes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#strict-class-initialization).',
},
{
possibleIn: 600,
@@ -351,7 +357,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: 'update to RxJS 6',
action:
'Remove deprecated RxJS 5 features using <a href="https://github.com/ReactiveX/rxjs-tslint" target="_blank">rxjs-tslint auto update rules</a><br/><br/>For most applications this will mean running the following two commands:<br/><br/>`npx rxjs-tslint`<br/>`rxjs-5-to-6-migrate -p src/tsconfig.app.json`',
'Remove deprecated RxJS 5 features using [rxjs-tslint auto update rules](https://github.com/ReactiveX/rxjs-tslint)<br/><br/>For most applications this will mean running the following two commands:<br/><br/>`npx rxjs-tslint`<br/>`rxjs-5-to-6-migrate -p src/tsconfig.app.json`',
},
{
possibleIn: 600,
@@ -374,7 +380,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: 'TypeScript 3.1',
action:
'Angular now uses TypeScript 3.1, read more about any potential breaking changes: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-1.html',
'Angular now uses TypeScript 3.1, read more about [any potential breaking changes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-1.html).',
},
{
possibleIn: 700,
@@ -382,7 +388,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: 'Node 10',
action:
'Angular has now added support for Node 10: https://nodejs.org/en/blog/release/v10.0.0/',
'Angular has now added support for [Node 10](https://nodejs.org/en/blog/release/v10.0.0/).',
},
{
possibleIn: 700,
@@ -464,7 +470,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: 'use ::ng-deep instead of /deep/',
action:
'Replace `/deep/` with `::ng-deep` in your styles, [read more about angular component styles and ::ng-deep](https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep). `/deep/` and `::ng-deep` both are deprecated but using `::ng-deep` is preferred until the shadow-piercing descendant combinator is [removed from browsers and tools](https://www.chromestatus.com/features/6750456638341120) completely.',
'Replace `/deep/` with `::ng-deep` in your styles, [read more about angular component styles and ::ng-deep](https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep). `/deep/` and `::ng-deep` both are deprecated but using `::ng-deep` is preferred until the shadow-piercing descendant combinator is [removed from browsers and tools](https://chromestatus.com/feature/5045542597951488) completely.',
},
{
possibleIn: 800,
@@ -480,7 +486,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: 'node 10',
action:
'Make sure you are using <a href="http://www.hostingadvice.com/how-to/update-node-js-latest-version/" target="_blank">Node 10 or later</a>.',
'Make sure you are using [Node 10 or later](http://www.hostingadvice.com/how-to/update-node-js-latest-version/).',
},
{
possibleIn: 800,
@@ -573,7 +579,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: 'node 10.13',
action:
'Make sure you are using <a href="http://www.hostingadvice.com/how-to/update-node-js-latest-version/" target="_blank">Node 10.13 or later</a>.',
'Make sure you are using [Node 10.13 or later](http://www.hostingadvice.com/how-to/update-node-js-latest-version/).',
},
{
possibleIn: 900,
@@ -782,8 +788,7 @@ export const RECOMMENDATIONS: Step[] = [
necessaryAsOf: 1000,
level: ApplicationComplexity.Basic,
step: 'v10 NodeJS 12',
action:
'Make sure you are using <a href="https://nodejs.org/dist/latest-v12.x/" target="_blank">Node 12 or later</a>.',
action: 'Make sure you are using [Node 12 or later](https://nodejs.org/dist/latest-v12.x/).',
},
{
possibleIn: 1000,
@@ -871,7 +876,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Medium,
step: 'esm5-bundles',
action:
"The [Angular Package Format](https://g.co/ng/apf) has been updated to remove `esm5` and `fesm5` formats. These are no longer distributed in our npm packages. If you don't use the CLI, you may need to downlevel Angular code to ES5 yourself.",
"The [Angular Package Format](https://angular.dev/tools/libraries/angular-package-format) has been updated to remove `esm5` and `fesm5` formats. These are no longer distributed in our npm packages. If you don't use the CLI, you may need to downlevel Angular code to ES5 yourself.",
},
{
possibleIn: 1000,
@@ -1335,7 +1340,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: 'TypeScript 4.4',
action:
'Angular now uses TypeScript 4.4, read more about any potential breaking changes: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-4.html',
'Angular now uses TypeScript 4.4, read more about [any potential breaking changes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-4.html).',
},
{
possibleIn: 1300,
@@ -1343,7 +1348,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: 'v13 node',
action:
'Make sure you are using <a href="http://www.hostingadvice.com/how-to/update-node-js-latest-version/" target="_blank">Node 12.20.0 or later</a>',
'Make sure you are using [Node 12.20.0 or later](http://www.hostingadvice.com/how-to/update-node-js-latest-version/)',
},
{
possibleIn: 1300,
@@ -1457,7 +1462,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: 'TypeScript 4.6',
action:
'Angular now uses TypeScript 4.6, read more about any potential breaking changes: https://devblogs.microsoft.com/typescript/announcing-typescript-4-6/',
'Angular now uses TypeScript 4.6, read more about [any potential breaking changes](https://devblogs.microsoft.com/typescript/announcing-typescript-4-6/).',
},
{
@@ -1466,7 +1471,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: 'v14 node',
action:
'Make sure you are using <a href="http://www.hostingadvice.com/how-to/update-node-js-latest-version/" target="_blank">Node 14.15.0 or later</a>',
'Make sure you are using [Node 14.15.0 or later](http://www.hostingadvice.com/how-to/update-node-js-latest-version/)',
},
{
possibleIn: 1400,
@@ -1669,7 +1674,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: 'v15 node support',
action:
'Make sure that you are using a supported version of node.js before you upgrade your application. Angular v15 supports node.js versions: 14.20.x, 16.13.x and 18.10.x. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-01" alt="Link to more information about this change">Read further</a>',
'Make sure that you are using a supported version of node.js before you upgrade your application. Angular v15 supports node.js versions: 14.20.x, 16.13.x and 18.10.x. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-01)',
},
{
possibleIn: 1500,
@@ -1677,7 +1682,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: 'v15 ts support',
action:
'Make sure that you are using a supported version of TypeScript before you upgrade your application. Angular v15 supports TypeScript version 4.8 or later. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-02" alt="Link to more information about this change">Read further</a>',
'Make sure that you are using a supported version of TypeScript before you upgrade your application. Angular v15 supports TypeScript version 4.8 or later. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-02)',
},
{
possibleIn: 1500,
@@ -1701,7 +1706,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Medium,
step: 'v15 keyframe',
action:
'In v15, the Angular compiler prefixes `@keyframes` in CSS with the component\'s scope. This means that any TypeScript code that relies on `keyframes` names no longer works in v15. Update any such instances to: define keyframes programmatically, use global stylesheets, or change the component\'s view encapsulation. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-03" alt="Link to more information about this change">Read further</a>',
"In v15, the Angular compiler prefixes `@keyframes` in CSS with the component's scope. This means that any TypeScript code that relies on `keyframes` names no longer works in v15. Update any such instances to: define keyframes programmatically, use global stylesheets, or change the component's view encapsulation. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-03)",
},
{
possibleIn: 1500,
@@ -1717,7 +1722,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Medium,
step: 'v15 base-decorators',
action:
'Make sure to use decorators in base classes with child classes that inherit constructors and use dependency injection. Such base classes should be decorated with either `@Injectable` or `@Directive` or the compiler returns an error. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-05" alt="Link to more information about this change">Read further</a>',
'Make sure to use decorators in base classes with child classes that inherit constructors and use dependency injection. Such base classes should be decorated with either `@Injectable` or `@Directive` or the compiler returns an error. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-05)',
},
{
possibleIn: 1500,
@@ -1725,7 +1730,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Medium,
step: 'v15 setDisabledState',
action:
'In v15, `setDisabledState` is always called when a `ControlValueAccessor` is attached. To opt-out of this behavior, use `FormsModule.withConfig` or `ReactiveFormsModule.withConfig`. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-06" alt="Link to more information about this change">Read further</a>',
'In v15, `setDisabledState` is always called when a `ControlValueAccessor` is attached. To opt-out of this behavior, use `FormsModule.withConfig` or `ReactiveFormsModule.withConfig`. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-06)',
},
{
possibleIn: 1500,
@@ -1733,7 +1738,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Advanced,
step: 'v15 canParse',
action:
'Applications that use `canParse` should use `analyze` from `@angular/localize/tools` instead. In v15, the `canParse` method was removed from all translation parsers in `@angular/localize/tools`. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-07" alt="Link to more information about this change">Read further</a>',
'Applications that use `canParse` should use `analyze` from `@angular/localize/tools` instead. In v15, the `canParse` method was removed from all translation parsers in `@angular/localize/tools`. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-07)',
},
{
possibleIn: 1500,
@@ -1741,7 +1746,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: 'v15 ActivatedRoutSnapshot',
action:
'Make sure that all `ActivatedRouteSnapshot` objects have a `title` property. In v15, the `title` property is a required property of `ActivatedRouteSnapshot`. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-08" alt="Link to more information about this change">Read further</a>',
'Make sure that all `ActivatedRouteSnapshot` objects have a `title` property. In v15, the `title` property is a required property of `ActivatedRouteSnapshot`. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-08)',
},
{
possibleIn: 1500,
@@ -1749,7 +1754,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Advanced,
step: 'v15 RouterOutlet',
action:
'If your tests with `RouterOutlet` break, make sure they don\'t depend on the instantiation order of the corresponding component relative to change detection. In v15, `RouterOutlet` instantiates the component after change detection. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-09" alt="Link to more information about this change">Read further</a>',
"If your tests with `RouterOutlet` break, make sure they don't depend on the instantiation order of the corresponding component relative to change detection. In v15, `RouterOutlet` instantiates the component after change detection. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-09)",
},
{
possibleIn: 1500,
@@ -1757,7 +1762,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: 'v15 relativeLinkResolution',
action:
'In v15, `relativeLinkResolution` is not configurable in the Router. It was used to opt out of an earlier bug fix that is now standard. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-10" alt="Link to more information about this change">Read further</a>',
'In v15, `relativeLinkResolution` is not configurable in the Router. It was used to opt out of an earlier bug fix that is now standard. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-10)',
},
{
possibleIn: 1500,
@@ -1765,7 +1770,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Medium,
step: 'v15 DATE_PIPE_DEFAULT_OPTIONS',
action:
'Change instances of the `DATE_PIPE_DEFAULT_TIMEZONE` token to use `DATE_PIPE_DEFAULT_OPTIONS` to configure time zones. In v15, the `DATE_PIPE_DEFAULT_TIMEZONE` token is deprecated. <a href="https://v15.angular.io/guide/update-to-version-15#v15-dp-01" alt="Link to more information about this change">Read further</a>',
'Change instances of the `DATE_PIPE_DEFAULT_TIMEZONE` token to use `DATE_PIPE_DEFAULT_OPTIONS` to configure time zones. In v15, the `DATE_PIPE_DEFAULT_TIMEZONE` token is deprecated. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-dp-01)',
},
{
possibleIn: 1500,
@@ -1781,7 +1786,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Medium,
step: 'v15 Injector.get',
action:
'Update instances of `Injector.get()` that use an `InjectFlags` parameter to use an `InjectOptions` parameter. The `InjectFlags` parameter of `Injector.get()` is deprecated in v15. <a href="https://v15.angular.io/guide/update-to-version-15#v15-dp-02" alt="Link to more information about this change">Read further</a>',
'Update instances of `Injector.get()` that use an `InjectFlags` parameter to use an `InjectOptions` parameter. The `InjectFlags` parameter of `Injector.get()` is deprecated in v15. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-dp-02)',
},
{
possibleIn: 1500,
@@ -1789,7 +1794,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: 'v15 TestBed.inject',
action:
'Update instances of `TestBed.inject()` that use an `InjectFlags` parameter to use an `InjectOptions` parameter. The `InjectFlags` parameter of `TestBed.inject()` is deprecated in v15. <a href="https://v15.angular.io/guide/update-to-version-15#v15-dp-01" alt="Link to more information about this change">Read further</a>',
'Update instances of `TestBed.inject()` that use an `InjectFlags` parameter to use an `InjectOptions` parameter. The `InjectFlags` parameter of `TestBed.inject()` is deprecated in v15. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-dp-01)',
},
{
possibleIn: 1500,
@@ -1797,7 +1802,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Medium,
step: 'v15 ngModule in providedIn',
action:
'Using `providedIn: ngModule` for an `@Injectable` and `InjectionToken` is deprecated in v15. <a href="https://v15.angular.io/guide/update-to-version-15#v15-dp-04" alt="Link to more information about this change">Read further</a>',
'Using `providedIn: ngModule` for an `@Injectable` and `InjectionToken` is deprecated in v15. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-dp-04)',
},
{
possibleIn: 1500,
@@ -1805,7 +1810,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: 'v15 providedIn any',
action:
'Using `providedIn: \'any\'` for an `@Injectable` or `InjectionToken` is deprecated in v15. <a href="https://v15.angular.io/guide/update-to-version-15#v15-dp-05" alt="Link to more information about this change">Read further</a>',
"Using `providedIn: 'any'` for an `@Injectable` or `InjectionToken` is deprecated in v15. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-dp-05)",
},
{
possibleIn: 1500,
@@ -1813,7 +1818,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Medium,
step: 'v15 RouterLinkWithHref',
action:
'Update instances of the `RouterLinkWithHref`directive to use the `RouterLink` directive. The `RouterLinkWithHref` directive is deprecated in v15. <a href="https://v15.angular.io/guide/update-to-version-15#v15-dp-06" alt="Link to more information about this change">Read further</a>',
'Update instances of the `RouterLinkWithHref`directive to use the `RouterLink` directive. The `RouterLinkWithHref` directive is deprecated in v15. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-dp-06)',
},
{
possibleIn: 1500,
@@ -1822,7 +1827,7 @@ export const RECOMMENDATIONS: Step[] = [
material: true,
step: 'v15 mat refactor',
action:
'In Angular Material v15, many of the components have been refactored to be based on the official Material Design Components for Web (MDC). This change affected the DOM and CSS classes of many components. <a href="https://rc.material.angular.dev/guide/mdc-migration" alt="Link to more information about this change">Read further</a>',
'In Angular Material v15, many of the components have been refactored to be based on the official Material Design Components for Web (MDC). This change affected the DOM and CSS classes of many components. [Read further](https://rc.material.angular.dev/guide/mdc-migration)',
},
{
possibleIn: 1500,
@@ -2669,7 +2674,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Basic,
step: '20.0.0_update_nodejs_version',
action:
'Ensure your Node.js version is at least 20.11.1 and not v18 or v22.0-v22.10 before upgrading to Angular v20. Check https://angular.dev/reference/versions for the full list of supported Node.js versions.',
'Ensure your Node.js version is at least 20.11.1 and not v18 or v22.0-v22.10 before upgrading to Angular v20. Check the [full list of supported Node.js versions](https://angular.dev/reference/versions).',
},
{
possibleIn: 2000,
@@ -2703,6 +2708,14 @@ export const RECOMMENDATIONS: Step[] = [
action:
"Upgrade your project's TypeScript version to at least 5.8 before upgrading to Angular v20 to ensure compatibility.",
},
{
possibleIn: 2000,
necessaryAsOf: 2000,
level: ApplicationComplexity.Medium,
step: '20.0.0_set_moduleResolution_to_bundler',
action:
"Set `moduleResolution` to `'bundler'` in your `tsconfig.json`. Angular CLI's `ng update` migration applies this change automatically; if you upgrade manually or override the option in a base tsconfig, set it explicitly so imports of secondary entry-points such as `@angular/core/rxjs-interop` continue to resolve correctly.",
},
{
possibleIn: 2000,
necessaryAsOf: 2000,
@@ -2912,4 +2925,12 @@ export const RECOMMENDATIONS: Step[] = [
action:
'The `lastSuccessfulNavigation` property on the Router has been converted to a signal. To get its value, you now need to invoke it as a function: `router.lastSuccessfulNavigation()`.',
},
{
possibleIn: 2100,
necessaryAsOf: 2100,
level: ApplicationComplexity.Medium,
step: '21.0.0-configure-commonengine-allowed-hosts',
action:
"Starting `@angular/ssr` 21.1.5, if your application uses SSR with `CommonEngine`, set the `allowedHosts` option in your `server.ts` (for example, `new CommonEngine({allowedHosts: ['localhost', '*.yourdomain.com']})`). Without it, SSR silently falls back to client-side rendering. This requirement comes from security advisory [GHSA-x288-3778-4hhx](https://github.com/angular/angular-cli/security/advisories/GHSA-x288-3778-4hhx) (also backported to 20.3.17 and 19.2.21).",
},
];
@@ -1,4 +1,4 @@
<div class="page docs-viewer">
<main class="page docs-viewer">
<h1 class="page-header" tabindex="-1">Update Guide</h1>
<div class="wizard">
<div>
@@ -205,4 +205,4 @@
}
</div>
}
</div>
</main>
@@ -1,12 +1,13 @@
@use '@angular/docs/styles/media-queries' as mq;
@use '@angular/docs/styles/links' as links;
$ver-dropdown-width: 200px;
$ver-dropdown-width: clamp(165px, 20vw, 200px);
:host {
display: flex;
flex-flow: column;
align-items: center;
padding: var(--layout-padding) 0px;
padding: var(--layout-padding);
container: update-guide-page / inline-size;
.docs-viewer {
@@ -172,7 +173,14 @@ h4 {
}
// Code blocks are generable from the markdown, we need to opt-out of the scoping
::ng-deep code {
cursor: pointer;
::ng-deep {
code {
cursor: pointer;
}
// External links (rendered with target="_blank") get an "open in new" icon
a[target='_blank'] {
@include links.external-link-with-icon;
}
}
}
@@ -13,7 +13,7 @@ import {provideHttpClientTesting} from '@angular/common/http/testing';
import {By} from '@angular/platform-browser';
import UpdateComponent from './update.component';
import {ApplicationComplexity} from './recommendations';
import {ApplicationComplexity, RECOMMENDATIONS} from './recommendations';
describe('UpdateComponent', () => {
let component: UpdateComponent;
@@ -91,4 +91,14 @@ describe('UpdateComponent', () => {
}
});
});
describe('RECOMMENDATIONS data', () => {
it('should use Markdown links instead of raw <a> HTML tags', () => {
for (const step of RECOMMENDATIONS) {
expect(step.action)
.withContext(`step "${step.step}" should use [text](url), not raw <a> HTML`)
.not.toMatch(/<a\s/i);
}
});
});
});
@@ -17,6 +17,20 @@ import {ActivatedRoute, Router} from '@angular/router';
import {marked} from 'marked';
import {MatSnackBar} from '@angular/material/snack-bar';
/**
* Configure marked with a custom link renderer so external links in the
* update guide open in a new tab, matching the convention applied elsewhere
* in adev via the `ExternalLink` directive.
*/
marked.use({
renderer: {
link({href, title, text}) {
const titleAttr = title ? ` title="${title}"` : '';
return `<a href="${href}"${titleAttr} target="_blank" rel="noopener noreferrer">${text}</a>`;
},
},
});
interface Option {
id: keyof Step;
name: string;
@@ -108,7 +122,7 @@ export default class UpdateComponent {
];
protected from = this.versions.find((version) => version.name === '20.0')!;
protected to = this.versions.find((version) => version.name === '21.0')!;
protected futureVersion = 2100;
protected futureVersion = 2200;
protected readonly steps: Step[] = RECOMMENDATIONS;
@@ -496,6 +496,27 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
category: 'Signal Forms',
status: 'new',
},
{
label: 'Cross-field logic',
path: 'guide/forms/signals/cross-field-logic',
contentPath: 'guide/forms/signals/cross-field-logic',
category: 'Signal Forms',
status: 'new',
},
{
label: 'Form submission',
path: 'guide/forms/signals/form-submission',
contentPath: 'guide/forms/signals/form-submission',
category: 'Signal Forms',
status: 'new',
},
{
label: 'Schemas',
path: 'guide/forms/signals/schemas',
contentPath: 'guide/forms/signals/schemas',
category: 'Signal Forms',
status: 'new',
},
{
label: 'Async operations',
path: 'guide/forms/signals/async-operations',
@@ -660,6 +681,7 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
path: 'guide/routing/testing',
contentPath: 'guide/routing/testing',
status: 'new',
isCrossReferenced: true,
},
{
label: 'Debugging tests',
@@ -863,6 +885,7 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
label: 'Route transition animations',
path: 'guide/routing/route-transition-animations',
contentPath: 'guide/routing/route-transition-animations',
isCrossReferenced: true,
},
],
},
@@ -875,7 +898,6 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
},
{
label: 'Build with AI',
status: 'new',
children: [
{
label: 'Get Started',
@@ -888,9 +910,10 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
contentPath: 'ai/develop-with-ai',
},
{
label: 'Design Patterns',
path: 'ai/design-patterns',
contentPath: 'ai/design-patterns',
label: 'Agent Skills',
path: 'ai/agent-skills',
contentPath: 'ai/agent-skills',
status: 'new',
},
{
label: 'Angular CLI MCP Server setup',
@@ -902,6 +925,11 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
path: 'ai/ai-tutor',
contentPath: 'ai/ai-tutor',
},
{
label: 'Design Patterns',
path: 'ai/design-patterns',
contentPath: 'ai/design-patterns',
},
],
},
{
@@ -1037,16 +1065,15 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
},
// TODO: create those guides
// The signal debugging docs should also be added to the signal section
// {
// label: 'Signals',
// path: 'tools/devtools/signals',
// contentPath: 'tools/devtools/signals',
// },
// {
// label: 'Router',
// path: 'tools/devtools/router',
// contentPath: 'tools/devtools/router',
// }
{
label: 'Router Tree',
path: 'tools/devtools/router',
contentPath: 'tools/devtools/router',
},
],
},
{
+2 -7
View File
@@ -128,13 +128,8 @@ export const REDIRECT_ROUTES: Route[] = [
redirectTo: '/tools/cli/build-system-migration#hot-module-replacement',
},
{
path: 'guide',
children: [
{
path: 'pipes',
redirectTo: '/guide/templates/pipes',
},
],
path: 'guide/pipes',
redirectTo: '/guide/templates/pipes',
},
{
path: 'guide/experimental/zoneless',
+3
View File
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="25" viewBox="0 -960 960 960" fill="#F637E3">
<path d="M450.001-611.691v-32.386q-39.385-9.923-64.692-41.897-25.308-31.975-25.308-74.025 0-49.922 35.038-84.96 35.039-35.038 84.961-35.038t84.961 35.038q35.038 35.038 35.038 84.96 0 42.05-25.308 74.025-25.307 31.974-64.692 41.897v32.386l273.846 157.538q17.173 9.912 26.663 26.582 9.491 16.671 9.491 36.495v62.152q0 19.824-9.491 36.495-9.49 16.67-26.663 26.582L516.154-111.771q-17.203 9.846-36.217 9.846t-36.091-9.846L176.155-265.847q-17.173-9.912-26.663-26.582-9.491-16.671-9.491-36.495v-62.152q0-19.824 9.491-36.495 9.49-16.67 26.663-26.582l273.846-157.538Zm-6.155 364.537L200-387.461v58.537q0 3.078 1.539 5.962 1.538 2.885 4.615 4.808l267.692 154.692q3.077 1.923 6.154 1.923t6.154-1.923l267.692-154.692q3.077-1.923 4.615-4.808 1.539-2.884 1.539-5.962v-58.537L516.154-247.154q-17.203 9.847-36.217 9.847t-36.091-9.847Zm6.155-162.847V-542.77L250.46-427.691l223.386 128.846q3.077 1.924 6.154 1.924t6.154-1.924l223.001-128.846L509.999-542.77v132.769h-59.998ZM480-699.999q25 0 42.5-17.5t17.5-42.5q0-25-17.5-42.5t-42.5-17.5q-25 0-42.5 17.5t-17.5 42.5q0 25 17.5 42.5t42.5 17.5Zm-2.308 538.61Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

+24
View File
@@ -0,0 +1,24 @@
# Agent Skills
Agent Skills are specialized, domain-specific instructions and capabilities designed for AI agents like Gemini CLI. These skills provide architectural guidance, generate idiomatic Angular code, and help scaffold new projects using modern best practices.
By using Agent Skills, you can ensure that the AI agent you are working with has the most up-to-date information about Angular's conventions, reactivity models (like Signals), and project structure.
## Available Skills
The Angular team maintains a collection of official skills that are regularly updated to stay in sync with the latest framework improvements.
| Skill | Description |
| :---------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`angular-developer`** | Generates Angular code and provides architectural guidance. Useful for creating components, services, or obtaining best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling, testing, or CLI tooling. |
| **`angular-new-app`** | Creates a new Angular app using the Angular CLI. Provides important guidelines for effectively setting up and structuring a modern Angular application. |
## Using Agent Skills
Agent Skills are designed to be used with agentic coding tools like [Gemini CLI](https://geminicli.com/docs/cli/skills/), [Antigravity](https://antigravity.google/docs/skills) and more. Activating a skill loads the specific instructions and resources needed for that task.
To use these skills in your own environment you may follow the instructions for your specific tool or use a community tool like [skills.sh](https://skills.sh/).
```bash
npx skills add https://github.com/angular/skills
```
+4 -3
View File
@@ -59,7 +59,7 @@ Here are examples of how to build with Genkit and Angular:
Here is an example of how to build with Firebase AI Logic and Angular:
- [Firebase AI Logic x Angular Starter Kit](https://github.com/angular/examples/tree/main/vertex-ai-firebase-angular-example) - Use this starter-kit to build an e-commerce application with a chat agent that can perform tasks. Start here if you do not have experience building with Firebase AI Logic and Angular.
- [Firebase AI Logic x Angular Starter Kit](https://github.com/angular/examples/tree/main/firebase-ai-logic-angular-example) - Use this starter-kit to build an e-commerce application with a chat agent that can perform tasks. Start here if you do not have experience building with Firebase AI Logic and Angular.
This example includes an [in-depth video walkthrough explaining the functionality and demonstrates how to add new features](https://youtube.com/live/4vfDz2al_BI).
@@ -79,7 +79,7 @@ When connecting to model providers, it is important to keep your API secrets saf
Your application's architecture determines which AI APIs and tools to choose. Specifically, choose based on whether or not your application is client-side or server-side. Tools such as Firebase AI Logic provide a secure connection to the model APIs for client-side code. If you want to use a different API than Firebase AI Logic or prefer to use a different model provider, consider creating a proxy-server or even [Cloud Functions for Firebase](https://firebase.google.com/docs/functions) to serve as a proxy and not expose your API keys.
For an example of connecting using a client-side app, see the code: [Firebase AI Logic Angular example repository](https://github.com/angular/examples/tree/main/vertex-ai-firebase-angular-example).
For an example of connecting using a client-side app, see the code: [Firebase AI Logic Angular example repository](https://github.com/angular/examples/tree/main/firebase-ai-logic-angular-example).
For server-side connections to model APIs that require API keys, prefer using a secrets manager or environment variable, not `environments.ts`. You should follow standard best practices for securing API keys and credentials. Firebase now provides a new secrets manager with the latest updates from Firebase App Hosting. To learn more, [check out the official documentation](https://firebase.google.com/docs/app-hosting/configure).
@@ -91,7 +91,7 @@ If you want to build agentic workflows, where agents are able to act and use too
Tool calling further enhances your web apps by expanding your AI integration further than a question and answer style chat bot. In fact, you can empower your model to request function calls using the function calling API of your model provider. The available tools can be used to perform more complex actions within the context of your application.
In the [e-commerce example](https://github.com/angular/examples/blob/main/vertex-ai-firebase-angular-example/src/app/ai.service.ts#L88) of the [Angular examples repository](https://github.com/angular/examples), the LLM requests to make calls to functions for inventory in order to gain the necessary context to perform more complex tasks such as calculating how much a group of items in the store will cost. The scope of the available API is up to you as a developer just as is whether or not to call a function requested by the LLM. You remain in control of the flow of execution. You can expose specific functions of a service for example but not all functions of that service.
In the [e-commerce example](https://github.com/angular/examples/blob/main/firebase-ai-logic-angular-example/src/app/ai.service.ts#L88) of the [Angular examples repository](https://github.com/angular/examples), the LLM requests to make calls to functions for inventory in order to gain the necessary context to perform more complex tasks such as calculating how much a group of items in the store will cost. The scope of the available API is up to you as a developer just as is whether or not to call a function requested by the LLM. You remain in control of the flow of execution. You can expose specific functions of a service for example but not all functions of that service.
### Handling non-deterministic responses
@@ -115,4 +115,5 @@ To learn about LLM prompts and AI IDE setup, see the following guides:
<docs-pill-row>
<docs-pill href="ai/develop-with-ai" title="LLM prompts and IDE setup"/>
<docs-pill href="ai/agent-skills" title="Agent Skills"/>
</docs-pill-row>
+1 -1
View File
@@ -1,4 +1,4 @@
{
"branchName": "refs/heads/21.2.x",
"sha": "a076ff7f05b678c4cdc6b85dbfe474a09f56022a"
"sha": "faea5e033fd1bc0a5dec7e430434414d1cf6243d"
}
+87 -48
View File
@@ -44,16 +44,6 @@
"description": "A global unique identifier for the panel.",
"jsdocTags": []
},
{
"name": "panelId",
"type": "InputSignal<string>",
"memberType": "property",
"memberTags": [
"readonly"
],
"description": "A local unique identifier for the panel, used to match with its trigger's `panelId`.",
"jsdocTags": []
},
{
"name": "visible",
"type": "Signal<boolean>",
@@ -165,7 +155,7 @@
}
],
"generics": [],
"description": "The content panel of an accordion item that is conditionally visible.\n\nThis directive is a container for the content that is shown or hidden. It requires\na `panelId` that must match the `panelId` of its corresponding `ngAccordionTrigger`.\nThe content within the panel should be provided using an `ng-template` with the\n`ngAccordionContent` directive so that the content is not rendered on the page until the trigger\nis expanded. It applies `role=\"region\"` for accessibility and uses the `inert` attribute to hide\nits content from assistive technologies when not visible.\n\n```html\n<div ngAccordionPanel panelId=\"unique-id-1\">\n <ng-template ngAccordionContent>\n <p>This content is lazily rendered and will be shown when the panel is expanded.</p>\n </ng-template>\n</div>\n```",
"description": "The content panel of an accordion item that is conditionally visible.\n\nThis directive is a container for the content that is shown or hidden. It should\nexpose a template reference that will be used by the corresponding `ngAccordionTrigger`.\nThe content within the panel should be provided using an `ng-template` with the\n`ngAccordionContent` directive so that the content is not rendered on the page until the trigger\nis expanded. It applies `role=\"region\"` for accessibility and uses the `inert` attribute to hide\nits content from assistive technologies when not visible.\n\n```html\n<div ngAccordionPanel #panel=\"ngAccordionPanel\">\n <ng-template ngAccordionContent>\n <p>This content is lazily rendered and will be shown when the panel is expanded.</p>\n </ng-template>\n</div>\n```",
"jsdocTags": [
{
"name": "developerPreview",
@@ -176,12 +166,12 @@
"comment": "[Accordion](guide/aria/accordion)"
}
],
"rawComment": "/**\n * The content panel of an accordion item that is conditionally visible.\n *\n * This directive is a container for the content that is shown or hidden. It requires\n * a `panelId` that must match the `panelId` of its corresponding `ngAccordionTrigger`.\n * The content within the panel should be provided using an `ng-template` with the\n * `ngAccordionContent` directive so that the content is not rendered on the page until the trigger\n * is expanded. It applies `role=\"region\"` for accessibility and uses the `inert` attribute to hide\n * its content from assistive technologies when not visible.\n *\n * ```html\n * <div ngAccordionPanel panelId=\"unique-id-1\">\n * <ng-template ngAccordionContent>\n * <p>This content is lazily rendered and will be shown when the panel is expanded.</p>\n * </ng-template>\n * </div>\n * ```\n *\n * @developerPreview 21.0\n * @see [Accordion](guide/aria/accordion)\n */",
"rawComment": "/**\n * The content panel of an accordion item that is conditionally visible.\n *\n * This directive is a container for the content that is shown or hidden. It should\n * expose a template reference that will be used by the corresponding `ngAccordionTrigger`.\n * The content within the panel should be provided using an `ng-template` with the\n * `ngAccordionContent` directive so that the content is not rendered on the page until the trigger\n * is expanded. It applies `role=\"region\"` for accessibility and uses the `inert` attribute to hide\n * its content from assistive technologies when not visible.\n *\n * ```html\n * <div ngAccordionPanel #panel=\"ngAccordionPanel\">\n * <ng-template ngAccordionContent>\n * <p>This content is lazily rendered and will be shown when the panel is expanded.</p>\n * </ng-template>\n * </div>\n * ```\n *\n * @developerPreview 21.0\n * @see [Accordion](guide/aria/accordion)\n */",
"implements": [],
"source": {
"filePath": "/src/aria/accordion/accordion-panel.ts",
"startLine": 42,
"endLine": 103
"startLine": 34,
"endLine": 88
}
},
{
@@ -199,6 +189,19 @@
"description": "A reference to the trigger element.",
"jsdocTags": []
},
{
"name": "panel",
"type": "InputSignal<AccordionPanel>",
"memberType": "property",
"memberTags": [
"readonly",
"input"
],
"description": "The associated AccordionPanel.",
"jsdocTags": [],
"inputAlias": "panel",
"isRequiredInput": true
},
{
"name": "id",
"type": "InputSignal<any>",
@@ -207,23 +210,20 @@
"readonly",
"input"
],
"description": "A unique identifier for the widget.",
"description": "The unique identifier for the trigger.",
"jsdocTags": [],
"inputAlias": "id",
"isRequiredInput": false
},
{
"name": "panelId",
"type": "InputSignal<string>",
"type": "Signal<any>",
"memberType": "property",
"memberTags": [
"readonly",
"input"
"readonly"
],
"description": "A local unique identifier for the trigger, used to match with its panel's `panelId`.",
"jsdocTags": [],
"inputAlias": "panelId",
"isRequiredInput": true
"description": "The unique identifier for the correspondingtrigger panel.",
"jsdocTags": []
},
{
"name": "disabled",
@@ -263,6 +263,39 @@
"description": "Whether the trigger is active.",
"jsdocTags": []
},
{
"name": "ngOnInit",
"signatures": [
{
"name": "ngOnInit",
"entryType": "function",
"description": "",
"generics": [],
"isNewType": false,
"jsdocTags": [],
"params": [],
"rawComment": "",
"returnType": "void"
}
],
"implementation": {
"params": [],
"isNewType": false,
"returnType": "void",
"generics": [],
"name": "ngOnInit",
"description": "",
"entryType": "function",
"jsdocTags": [],
"rawComment": ""
},
"entryType": "function",
"description": "",
"jsdocTags": [],
"rawComment": "",
"memberType": "method",
"memberTags": []
},
{
"name": "expand",
"signatures": [
@@ -364,7 +397,7 @@
}
],
"generics": [],
"description": "The trigger that toggles the visibility of its associated `ngAccordionPanel`.\n\nThis directive requires a `panelId` that must match the `panelId` of the `ngAccordionPanel` it\ncontrols. When clicked, it will expand or collapse the panel. It also handles keyboard\ninteractions for navigation within the `ngAccordionGroup`. It applies `role=\"button\"` and manages\n`aria-expanded`, `aria-controls`, and `aria-disabled` attributes for accessibility.\nThe `disabled` input can be used to disable the trigger.\n\n```html\n<button ngAccordionTrigger panelId=\"unique-id-1\">\n Accordion Trigger Text\n</button>\n```",
"description": "The trigger that toggles the visibility of its associated `ngAccordionPanel`.\n\nThis directive requires the `panel` input be set to the template reference of the `ngAccordionPanel`\nit controls. When clicked, it will expand or collapse the panel. It also handles keyboard\ninteractions for navigation within the `ngAccordionGroup`. It applies `role=\"button\"` and manages\n`aria-expanded`, `aria-controls`, and `aria-disabled` attributes for accessibility.\nThe `disabled` input can be used to disable the trigger.\n\n```html\n<button ngAccordionTrigger [panel]=\"panel\">\n Accordion Trigger Text\n</button>\n```",
"jsdocTags": [
{
"name": "developerPreview",
@@ -375,8 +408,10 @@
"comment": "[Accordion](guide/aria/accordion)"
}
],
"rawComment": "/**\n * The trigger that toggles the visibility of its associated `ngAccordionPanel`.\n *\n * This directive requires a `panelId` that must match the `panelId` of the `ngAccordionPanel` it\n * controls. When clicked, it will expand or collapse the panel. It also handles keyboard\n * interactions for navigation within the `ngAccordionGroup`. It applies `role=\"button\"` and manages\n * `aria-expanded`, `aria-controls`, and `aria-disabled` attributes for accessibility.\n * The `disabled` input can be used to disable the trigger.\n *\n * ```html\n * <button ngAccordionTrigger panelId=\"unique-id-1\">\n * Accordion Trigger Text\n * </button>\n * ```\n *\n * @developerPreview 21.0\n * @see [Accordion](guide/aria/accordion)\n */",
"implements": [],
"rawComment": "/**\n * The trigger that toggles the visibility of its associated `ngAccordionPanel`.\n *\n * This directive requires the `panel` input be set to the template reference of the `ngAccordionPanel`\n * it controls. When clicked, it will expand or collapse the panel. It also handles keyboard\n * interactions for navigation within the `ngAccordionGroup`. It applies `role=\"button\"` and manages\n * `aria-expanded`, `aria-controls`, and `aria-disabled` attributes for accessibility.\n * The `disabled` input can be used to disable the trigger.\n *\n * ```html\n * <button ngAccordionTrigger [panel]=\"panel\">\n * Accordion Trigger Text\n * </button>\n * ```\n *\n * @developerPreview 21.0\n * @see [Accordion](guide/aria/accordion)\n */",
"implements": [
"OnInit"
],
"isStandalone": true,
"selector": "[ngAccordionTrigger]",
"exportAs": [
@@ -388,7 +423,7 @@
"source": {
"filePath": "/src/aria/accordion/accordion-trigger.ts",
"startLine": 42,
"endLine": 107
"endLine": 112
}
},
{
@@ -536,7 +571,7 @@
}
],
"generics": [],
"description": "A container for a group of accordion items. It manages the overall state and\ninteractions of the accordion, such as keyboard navigation and expansion mode.\n\nThe `ngAccordionGroup` serves as the root of a group of accordion triggers and panels,\ncoordinating the behavior of the `ngAccordionTrigger` and `ngAccordionPanel` elements within it.\nIt supports both single and multiple expansion modes.\n\n```html\n<div ngAccordionGroup [multiExpandable]=\"true\" [(expandedPanels)]=\"expandedItems\">\n <div class=\"accordion-item\">\n <h3>\n <button ngAccordionTrigger panelId=\"item-1\">Item 1</button>\n </h3>\n <div ngAccordionPanel panelId=\"item-1\">\n <ng-template ngAccordionContent>\n <p>Content for Item 1.</p>\n </ng-template>\n </div>\n </div>\n <div class=\"accordion-item\">\n <h3>\n <button ngAccordionTrigger panelId=\"item-2\">Item 2</button>\n </h3>\n <div ngAccordionPanel panelId=\"item-2\">\n <ng-template ngAccordionContent>\n <p>Content for Item 2.</p>\n </ng-template>\n </div>\n </div>\n</div>\n```",
"description": "A container for a group of accordion items. It manages the overall state and\ninteractions of the accordion, such as keyboard navigation and expansion mode.\n\nThe `ngAccordionGroup` serves as the root of a group of accordion triggers and panels,\ncoordinating the behavior of the `ngAccordionTrigger` and `ngAccordionPanel` elements within it.\nIt supports both single and multiple expansion modes.\n\n```html\n<div ngAccordionGroup [multiExpandable]=\"true\">\n <div class=\"accordion-item\">\n <h3>\n <button ngAccordionTrigger [panel]=\"panel1\">Item 1</button>\n </h3>\n <div ngAccordionPanel #panel1=\"ngAccordionPanel\">\n <ng-template ngAccordionContent>\n <p>Content for Item 1.</p>\n </ng-template>\n </div>\n </div>\n <div class=\"accordion-item\">\n <h3>\n <button ngAccordionTrigger [panel]=\"panel2\">Item 2</button>\n </h3>\n <div ngAccordionPanel #panel2=\"ngAccordionPanel\">\n <ng-template ngAccordionContent>\n <p>Content for Item 2.</p>\n </ng-template>\n </div>\n </div>\n</div>\n```",
"jsdocTags": [
{
"name": "developerPreview",
@@ -547,7 +582,7 @@
"comment": "[Accordion](guide/aria/accordion)"
}
],
"rawComment": "/**\n * A container for a group of accordion items. It manages the overall state and\n * interactions of the accordion, such as keyboard navigation and expansion mode.\n *\n * The `ngAccordionGroup` serves as the root of a group of accordion triggers and panels,\n * coordinating the behavior of the `ngAccordionTrigger` and `ngAccordionPanel` elements within it.\n * It supports both single and multiple expansion modes.\n *\n * ```html\n * <div ngAccordionGroup [multiExpandable]=\"true\" [(expandedPanels)]=\"expandedItems\">\n * <div class=\"accordion-item\">\n * <h3>\n * <button ngAccordionTrigger panelId=\"item-1\">Item 1</button>\n * </h3>\n * <div ngAccordionPanel panelId=\"item-1\">\n * <ng-template ngAccordionContent>\n * <p>Content for Item 1.</p>\n * </ng-template>\n * </div>\n * </div>\n * <div class=\"accordion-item\">\n * <h3>\n * <button ngAccordionTrigger panelId=\"item-2\">Item 2</button>\n * </h3>\n * <div ngAccordionPanel panelId=\"item-2\">\n * <ng-template ngAccordionContent>\n * <p>Content for Item 2.</p>\n * </ng-template>\n * </div>\n * </div>\n * </div>\n * ```\n *\n * @developerPreview 21.0\n * @see [Accordion](guide/aria/accordion)\n */",
"rawComment": "/**\n * A container for a group of accordion items. It manages the overall state and\n * interactions of the accordion, such as keyboard navigation and expansion mode.\n *\n * The `ngAccordionGroup` serves as the root of a group of accordion triggers and panels,\n * coordinating the behavior of the `ngAccordionTrigger` and `ngAccordionPanel` elements within it.\n * It supports both single and multiple expansion modes.\n *\n * ```html\n * <div ngAccordionGroup [multiExpandable]=\"true\">\n * <div class=\"accordion-item\">\n * <h3>\n * <button ngAccordionTrigger [panel]=\"panel1\">Item 1</button>\n * </h3>\n * <div ngAccordionPanel #panel1=\"ngAccordionPanel\">\n * <ng-template ngAccordionContent>\n * <p>Content for Item 1.</p>\n * </ng-template>\n * </div>\n * </div>\n * <div class=\"accordion-item\">\n * <h3>\n * <button ngAccordionTrigger [panel]=\"panel2\">Item 2</button>\n * </h3>\n * <div ngAccordionPanel #panel2=\"ngAccordionPanel\">\n * <ng-template ngAccordionContent>\n * <p>Content for Item 2.</p>\n * </ng-template>\n * </div>\n * </div>\n * </div>\n * ```\n *\n * @developerPreview 21.0\n * @see [Accordion](guide/aria/accordion)\n */",
"implements": [],
"isStandalone": true,
"selector": "[ngAccordionGroup]",
@@ -559,8 +594,8 @@
],
"source": {
"filePath": "src/aria/accordion/accordion-group.ts",
"startLine": 62,
"endLine": 158
"startLine": 60,
"endLine": 120
}
}
],
@@ -569,28 +604,20 @@
"Directive",
"@angular/core"
],
[
"input",
"@angular/core"
],
[
"inject",
"@angular/core"
],
[
"afterRenderEffect",
"@angular/core"
],
[
"signal",
"@angular/core"
],
[
"computed",
"@angular/core"
],
[
"WritableSignal",
"inject",
"@angular/core"
],
[
"input",
"@angular/core"
],
[
@@ -602,17 +629,25 @@
"@angular/core"
],
[
"model",
"OnInit",
"@angular/core"
],
[
"booleanAttribute",
"@angular/core"
],
[
"model",
"@angular/core"
],
[
"contentChildren",
"@angular/core"
],
[
"signal",
"@angular/core"
],
[
"Directionality",
"@angular/cdk/bidi"
@@ -645,10 +680,6 @@
"AccordionPanel.id",
"@angular/aria/accordion"
],
[
"AccordionPanel.panelId",
"@angular/aria/accordion"
],
[
"AccordionPanel.visible",
"@angular/aria/accordion"
@@ -673,6 +704,10 @@
"AccordionTrigger.element",
"@angular/aria/accordion"
],
[
"AccordionTrigger.panel",
"@angular/aria/accordion"
],
[
"AccordionTrigger.id",
"@angular/aria/accordion"
@@ -693,6 +728,10 @@
"AccordionTrigger.active",
"@angular/aria/accordion"
],
[
"AccordionTrigger.ngOnInit",
"@angular/aria/accordion"
],
[
"AccordionTrigger.expand",
"@angular/aria/accordion"
+1 -1
View File
@@ -792,7 +792,7 @@
"source": {
"filePath": "/src/aria/menu/menu.ts",
"startLine": 58,
"endLine": 194
"endLine": 201
}
}
],
+3 -3
View File
@@ -6,9 +6,9 @@ Keeping your Angular application up-to-date enables you to take advantage of lea
This document contains information and resources to help you keep your Angular applications and libraries up-to-date.
For information about our versioning policy and practices —including support and deprecation practices, as well as the release schedule— see [Angular versioning and releases](reference/releases 'Angular versioning and releases').
For information about our versioning policy and practices — including support and deprecation practices, as well as the release schedule — see [Angular versioning and releases](reference/releases 'Angular versioning and releases').
HELPFUL: If you are currently using AngularJS, see [Upgrading from AngularJS](https://angular.io/guide/upgrade 'Upgrading from Angular JS').
HELPFUL: If you are currently using AngularJS, see [Upgrading from AngularJS](https://angular.io/guide/upgrade 'Upgrading from AngularJS').
_AngularJS_ is the name for all v1.x versions of Angular.
## Getting notified of new releases
@@ -30,7 +30,7 @@ To check your application's version of Angular use the `ng version` command from
The most recent stable released version of Angular appears [on npm](https://www.npmjs.com/package/@angular/core 'Angular on npm') under "Version." For example, `16.2.4`.
You can also find the most current version of Angular by using the CLI command [`ng update`](cli/update).
By default, [`ng update`](cli/update)(without additional arguments) lists the updates that are available to you.
By default, [`ng update`](cli/update) (without additional arguments) lists the updates that are available to you.
## Updating your environment and apps
+1 -1
View File
@@ -1,4 +1,4 @@
{
"branchName": "refs/heads/21.2.x",
"sha": "fc8b94d631a5d105a87abc2a008a6e8f76d7f3f5"
"sha": "4e2c69bca091e2218fd456afe797826f033a76f2"
}
+99 -99
View File
@@ -482,19 +482,6 @@
"endLine": 19
}
},
{
"name": "CDK_DROP_LIST_GROUP",
"type": "any",
"entryType": "constant",
"rawComment": "/**\n * Injection token that can be used to reference instances of `CdkDropListGroup`. It serves as\n * alternative token to the actual `CdkDropListGroup` class which could cause unnecessary\n * retention of the class and its directive metadata.\n */",
"description": "Injection token that can be used to reference instances of `CdkDropListGroup`. It serves as\nalternative token to the actual `CdkDropListGroup` class which could cause unnecessary\nretention of the class and its directive metadata.",
"jsdocTags": [],
"source": {
"filePath": "/src/cdk/drag-drop/directives/drop-list-group.ts",
"startLine": 16,
"endLine": 18
}
},
{
"name": "CdkDragRelease",
"entryType": "interface",
@@ -533,6 +520,19 @@
"endLine": 26
}
},
{
"name": "CDK_DROP_LIST_GROUP",
"type": "any",
"entryType": "constant",
"rawComment": "/**\n * Injection token that can be used to reference instances of `CdkDropListGroup`. It serves as\n * alternative token to the actual `CdkDropListGroup` class which could cause unnecessary\n * retention of the class and its directive metadata.\n */",
"description": "Injection token that can be used to reference instances of `CdkDropListGroup`. It serves as\nalternative token to the actual `CdkDropListGroup` class which could cause unnecessary\nretention of the class and its directive metadata.",
"jsdocTags": [],
"source": {
"filePath": "/src/cdk/drag-drop/directives/drop-list-group.ts",
"startLine": 17,
"endLine": 19
}
},
{
"name": "CDK_DRAG_PLACEHOLDER",
"type": "any",
@@ -559,70 +559,6 @@
"endLine": 25
}
},
{
"name": "CdkDropListGroup",
"isAbstract": false,
"entryType": "undecorated_class",
"members": [
{
"name": "disabled",
"type": "boolean",
"memberType": "property",
"memberTags": [],
"description": "Whether starting a dragging sequence from inside this group is disabled.",
"jsdocTags": []
},
{
"name": "ngOnDestroy",
"signatures": [
{
"name": "ngOnDestroy",
"entryType": "function",
"description": "",
"generics": [],
"isNewType": false,
"jsdocTags": [],
"params": [],
"rawComment": "",
"returnType": "void"
}
],
"implementation": {
"params": [],
"isNewType": false,
"returnType": "void",
"generics": [],
"name": "ngOnDestroy",
"description": "",
"entryType": "function",
"jsdocTags": [],
"rawComment": ""
},
"entryType": "function",
"description": "",
"jsdocTags": [],
"rawComment": "",
"memberType": "method",
"memberTags": []
}
],
"generics": [
{
"name": "T"
}
],
"description": "Declaratively connects sibling `cdkDropList` instances together. All of the `cdkDropList`\nelements that are placed inside a `cdkDropListGroup` will be connected to each other\nautomatically. Can be used as an alternative to the `cdkDropListConnectedTo` input\nfrom `cdkDropList`.",
"jsdocTags": [],
"rawComment": "/**\n * Declaratively connects sibling `cdkDropList` instances together. All of the `cdkDropList`\n * elements that are placed inside a `cdkDropListGroup` will be connected to each other\n * automatically. Can be used as an alternative to the `cdkDropListConnectedTo` input\n * from `cdkDropList`.\n */",
"implements": [
"OnDestroy"
],
"source": {
"filePath": "/src/cdk/drag-drop/directives/drop-list-group.ts",
"startLine": 26,
"endLine": 42
}
},
{
"name": "CdkDragPlaceholder",
"isAbstract": false,
@@ -706,6 +642,70 @@
"endLine": 44
}
},
{
"name": "CdkDropListGroup",
"isAbstract": false,
"entryType": "undecorated_class",
"members": [
{
"name": "disabled",
"type": "boolean",
"memberType": "property",
"memberTags": [],
"description": "Whether starting a dragging sequence from inside this group is disabled.",
"jsdocTags": []
},
{
"name": "ngOnDestroy",
"signatures": [
{
"name": "ngOnDestroy",
"entryType": "function",
"description": "",
"generics": [],
"isNewType": false,
"jsdocTags": [],
"params": [],
"rawComment": "",
"returnType": "void"
}
],
"implementation": {
"params": [],
"isNewType": false,
"returnType": "void",
"generics": [],
"name": "ngOnDestroy",
"description": "",
"entryType": "function",
"jsdocTags": [],
"rawComment": ""
},
"entryType": "function",
"description": "",
"jsdocTags": [],
"rawComment": "",
"memberType": "method",
"memberTags": []
}
],
"generics": [
{
"name": "T"
}
],
"description": "Declaratively connects sibling `cdkDropList` instances together. All of the `cdkDropList`\nelements that are placed inside a `cdkDropListGroup` will be connected to each other\nautomatically. Can be used as an alternative to the `cdkDropListConnectedTo` input\nfrom `cdkDropList`.",
"jsdocTags": [],
"rawComment": "/**\n * Declaratively connects sibling `cdkDropList` instances together. All of the `cdkDropList`\n * elements that are placed inside a `cdkDropListGroup` will be connected to each other\n * automatically. Can be used as an alternative to the `cdkDropListConnectedTo` input\n * from `cdkDropList`.\n */",
"implements": [
"OnDestroy"
],
"source": {
"filePath": "/src/cdk/drag-drop/directives/drop-list-group.ts",
"startLine": 27,
"endLine": 43
}
},
{
"name": "CdkDragPreview",
"isAbstract": false,
@@ -6294,11 +6294,11 @@
"@angular/core"
],
[
"OnDestroy",
"Input",
"@angular/core"
],
[
"Input",
"OnDestroy",
"@angular/core"
],
[
@@ -6422,11 +6422,11 @@
"@angular/cdk/drag-drop"
],
[
"CDK_DROP_LIST_GROUP",
"CdkDragRelease",
"@angular/cdk/drag-drop"
],
[
"CdkDragRelease",
"CDK_DROP_LIST_GROUP",
"@angular/cdk/drag-drop"
],
[
@@ -6438,11 +6438,11 @@
"@angular/cdk/drag-drop"
],
[
"CdkDropListGroup",
"CdkDragPlaceholder",
"@angular/cdk/drag-drop"
],
[
"CdkDragPlaceholder",
"CdkDropListGroup",
"@angular/cdk/drag-drop"
],
[
@@ -6593,10 +6593,6 @@
"DropListOrientation",
"@angular/cdk/drag-drop"
],
[
"CDK_DROP_LIST_GROUP",
"@angular/cdk/drag-drop"
],
[
"CdkDragRelease",
"@angular/cdk/drag-drop"
@@ -6609,6 +6605,10 @@
"CdkDragRelease.event",
"@angular/cdk/drag-drop"
],
[
"CDK_DROP_LIST_GROUP",
"@angular/cdk/drag-drop"
],
[
"CDK_DRAG_PLACEHOLDER",
"@angular/cdk/drag-drop"
@@ -6617,18 +6617,6 @@
"CDK_DRAG_PREVIEW",
"@angular/cdk/drag-drop"
],
[
"CdkDropListGroup",
"@angular/cdk/drag-drop"
],
[
"CdkDropListGroup.disabled",
"@angular/cdk/drag-drop"
],
[
"CdkDropListGroup.ngOnDestroy",
"@angular/cdk/drag-drop"
],
[
"CdkDragPlaceholder",
"@angular/cdk/drag-drop"
@@ -6645,6 +6633,18 @@
"CdkDragPlaceholder.ngOnDestroy",
"@angular/cdk/drag-drop"
],
[
"CdkDropListGroup",
"@angular/cdk/drag-drop"
],
[
"CdkDropListGroup.disabled",
"@angular/cdk/drag-drop"
],
[
"CdkDropListGroup.ngOnDestroy",
"@angular/cdk/drag-drop"
],
[
"CdkDragPreview",
"@angular/cdk/drag-drop"
@@ -1142,8 +1142,8 @@
"implements": [],
"source": {
"filePath": "/src/cdk/testing/selenium-webdriver/selenium-web-driver-harness-environment.ts",
"startLine": 35,
"endLine": 38
"startLine": 34,
"endLine": 37
}
},
{
@@ -1194,8 +1194,8 @@
"rawComment": "/** Waits for angular to be ready after the page load. */",
"source": {
"filePath": "/src/cdk/testing/selenium-webdriver/selenium-web-driver-harness-environment.ts",
"startLine": 65,
"endLine": 68
"startLine": 66,
"endLine": 69
}
},
{
@@ -1635,8 +1635,8 @@
"implements": [],
"source": {
"filePath": "/src/cdk/testing/selenium-webdriver/selenium-web-driver-harness-environment.ts",
"startLine": 71,
"endLine": 150
"startLine": 72,
"endLine": 151
}
}
],
+1 -1
View File
@@ -1,4 +1,4 @@
{
"branchName": "refs/heads/21.2.x",
"sha": "8e9555870edb3275b35d299613ef3cf9d3bfb73a"
"sha": "a8aca91bb6d490f66b6bdc873e3e350b9a1addad"
}
+2 -2
View File
@@ -109,7 +109,7 @@
"aliases": [
"s"
],
"description": "Include the styles for the root component directly within the `app.component.ts` file. Only CSS styles can be included inline. By default, a separate stylesheet file (e.g., `app.component.css`) is created."
"description": "Include the styles for the root component directly within the `app.ts` file. Only CSS styles can be included inline. By default, a separate stylesheet file (e.g., `app.css`) is created."
},
{
"name": "inline-template",
@@ -117,7 +117,7 @@
"aliases": [
"t"
],
"description": "Include the HTML template for the root component directly within the `app.component.ts` file. By default, a separate template file (e.g., `app.component.html`) is created."
"description": "Include the HTML template for the root component directly within the `app.ts` file. By default, a separate template file (e.g., `app.html`) is created."
},
{
"name": "minimal",
+2 -2
View File
@@ -91,7 +91,7 @@
"aliases": [
"s"
],
"description": "Include the styles for the initial application's root component directly within the `app.component.ts` file. By default, a separate stylesheet file (e.g., `app.component.css`) is created."
"description": "Include the styles for the initial application's root component directly within the `app.ts` file. By default, a separate stylesheet file (e.g., `app.css`) is created."
},
{
"name": "inline-template",
@@ -99,7 +99,7 @@
"aliases": [
"t"
],
"description": "Include the HTML template for the initial application's root component directly within the `app.component.ts` file. By default, a separate template file (e.g., `app.component.html`) is created."
"description": "Include the HTML template for the initial application's root component directly within the `app.ts` file. By default, a separate template file (e.g., `app.html`) is created."
},
{
"name": "interactive",

Some files were not shown because too many files have changed in this diff Show More