Compare commits

...

108 Commits

Author SHA1 Message Date
Kristiyan Kostadinov 1c27fa982c release: cut the v20.2.1 release 2025-08-21 12:52:59 +02:00
Matthieu Riegler a28672fb70 fix(compiler): Keep paraenthesis in Nullish + Boolean expression. (#63292)
Ts 5.9 introduced a regression coming from 5.8 when parenthesis aren't generated for expressions like (`(a ?? b) && c`).
This fix works around this explicitly specifying that we want to keep those parenthesis that we're aware of in this specific case;

This change can be reverted if the root issue (https://github.com/microsoft/TypeScript/issues/61369) is fixed. (but let's keep the tests in any case for the coverage)

fixes #63287

PR Close #63292
2025-08-21 12:15:52 +02:00
Angular Robot 65c5a734e2 build: update @angular/ng-dev digest to c93dfc8 (#63290)
See associated pull request for more information.

PR Close #63290
2025-08-20 16:16:17 +00:00
Joey Perrott 9bdb4fe8cc build: reenable firefox tests for devtools (#63288)
Reenable firefox tests for devtools as the spaces issues with path names is addressed post v7 of bazel

PR Close #63288
2025-08-20 16:08:22 +00:00
Alan Agius 11c638557b build: enforce frozen lockfile mode (#63260)
This commit adds `lockfile_mode=error` to the `.bazelrc` file. This change ensures that any future builds will fail if the lock file is not up-to-date with the `BUILD.bazel` file, preventing inconsistencies and encouraging developers to commit updated lock files.

PR Close #63260
2025-08-20 16:00:06 +00:00
Angular Robot a6130e076a build: update cross-repo angular dependencies (#63286)
See associated pull request for more information.

PR Close #63286
2025-08-20 15:47:25 +00:00
Devin Chasanoff 906bce0877 docs: add ai design patterns to adev/ai (#63095)
PR Close #63095
2025-08-20 15:43:36 +00:00
Angular Robot a827f02746 build: update cross-repo angular dependencies (#63285)
See associated pull request for more information.

PR Close #63285
2025-08-20 15:16:58 +00:00
Matthieu Riegler eb0183009b docs: remove IsolatedShadowDom from the 20.2 release (#63281)
The change has been reverted by #63142

PR Close #63281
2025-08-20 13:05:12 +00:00
Jessica Janiuk 9e172e0280 release: cut the v20.2.0 release 2025-08-20 14:29:27 +02:00
Kristiyan Kostadinov 878b99a1c6 fix(compiler-cli): account for expression with type arguments during HMR extraction (#63261)
Fixes that the HMR extraction logic didn't accoubnt for expressions with type arguments (e.g. `viewChild('foo', {read: TemplateRef<unknown>})`).

Fixes #63240.

PR Close #63261
2025-08-20 11:31:45 +00:00
Angular Robot 9655ea7f5c build: update dependency playwright-core to v1.55.0 (#63273)
See associated pull request for more information.

PR Close #63273
2025-08-20 11:14:53 +00:00
Angular Robot d76a911669 build: update all non-major dependencies (#63266)
See associated pull request for more information.

PR Close #63266
2025-08-20 10:06:50 +00:00
ivanwonder 591c7e2ec8 fix(language-service): Support to resolve the re-export component. (#62585)
In the context of TypeScript (TS), a re-exported symbol is considered a distinct symbol.
This means that a developer can choose to import either the re-exported symbol or
the original symbol. However, in the context of Angular, the re-exported symbol
is treated as the same component because it uses the same selector.

This pull request will utilize the most recent re-export component file to
resolve the module specifier.

PR Close #62585
2025-08-20 09:39:56 +00:00
Matthieu Riegler 81dc006772 docs: update NG_VALIDATORS examples to use forwardRef (#63247)
PR Close #63247
2025-08-20 09:27:21 +00:00
Matthieu Riegler c0eb0cb7a5 docs(docs-infra): remove temporary shiki dts (#63253)
The tooling now supports reading `d.mts` typing files

PR Close #63253
2025-08-20 09:26:18 +00:00
Angular Robot 416878bb7c build: update cross-repo angular dependencies (#63265)
See associated pull request for more information.

PR Close #63265
2025-08-20 09:06:56 +00:00
Matthieu Riegler fceb19128d docs: rewording heading for define option (#63009)
This is an attemp to improve search results

PR Close #63009
2025-08-20 09:04:59 +00:00
Jessica Janiuk f9d73cc687 fix(core): handle cases where classes added have no animations (#63242)
In the case that someone wants to disable animations via selector specificity, for example by adding an `.animate-disabled` class to a parent node, we need to make sure the animate instructions don't misbehave. Now we detect if animations exist in the provided classes and react accordingly.

fixes: #63161

PR Close #63242
2025-08-20 08:59:03 +00:00
tjshiu 5ceb1167fb docs: remove redundant Angular docs link in tailwind guide (#63205)
The Tailwind CSS guide already resides within the Angular documentation, making a link to the Angular documentation redundant. This commit removes the unnecessary link.

PR Close #63205
2025-08-20 08:30:36 +00:00
tjshiu 6b475eb86c docs: update tailwind guide and navigation (#63205)
PR Close #63205
2025-08-20 08:30:36 +00:00
tjshiu 9eac011bd0 docs: add guide for using Tailwind CSS (#63205)
Adds a new guide that explains how to set up and use Tailwind CSS in an Angular project. This guide covers installation, configuration, and provides a basic usage example.

PR Close #63205
2025-08-20 08:30:35 +00:00
Angular Robot 0ba671d4a0 build: update pnpm to v10.15.0 (#63259)
See associated pull request for more information.

PR Close #63259
2025-08-20 08:29:24 +00:00
Joey Perrott 38b9b79c29 build: move from using WORKSPACE to MODULE.bazel (#63249)
Update to use MODULE.bazel

PR Close #63249
2025-08-20 08:27:00 +00:00
cexbrayat 1edb83c019 docs: animationsEnabled defaults to false (#63262)
PR Close #63262
2025-08-20 08:25:26 +00:00
Angular Robot be0e8457b7 build: update all non-major dependencies (#63258)
See associated pull request for more information.

PR Close #63258
2025-08-20 08:23:17 +00:00
Angular Robot aff482913b build: update cross-repo angular dependencies (#63244)
See associated pull request for more information.

PR Close #63244
2025-08-19 15:59:55 +00:00
Matthieu Riegler 9374d57330 build: remove patch-package dependency (#63233)
This a patch backport of #63126

PR Close #63233
2025-08-19 12:34:06 +00:00
Julien Zapata Duque 52106fb71b docs: use correct closing quote in input and model import usage notes (#63237)
PR Close #63237
2025-08-19 12:33:24 +00:00
Angular Robot 58765137ab build: update all non-major dependencies (#63236)
See associated pull request for more information.

PR Close #63236
2025-08-19 11:14:57 +00:00
Shuaib Hasan Akib 8164b2298e refactor(core): update NG0303 error message (#63222)
Ensure consistency in error message wording by aligning the NG0303
error with other Angular error strings. This improves clarity and
maintains a uniform developer experience

PR Close #63222
2025-08-19 08:25:50 +00:00
Angular Robot 966d95df20 docs: update Angular CLI help (#63226)
Updated Angular CLI help contents.

PR Close #63226
2025-08-19 08:16:32 +00:00
Angular Robot fe27810a24 build: update github/codeql-action action to v3.29.10 (#63232)
See associated pull request for more information.

PR Close #63232
2025-08-19 08:06:26 +00:00
Angular Robot 4dfd38e127 build: update dependency preact to v10.27.1 (#63231)
See associated pull request for more information.

PR Close #63231
2025-08-19 08:05:37 +00:00
Avetik Harutyunyan a8c5bafd18 docs: fix typo in SSR section (#63224)
PR Close #63224
2025-08-19 08:01:28 +00:00
Matthieu Riegler d8254d95e9 docs: update version compatiblity. (#63223)
TS 5.9 support landed with #62939

PR Close #63223
2025-08-19 08:00:55 +00:00
Paweł Kawula 0c61fc6d43 docs: fixed mismatch between supported node versions (#63218)
node versions listed here https://angular.dev/reference/versions
and minimal listed in installation.md are different

PR Close #63218
2025-08-19 07:59:22 +00:00
Matthieu Riegler 0da66e6d43 docs(docs-infra): lift circular imports (#63186)
This commit also adds adev on the cyclic import check.

PR Close #63186
2025-08-19 07:58:47 +00:00
Jessica Janiuk 7b51728813 fix(compiler): fixes animation event host bindings not firing (#63217)
Host bindings for `(animate.enter)` and `(animate.leave)` were not firing properly. This fixes the compiler ingest to make sure they do fire.

fixes: #63199

PR Close #63217
2025-08-18 15:56:49 +00:00
AleksanderBodurri 5be80d33a3 fix(devtools): DOM traversal bug (#62719)
Previously, Angular devtools would mistakenly traverse the same DOM elements multiple times while doing traversal for the component tree explorer. This error case would occur when more than 1 Angular application root component was present on the same page and in distinct DOM branches.

Some example cases that did work previously:

```html
<app-root>
...
</app-root>
```

```html
<app-root>
...
<app-root-2></app-root-2>
...
</app-root>
```

An example of where it would enter the irregular behaviour

```html
<app-root>
...
</app-root>
<app-root-2>
...
</app-root-2>
```

Now, we properly ignore duplicate DOM paths when looking for application and non-application root component to begin the Angular DevTools component discovery logic.

PR Close #62719
2025-08-18 15:43:09 +00:00
Angular Robot 1e3748b893 build: update cross-repo angular dependencies (#63221)
See associated pull request for more information.

PR Close #63221
2025-08-18 15:21:53 +00:00
Joey Perrott 87523e90bc build: update the failure message with the correct command (#63219)
Update the failure message for compliance tests to use the correct command for updating the goldens

PR Close #63219
2025-08-18 15:08:57 +00:00
Jessica Janiuk bdc31675b7 fix(core): ensure animate events do not have duplicate elements (#63216)
This applies the same fix that fixed the class version to the event binding version. It prevents duplicate elements from being on screen when animations have been toggled too fast.

fixes: #63127

PR Close #63216
2025-08-18 12:42:17 +00:00
Paul Gschwendtner 726d6026b1 ci: mark myself as unavailable during OOO (#63214)
Marks myself as unavailable during OOO to not block reviews :)

PR Close #63214
2025-08-18 12:53:20 +02:00
Alan Agius 0eb550e297 fix(docs-infra): allow wrapping of types-and-default CLI options (#63211)
This change fixes an issue where long lists of enum values would display on a single line, running off the screen, especially on mobile devices.

PR Close #63211
2025-08-18 12:52:05 +02:00
Alan Agius 67cfe686b1 fix(docs-infra): add spacing between Alias and Value (#63211)
Prior to this change there was noi spacing between the Alias and Value

PR Close #63211
2025-08-18 12:52:05 +02:00
Alan Agius c7440dddef fix(docs-infra): display value type in CLI pages (#63211)
The value type was not being displayed when a value had an enum, which was misleading. This change ensures the value type is always shown, so users know whether to expect a single value or an array of values.

PR Close #63211
2025-08-18 12:52:04 +02:00
Angular Robot c714426963 build: lock file maintenance (#63210)
See associated pull request for more information.

PR Close #63210
2025-08-18 12:51:22 +02:00
Walter Breakell a1fe7091f9 docs: fix grammatical mistake in installation guide (#63202)
PR Close #63202
2025-08-18 12:50:02 +02:00
cexbrayat af63b800ec refactor(core): improve animation instruction robustness and maintainability (#63163)
This commit extracts helper functions to reduce code duplication across animation instructions and adds early return when animations are disabled.

PR Close #63163
2025-08-18 12:49:18 +02:00
Matthieu Riegler 9e828d5e54 docs(docs-infra): remove @adev/constant path (#63213)
PR Close #63213
2025-08-18 10:06:25 +02:00
Alan Agius 7a4bc79720 build: remove extra comma in JSON (#63212)
This fixes CI which is currently broken.

PR Close #63212
2025-08-18 09:44:02 +02:00
Matthieu Riegler 1d5ea07bca docs: revert remove of build-and-link (#63187)
This works again since angular/dev-infra#2922 landed

PR Close #63187
2025-08-18 09:14:37 +02:00
Angular Robot 2031359069 build: update cross-repo angular dependencies (#63191)
See associated pull request for more information.

PR Close #63191
2025-08-18 09:13:08 +02:00
Angular Robot 0838df97bf docs: update Angular CLI help (#63193)
Updated Angular CLI help contents.

PR Close #63193
2025-08-18 09:11:08 +02:00
Gerome Grignon dbd403031a docs(): remove double parenthesis (#63196)
PR Close #63196
2025-08-18 09:09:52 +02:00
Shuaib Hasan Akib 287d6c8fdd docs(docs-infra): add paths for constants and missing link (#63197)
PR Close #63197
2025-08-18 09:09:00 +02:00
Angular Robot 732aadf082 build: update all non-major dependencies (#63204)
See associated pull request for more information.

PR Close #63204
2025-08-18 09:07:28 +02:00
Shuaib Hasan Akib 2d8ac7d9ef docs(docs-infra): replace deprecated router method (#63183)
PR Close #63183
2025-08-15 13:50:58 +02:00
Angular Robot 28b8782266 build: update dependency @codemirror/language to v6.11.3 (#63185)
See associated pull request for more information.

PR Close #63185
2025-08-15 13:49:29 +02:00
Shuaib Hasan Akib d8ac27f94a docs(docs-infra): replace Input by signal one (#63169)
PR Close #63169
2025-08-15 13:42:41 +02:00
Cheng-Hsuan Tsai 81751465b4 docs(docs-infra): add dark mode to example preview (#63171)
PR Close #63171
2025-08-15 13:41:09 +02:00
cexbrayat de6b6413e4 docs: add --yes option to mcp commands (#63173)
This makes it consistent with the message output by the CLI in v20.2 (see https://github.com/angular/angular-cli/commit/8b4de57af1)

PR Close #63173
2025-08-15 12:32:29 +02:00
Angular Robot d4a380d7bd build: update all non-major dependencies (#63182)
See associated pull request for more information.

PR Close #63182
2025-08-15 12:31:55 +02:00
Angular Robot 124d44f130 build: update cross-repo angular dependencies (#63179)
See associated pull request for more information.

PR Close #63179
2025-08-15 11:41:02 +02:00
Kristiyan Kostadinov 19ed12c81e fix(compiler): error when ng-content fallback has translated children (#63156)
Fixes that the pipeline wasn't processing the fallback content of `ng-content` for i18n which resulted in a compiler error further down the line.

Fixes #63065.

PR Close #63156
2025-08-15 09:47:18 +02:00
Kristiyan Kostadinov 557e6fe6eb fix(compiler): incorrect source span for expression AST inside template attribute (#63175)
Similar fix as #63082, but for template attributes. The root cause is the same where we should be using `fullStart` instead of `start` in order to account for whitespaces being skipped.

Fixes #63157.

PR Close #63175
2025-08-15 09:44:36 +02:00
Alan Agius b7cefe0370 Revert "ci: redirect adev to index.csr.html (#63168)" (#63177)
This reverts commit 5129daed1b.

PR Close #63177
2025-08-15 09:43:15 +02:00
Matthieu Riegler 8b02aa0333 ci: redirect adev to index.csr.html (#63168)
The build doesn't produce an `index.html`

PR Close #63168
2025-08-14 21:15:48 +00:00
Angular Robot c68a099ded build: update all non-major dependencies (#63129)
See associated pull request for more information.

PR Close #63129
2025-08-14 22:08:30 +02:00
Charles Lyding dc36fa5200 docs: update MCP server documentation for 20.2 (#63141)
This commit updates the MCP server documentation with the following changes:

- Updates the description of the `ng mcp` command behavior.
- Adds a configuration example for the Gemini CLI.
- Adds a new section for command options, including `--read-only` and `--local-only`.
- Alphabetizes the IDE configuration sections for better readability.
- Alphabetizes the "Available Tools" table.

PR Close #63141
2025-08-14 22:07:56 +02:00
Angular Robot e607d4db2b build: update cross-repo angular dependencies (#63151)
See associated pull request for more information.

PR Close #63151
2025-08-14 22:05:17 +02:00
Angular Robot e159ab1ee3 docs: update Angular CLI help (#63160)
Updated Angular CLI help contents.

PR Close #63160
2025-08-14 22:04:05 +02:00
Shuaib Hasan Akib 24e7238c54 docs(docs-infra): enhance method name following the guideline (#63164)
PR Close #63164
2025-08-14 22:03:17 +02:00
Joey Perrott f863792923 build: run integration tests using remote execution (#63118)
With the change to size tracking integration test can now be executed on our RBE platform

PR Close #63118
2025-08-14 22:02:33 +02:00
Ben Hong 65cca30361 docs: add rendering strategies guide for router (#62859)
PR Close #62859
2025-08-14 22:01:58 +02:00
Matthieu Riegler 8747f9ad55 docs: fix edit links for block/element api entries (#62766)
PR Close #62766
2025-08-14 13:03:01 +02:00
Matthieu Riegler 3ecf8c7114 docs: update testing scenarios and remove imports. (#63076)
With standalone, `imports` are not necessary anymore when configuring the Testing module.

Also
fixes #58073

PR Close #63076
2025-08-14 13:02:18 +02:00
Joey Perrott a6a2e38e5c build: update to bazel 7.6.0 (#63096)
Update to later version of bazel

PR Close #63096
2025-08-14 13:01:32 +02:00
Angular Robot 2faed63fed build: update actions/checkout action to v5 (#63116)
See associated pull request for more information.

PR Close #63116
2025-08-14 13:00:27 +02:00
Andrew Scott 1cf4d34c37 release: cut the v20.2.0-rc.1 release 2025-08-13 13:27:08 -07:00
Angular Robot ced0357bf8 build: update cross-repo angular dependencies (#63137)
See associated pull request for more information.

PR Close #63137
2025-08-13 12:52:28 -07:00
Andrew Scott d9f0e6b27c Revert "feat(platform-browser): Add IsolatedShadowDom encapsulation method (#62723)" (#63142)
This reverts commit d24d5742db. A
legitimate issue was raised in the original commit
(see https://github.com/angular/angular/commit/d24d5742db694604b09d57a3503e8c32751c4836#commitcomment-163853393)

PR Close #63142
2025-08-13 11:12:59 -07:00
Jeremy Elbourn 767a280562 docs: add rxjs-interop section for rxResource (#63125)
This commit adds brief documentation for `rxResource` to the "Using
Angular with RxJS" guide. The only available documentation for
`rxResource` today is the API reference, which lacks any code examples.

PR Close #63125
2025-08-13 09:29:34 -07:00
cexbrayat 254b560138 docs: update best-practices (#63132)
This removes the common pitfall for if blocks in the best practices, as this is no longer true in Angular v20.2, see angular/angular@a409534

PR Close #63132
2025-08-13 09:20:32 -07:00
Angular Robot b0900ccee5 build: update github/codeql-action action to v3.29.9 (#63128)
See associated pull request for more information.

PR Close #63128
2025-08-13 09:19:57 -07:00
Alan Agius 0065ebb115 docs: add link to ai-config command (#63139)
This adds a link to the new command.

PR Close #63139
2025-08-13 09:14:18 -07:00
Jeremy Elbourn 0211668d20 docs: add topic for takeUntilDestroyed (#63122)
This was missing from the RxJS interop guide. I came across it while
cleaning up some Google-internal docs and realized I had nothing on adev
to which I could link.

PR Close #63122
2025-08-12 18:41:19 -07:00
Paul Gschwendtner ada3c37338 refactor(compiler-cli): ensure JIT transforms with queries work with closure property renaming (#63123)
This map for the JIT transforms accidentally is property-renamed,
breaking the lookups below. This commit fixes this.

PR Close #63123
2025-08-12 13:24:10 -07:00
Jeremy Elbourn 4635095c01 fix(docs-infra): put content in <main> element (#63121)
This fix updates the adev `DocViewer` component to support rendering with the `main[docsViewer` selector so that the primary content for the page is inside of a `<main>` element (without introducing an extra DOM element).

PR Close #63121
2025-08-12 11:05:16 -07:00
Angular Robot b13c3fc2eb build: update actions/checkout action to v5 (#63115)
See associated pull request for more information.

PR Close #63115
2025-08-12 11:00:49 -07:00
ivanwonder c81e345e72 feat(language-service): support auto-import for attribute completions (#62797)
Add logic to provide code actions for auto-importing directives that
are out of scope.

PR Close #62797
2025-08-12 10:57:09 -07:00
Angular Robot 31df4d2fd1 build: update cross-repo angular dependencies (#63088)
See associated pull request for more information.

PR Close #63088
2025-08-12 09:53:15 -07:00
Matthieu Riegler 0e3465dfd9 docs: add missing supported != operator (#63108)
fixes 63103

PR Close #63108
2025-08-12 09:39:08 -07:00
Alan Agius 6fb2b71489 build: use link: instead of file: (#63111)
When using `file:` renovate updates fails due to ` ERR_PNPM_LINKED_PKG_DIR_NOT_FOUND ` this is due to a different behaviour between `link:` amd `file:`. `link:` however will not fail when the directory does not exist.

PR Close #63111
2025-08-12 09:37:54 -07:00
Angular Robot 5105477490 build: update pnpm to v10 (#63117)
See associated pull request for more information.

PR Close #63117
2025-08-12 09:36:28 -07:00
Alan Agius 856dd50e64 ci: correctly configure ignored filenames (#63105)
Previously, the path did not match a file.

PR Close #63105
2025-08-12 10:02:00 +02:00
Alan Agius 1a16fb7aa2 build: resolve pnpm workspace dependency on compiler-cli (#63105)
The `pnpm install` command was failing for the `packages/core/test/bundling` project with the error:
`ERR_PNPM_NO_MATCHING_VERSION No matching version found for @angular/compiler-cli@0.0.0-PLACEHOLDER`

This happenes only in renovate updates.

PR Close #63105
2025-08-12 10:02:00 +02:00
Alan Agius 0e1bd1b404 build: fix ERR_PNPM_LINKED_PKG_DIR_NOT_FOUND for typings tests (#63105)
During `pnpm install` in a monorepo setup, the `packages/zone.js/test/typings` project would fail with the error: `ERR_PNPM_LINKED_PKG_DIR_NOT_FOUND: Could not install from "/.../node_modules/typescript" as it does not exist.`

PR Close #63105
2025-08-12 10:02:00 +02:00
Alan Agius 4ab709460a build: remove redundant yarn.lock files (#63105)
These are now managed by pnpm.

PR Close #63105
2025-08-12 10:02:00 +02:00
Matthieu Riegler b38c43bacc refactor(zone.js): remove unused jasmine globalerror monkey patching. (#63077)
This is for testing purposes for now. See discussion on the related issue.

fixes #63072

PR Close #63077
2025-08-11 16:41:12 -07:00
Angular Robot 88d48de46e build: update scorecard action dependencies (#63089)
See associated pull request for more information.

PR Close #63089
2025-08-11 16:38:13 -07:00
Matthieu Riegler af247cacb6 refactor(core): remove temporary resource setter function. (#63097)
Now that G3 has been fully migrated to the new throwing behavior, we don't need that setter anymore.

PR Close #63097
2025-08-11 15:43:48 -07:00
Matthieu Riegler 499fa8fa88 docs: remove router testing from the testing scenarios guide (#63078)
This commit also adds the router testing guide to the testing section

PR Close #63078
2025-08-11 12:15:41 -07:00
Kristiyan Kostadinov 79b91593c9 fix(compiler): incorrect spans for AST inside input value with leading space (#63082)
When parsing expressions inside a bound attribute, we offset all of its spans by an `absoluteOffset` in order to get the right spans in the source file. The offset was incorrect when parsing an attribute with leading spaces during the construction of the Ivy AST, because of the combination of:
1. We were setting the offset by looking at `valueSpan.start`.
2. The Ivy parser sets `leadingTriviaChars: [' ', '\n']` which means that spaces and new lines will be ignored in the `sourceSpan.start`.

These changes resolve the issue by using `valueSpan.fullStart` which includes the leading spaces.

Fixes #63069.

PR Close #63082
2025-08-11 11:57:08 -07:00
Alan Agius 51801612c3 ci: several fixes for renovate (#63083)
This commit contains several fixes for renovate to work properly with `pnpm`

PR Close #63083
2025-08-11 11:03:31 -07:00
Joey Perrott a92dea5b99 build: update to the latest version of devinfra and rename npm2 workspace (#63093)
Rename the npm2 workspace to npm and use the latest version of devinfra which drops rules_nodejs

PR Close #63093
2025-08-11 10:35:34 -07:00
Kristiyan Kostadinov 1156d7d786 release: cut the v20.2.0-rc.0 release 2025-08-11 10:41:09 +02:00
289 changed files with 16812 additions and 10944 deletions
+3
View File
@@ -12,6 +12,9 @@ common --@aspect_rules_ts//ts:default_to_tsc_transpiler
# Needed as otherwise `env` of TS actions would be ignored.
common --incompatible_merge_fixed_and_default_shell_env
# Frozen lockfile
common --lockfile_mode=error
###############################
# Filesystem interactions #
###############################
+1 -1
View File
@@ -1 +1 @@
6.5.0
7.6.1
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -5,9 +5,9 @@ runs:
using: 'composite'
steps:
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Saucelabs Variables
uses: angular/dev-infra/github-actions/saucelabs@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/saucelabs@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Starting Saucelabs tunnel service
shell: bash
run: ./tools/saucelabs/sauce-service.sh run &
+4 -4
View File
@@ -21,16 +21,16 @@ 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@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Build adev to ensure it continues to work
run: pnpm bazel build //adev:build --full_build_adev --config=release
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
workflow-artifact-name: 'adev-preview'
pull-number: '${{github.event.pull_request.number}}'
+2 -2
View File
@@ -29,7 +29,7 @@ jobs:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
with:
token: '${{secrets.GITHUB_TOKEN}}'
@@ -40,7 +40,7 @@ jobs:
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}}
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
github-token: '${{secrets.GITHUB_TOKEN}}'
workflow-artifact-name: 'adev-preview'
@@ -13,9 +13,9 @@ jobs:
assistant_to_the_branch_manager:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- uses: angular/dev-infra/github-actions/branch-manager@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
- uses: angular/dev-infra/github-actions/branch-manager@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
+2 -2
View File
@@ -28,7 +28,7 @@ jobs:
- uses: alessbell/pull-request-comment-branch@aad01d65d6982b8eacabed5e9a684cd8ceb98da6 # v1.1
id: comment-branch
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
# Specify repository as the PR branch might be from a fork.
repository: ${{steps.comment-branch.outputs.head_owner}}/${{steps.comment-branch.outputs.head_repo}}
@@ -38,7 +38,7 @@ jobs:
- run: pnpm install --frozen-lockfile
- uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
- uses: angular/dev-infra/github-actions/bazel/configure-remote@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
bazelrc: ./.bazelrc.user
+22 -22
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@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
cache-node-modules: true
- name: Install node modules
@@ -41,13 +41,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
@@ -68,13 +68,13 @@ jobs:
runs-on: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
@@ -86,13 +86,13 @@ jobs:
runs-on: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
@@ -105,11 +105,11 @@ jobs:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
@@ -124,13 +124,13 @@ jobs:
labels: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Install node modules
run: pnpm install --frozen-lockfile
- run: echo "https://${{secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN}}:@github.com" > ${HOME}/.git_credentials
@@ -142,7 +142,7 @@ jobs:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
cache-node-modules: true
node-module-directories: |
@@ -150,9 +150,9 @@ jobs:
./packages/zone.js/node_modules
./packages/zone.js/test/typings/node_modules
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
@@ -204,11 +204,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Build adev to ensure it continues to work
+4 -4
View File
@@ -12,14 +12,14 @@ jobs:
labels:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: angular/dev-infra/github-actions/pull-request-labeling@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: angular/dev-infra/github-actions/pull-request-labeling@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
post_approval_changes:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: angular/dev-infra/github-actions/post-approval-changes@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: angular/dev-infra/github-actions/post-approval-changes@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
+2 -2
View File
@@ -13,8 +13,8 @@ jobs:
statuses: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: angular/dev-infra/github-actions/google-internal-tests@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: angular/dev-infra/github-actions/google-internal-tests@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
run-tests-guide-url: http://go/angular-g3sync-start
github-token: ${{ secrets.GITHUB_TOKEN }}
+4 -4
View File
@@ -13,17 +13,17 @@ jobs:
JOBS: 2
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
cache-node-modules: true
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Saucelabs Variables
uses: angular/dev-infra/github-actions/saucelabs@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/saucelabs@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- 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@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
- uses: angular/dev-infra/github-actions/unified-status-check@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
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@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- 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@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- 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
+17 -17
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@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
cache-node-modules: true
- name: Install node modules
@@ -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@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/linting/licenses@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
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@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Run unit tests
@@ -72,13 +72,13 @@ jobs:
runs-on: ubuntu-latest-8core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Run CI tests for framework
@@ -98,13 +98,13 @@ jobs:
runs-on: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Run integration CI tests for framework
@@ -115,11 +115,11 @@ jobs:
labels: ubuntu-latest-8core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Run tests
@@ -132,7 +132,7 @@ jobs:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
with:
cache-node-modules: true
node-module-directories: |
@@ -140,9 +140,9 @@ jobs:
./packages/zone.js/node_modules
./packages/zone.js/test/typings/node_modules
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c
- name: Install node modules
run: pnpm install --frozen-lockfile
- run: |
+2 -2
View File
@@ -25,7 +25,7 @@ jobs:
steps:
- name: 'Checkout code'
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
@@ -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@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
uses: github/codeql-action/upload-sarif@96f518a34f7a870018057716cc4d7a5c014bd61c # v3.29.10
with:
sarif_file: results.sarif
@@ -24,7 +24,7 @@ jobs:
steps:
- name: Checkout the repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
# Setting `persist-credentials: false` prevents the github-action account from being the
# account that is attempted to be used for authentication, instead the remote is set to
+2 -2
View File
@@ -56,8 +56,8 @@
version: 3
# availability:
# users_unavailable: ['atscott']
availability:
users_unavailable: ['devversion']
# Meta field that goes unused by PullApprove to allow for defining aliases to be
# used throughout the config.
+1 -1
View File
@@ -1,5 +1,5 @@
load("@aspect_rules_js//js:defs.bzl", "js_library")
load("@npm2//:defs.bzl", "npm_link_all_packages")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//:yarn.bzl", "YARN_PATH")
load("//tools:defaults2.bzl", "copy_to_bin", "js_binary")
+60 -152
View File
@@ -1,52 +1,57 @@
<a name="20.2.0-next.6"></a>
# 20.2.0-next.6 (2025-08-07)
<a name="20.2.1"></a>
# 20.2.1 (2025-08-21)
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [a28672fb70](https://github.com/angular/angular/commit/a28672fb7017cc62e42829c5910c3b39373d7913) | fix | Keep paraenthesis in Nullish + Boolean expression. ([#63292](https://github.com/angular/angular/pull/63292)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="20.2.0"></a>
# 20.2.0 (2025-08-20)
## Deprecations
### animations
- @angular/animations
### core
- @angular/animations
### router
- The Router.getCurrentNavigation method is deprecated. Use the Router.currentNavigation signal instead.
- The Router.getCurrentNavigation method is deprecated. Use the Router.currentNavigation signal instead.
### animations
| Commit | Type | Description |
| -- | -- | -- |
| [9766116cea](https://github.com/angular/angular/commit/9766116cea69607d80144251a599f1cc1b12e02c) | refactor | deprecate the animations package ([#62795](https://github.com/angular/angular/pull/62795)) |
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [7767aa640c](https://github.com/angular/angular/commit/7767aa640c542f5058df9322f2bbe974fa8d3c81) | fix | allow more characters in square-bracketed attribute names ([#62742](https://github.com/angular/angular/pull/62742)) |
| [7b51728813](https://github.com/angular/angular/commit/7b517288139aec166e5e5b60e84b1e22e3d6b70f) | fix | fixes animation event host bindings not firing ([#63217](https://github.com/angular/angular/pull/63217)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [5abfe4a899](https://github.com/angular/angular/commit/5abfe4a8999e42ad44e6f1d4414f241094bb8fdb) | feat | add diagnostic for uninvoked functions in text interpolation ([#59191](https://github.com/angular/angular/pull/59191)) |
| [c4917074f1](https://github.com/angular/angular/commit/c4917074f1e278ea24948a8810b3d4f306765174) | fix | display proper function in NG8117 message ([#62842](https://github.com/angular/angular/pull/62842)) |
| [812463c563](https://github.com/angular/angular/commit/812463c5636effe5bd5ba5c7c7fc65c3cc08d047) | fix | Ignore diagnostics on ngTemplateContextGuard lines in TCB ([#63054](https://github.com/angular/angular/pull/63054)) |
| [45b030b5ce](https://github.com/angular/angular/commit/45b030b5ce1e116a88fe1c2fe133f654fb1f66c5) | fix | prevent dom event assertion in TCB generation on older angular versions ([#63053](https://github.com/angular/angular/pull/63053)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="20.2.0-next.5"></a>
# 20.2.0-next.5 (2025-08-06)
## Deprecations
### router
- The Router.getCurrentNavigation method is deprecated. Use the Router.currentNavigation signal instead.
### platform-browser
| Commit | Type | Description |
| -- | -- | -- |
| [d24d5742db](https://github.com/angular/angular/commit/d24d5742db694604b09d57a3503e8c32751c4836) | feat | Add IsolatedShadowDom encapsulation method ([#62723](https://github.com/angular/angular/pull/62723)) |
### router
| Commit | Type | Description |
| -- | -- | -- |
| [687c374826](https://github.com/angular/angular/commit/687c374826c5e9ea91839c20f0df815ce085c583) | feat | add a currentNavigation signal to the Router service. ([#63011](https://github.com/angular/angular/pull/63011)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="20.1.6"></a>
# 20.1.6 (2025-08-06)
<!-- CHANGELOG SPLIT MARKER -->
<a name="20.2.0-next.4"></a>
# 20.2.0-next.4 (2025-08-06)
## Deprecations
### router
- The Router.getCurrentNavigation method is deprecated. Use the Router.currentNavigation signal instead.
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [fb1fc823c4](https://github.com/angular/angular/commit/fb1fc823c47ef34347ba758dd73cc997c7f0c009) | fix | correctly type check host listeners to own outputs ([#62965](https://github.com/angular/angular/pull/62965)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [6b1f4b9e8b](https://github.com/angular/angular/commit/6b1f4b9e8bb981377e271e6af0d9768ff7f765e9) | feat | add enter and leave animation instructions ([#62682](https://github.com/angular/angular/pull/62682)) |
| [cec91c0035](https://github.com/angular/angular/commit/cec91c00356ee3974c39c9471b243a2a16149f5b) | feat | add option to infer the tag names of components in tests ([#62283](https://github.com/angular/angular/pull/62283)) |
| [141bb75ff2](https://github.com/angular/angular/commit/141bb75ff241425a93ce5b60b56a4247e67d7648) | feat | Promote zoneless to stable ([#62699](https://github.com/angular/angular/pull/62699)) |
| [4138aca91f](https://github.com/angular/angular/commit/4138aca91fe828f0cfbd779d0c456cdea7703bdc) | feat | render ARIA property bindings as attributes ([#62630](https://github.com/angular/angular/pull/62630)) |
| [a409534d6c](https://github.com/angular/angular/commit/a409534d6c3d7cb4472afffd6b17df8c25e34106) | feat | support `as` aliases on `else if` blocks ([#63047](https://github.com/angular/angular/pull/63047)) |
| [745ea44394](https://github.com/angular/angular/commit/745ea4439465494ab5b7002dd1fa320cd32220fb) | feat | support TypeScript 5.9 ([#62541](https://github.com/angular/angular/pull/62541)) |
| [593cc8a368](https://github.com/angular/angular/commit/593cc8a3684dfb163bfffa265c5efb3bc7efacd1) | fix | checks if body exists before continuing ([#62768](https://github.com/angular/angular/pull/62768)) |
| [bdc31675b7](https://github.com/angular/angular/commit/bdc31675b7e5f37d2b312c766fe4963305620bdf) | fix | ensure animate events do not have duplicate elements ([#63216](https://github.com/angular/angular/pull/63216)) |
| [de3a0c5cf3](https://github.com/angular/angular/commit/de3a0c5cf3f87782fa63d30edf6ac05eb6be9fac) | fix | Fix `animate.enter` class removal when composing classes ([#62981](https://github.com/angular/angular/pull/62981)) |
| [6597ac0af7](https://github.com/angular/angular/commit/6597ac0af78ac2224ec2f9a37283b53aee11abe1) | fix | fix support for space separated strings in leave animations ([#62979](https://github.com/angular/angular/pull/62979)) |
| [ebd622b344](https://github.com/angular/angular/commit/ebd622b3449789b72efc8295244ca924a299e7c1) | fix | fixes empty animations when recalculating styles ([#63007](https://github.com/angular/angular/pull/63007)) |
| [455b147488](https://github.com/angular/angular/commit/455b147488dc0a064c0ca13a96a4df3c3ed01152) | fix | fixes timing issues with enter animations ([#62925](https://github.com/angular/angular/pull/62925)) |
| [648bbb097e](https://github.com/angular/angular/commit/648bbb097e858fd1276b6ee88c82b674341e6163) | fix | properly recognize failed `fetch` responses when loading external resources in JIT ([#62992](https://github.com/angular/angular/pull/62992)) |
| [f9d73cc687](https://github.com/angular/angular/commit/f9d73cc6877d516da4ab4704c21bb19164123fa1) | fix | handle cases where classes added have no animations ([#63242](https://github.com/angular/angular/pull/63242)) |
| [6a1184600c](https://github.com/angular/angular/commit/6a1184600ce0fc7a3f338d6766612e9510ef5518) | fix | prevents duplicate nodes when `@if` toggles with leave animations ([#63048](https://github.com/angular/angular/pull/63048)) |
| [063b5e166f](https://github.com/angular/angular/commit/063b5e166f66bce1abd06c258242212009e76cca) | fix | switch check to documentElement with chaining ([#62773](https://github.com/angular/angular/pull/62773)) |
| [320de4e96d](https://github.com/angular/angular/commit/320de4e96d250cad1ce2c9f8c0fa2022da53b734) | refactor | deprecate animations field on component interface ([#62895](https://github.com/angular/angular/pull/62895)) |
### forms
| Commit | Type | Description |
| -- | -- | -- |
@@ -54,11 +59,16 @@
### http
| Commit | Type | Description |
| -- | -- | -- |
| [e5d6fb5825](https://github.com/angular/angular/commit/e5d6fb5825d5e1b76d73d5c1c64c9986cfb02874) | fix | Reset headers, progress, and statusCode when using `set()` in `HttpResource` ([#62873](https://github.com/angular/angular/pull/62873)) |
### migrations
| [0984b30388](https://github.com/angular/angular/commit/0984b30388ef51dfad66f1228f665b89b73ef3fb) | feat | Add redirected property to HttpResponse and HttpErrorResponse ([#62675](https://github.com/angular/angular/pull/62675)) |
| [be811fee79](https://github.com/angular/angular/commit/be811fee7925fb482567fa7cd9d485ac28acdade) | feat | add referrer & integrity support for fetch requests in httpResource ([#62461](https://github.com/angular/angular/pull/62461)) |
| [1cf9d9064c](https://github.com/angular/angular/commit/1cf9d9064c15c00071ece3b78c8019035a6db6ce) | feat | Add support for fetch referrer & integrity options in HttpClient ([#62417](https://github.com/angular/angular/pull/62417)) |
| [1408baff45](https://github.com/angular/angular/commit/1408baff453e636da05838fa17c6e4abd86c4b72) | fix | Add missing timeout and transferCache options to `HttpClient` ([#62586](https://github.com/angular/angular/pull/62586)) |
### language-service
| Commit | Type | Description |
| -- | -- | -- |
| [b1514d512e](https://github.com/angular/angular/commit/b1514d512e041674d1ebbac88eb2d9f6a0f2cf5e) | fix | incorrect filtering in inject migration ([#62913](https://github.com/angular/angular/pull/62913)) |
| [c81e345e72](https://github.com/angular/angular/commit/c81e345e726b5b281621159c789e6d80a9f328e2) | feat | support auto-import for attribute completions ([#62797](https://github.com/angular/angular/pull/62797)) |
| [d64dd27a02](https://github.com/angular/angular/commit/d64dd27a02630b631bc9890d7292d4683493cb65) | feat | support to report the deprecated API in the template ([#62054](https://github.com/angular/angular/pull/62054)) |
| [591c7e2ec8](https://github.com/angular/angular/commit/591c7e2ec82c6669ffa6e0011b8a0a4fc12e9c3a) | fix | Support to resolve the re-export component. ([#62585](https://github.com/angular/angular/pull/62585)) |
### platform-browser
| Commit | Type | Description |
| -- | -- | -- |
@@ -67,11 +77,22 @@
| Commit | Type | Description |
| -- | -- | -- |
| [d00b3fed58](https://github.com/angular/angular/commit/d00b3fed58496369d9f3a1ac0d74416a586be78b) | feat | add a `currentNavigation` signal to the `Router` service. ([#62971](https://github.com/angular/angular/pull/62971)) |
| [687c374826](https://github.com/angular/angular/commit/687c374826c5e9ea91839c20f0df815ce085c583) | feat | add a currentNavigation signal to the Router service. ([#63011](https://github.com/angular/angular/pull/63011)) |
| [9c45c322d1](https://github.com/angular/angular/commit/9c45c322d1ac3b05c916b7c956263066fb9be47f) | fix | ensure preloaded components are properly activated ([#62502](https://github.com/angular/angular/pull/62502)) |
### service-worker
| Commit | Type | Description |
| -- | -- | -- |
| [8255e0cf15](https://github.com/angular/angular/commit/8255e0cf15353e9eee339ae01851e32c0e5e174d) | feat | add messageerror event handling and logging ([#62834](https://github.com/angular/angular/pull/62834)) |
| [5220b51e75](https://github.com/angular/angular/commit/5220b51e75e672ff41c90f4798289961973df8e0) | feat | Adds for type in provideServiceWorker ([#62831](https://github.com/angular/angular/pull/62831)) |
| [4ac6171b09](https://github.com/angular/angular/commit/4ac6171b09e449c619e0588c366861f8f3bb59be) | feat | Adds support for updateViaCache in provideServiceWorker ([#62721](https://github.com/angular/angular/pull/62721)) |
| [b65c3d5e19](https://github.com/angular/angular/commit/b65c3d5e195267dd90b2826d4615ced1328b1709) | feat | Improves storage full detection in data caching ([#62737](https://github.com/angular/angular/pull/62737)) |
| [3b214d2040](https://github.com/angular/angular/commit/3b214d20403160ab73e65dca0352545efd577c31) | feat | Logs unhandled promise rejections in service worker ([#63059](https://github.com/angular/angular/pull/63059)) |
| [6d011687ec](https://github.com/angular/angular/commit/6d011687ec1fa2b8f0211379bb98adc8e02f4e9a) | feat | notify clients about version failures ([#62718](https://github.com/angular/angular/pull/62718)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="20.1.6"></a>
# 20.1.6 (2025-08-06)
<!-- CHANGELOG SPLIT MARKER -->
@@ -96,44 +117,6 @@
<!-- CHANGELOG SPLIT MARKER -->
<a name="20.2.0-next.3"></a>
# 20.2.0-next.3 (2025-07-31)
## Deprecations
### animations
- @angular/animations
### core
- @angular/animations
### animations
| Commit | Type | Description |
| -- | -- | -- |
| [9766116cea](https://github.com/angular/angular/commit/9766116cea69607d80144251a599f1cc1b12e02c) | refactor | deprecate the animations package ([#62795](https://github.com/angular/angular/pull/62795)) |
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [5b25d93f27](https://github.com/angular/angular/commit/5b25d93f27b259098ed968a8a355e9c16867b37b) | fix | exclude more safe reads expression from 2way-binding ([#62852](https://github.com/angular/angular/pull/62852)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [c4917074f1](https://github.com/angular/angular/commit/c4917074f1e278ea24948a8810b3d4f306765174) | fix | display proper function in NG8117 message ([#62842](https://github.com/angular/angular/pull/62842)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [92c2d2a006](https://github.com/angular/angular/commit/92c2d2a0065a1d5a7e87fb54a4cd454f21bd8ab9) | fix | update symbols for new signals api ([#62284](https://github.com/angular/angular/pull/62284)) |
| [320de4e96d](https://github.com/angular/angular/commit/320de4e96d250cad1ce2c9f8c0fa2022da53b734) | refactor | deprecate animations field on component interface ([#62895](https://github.com/angular/angular/pull/62895)) |
### http
| Commit | Type | Description |
| -- | -- | -- |
| [0984b30388](https://github.com/angular/angular/commit/0984b30388ef51dfad66f1228f665b89b73ef3fb) | feat | Add redirected property to HttpResponse and HttpErrorResponse ([#62675](https://github.com/angular/angular/pull/62675)) |
| [245494ad29](https://github.com/angular/angular/commit/245494ad292ea0b61ad7e314c8913afdcd8ca837) | fix | add missing http options allowed in fetch API ([#62881](https://github.com/angular/angular/pull/62881)) |
| [1b73c23597](https://github.com/angular/angular/commit/1b73c235977f37ca7fbc5f4be8b194054632352b) | fix | propagate plain errors when parsing fails ([#62765](https://github.com/angular/angular/pull/62765)) |
### service-worker
| Commit | Type | Description |
| -- | -- | -- |
| [b65c3d5e19](https://github.com/angular/angular/commit/b65c3d5e195267dd90b2826d4615ced1328b1709) | feat | Improves storage full detection in data caching ([#62737](https://github.com/angular/angular/pull/62737)) |
| [6d011687ec](https://github.com/angular/angular/commit/6d011687ec1fa2b8f0211379bb98adc8e02f4e9a) | feat | notify clients about version failures ([#62718](https://github.com/angular/angular/pull/62718)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="20.1.4"></a>
# 20.1.4 (2025-07-31)
### compiler
@@ -152,37 +135,6 @@
<!-- CHANGELOG SPLIT MARKER -->
<a name="20.2.0-next.2"></a>
# 20.2.0-next.2 (2025-07-23)
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [7767aa640c](https://github.com/angular/angular/commit/7767aa640c542f5058df9322f2bbe974fa8d3c81) | fix | allow more characters in square-bracketed attribute names ([#62742](https://github.com/angular/angular/pull/62742)) |
| [3171d01452](https://github.com/angular/angular/commit/3171d01452444721dbea53d1d1ca758f38d083a5) | fix | fix detection of directive deps in JIT ([#62666](https://github.com/angular/angular/pull/62666)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [5abfe4a899](https://github.com/angular/angular/commit/5abfe4a8999e42ad44e6f1d4414f241094bb8fdb) | feat | add diagnostic for uninvoked functions in text interpolation ([#59191](https://github.com/angular/angular/pull/59191)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [6b1f4b9e8b](https://github.com/angular/angular/commit/6b1f4b9e8bb981377e271e6af0d9768ff7f765e9) | feat | add enter and leave animation instructions ([#62682](https://github.com/angular/angular/pull/62682)) |
| [cec91c0035](https://github.com/angular/angular/commit/cec91c00356ee3974c39c9471b243a2a16149f5b) | feat | add option to infer the tag names of components in tests ([#62283](https://github.com/angular/angular/pull/62283)) |
| [4138aca91f](https://github.com/angular/angular/commit/4138aca91fe828f0cfbd779d0c456cdea7703bdc) | feat | render ARIA property bindings as attributes ([#62630](https://github.com/angular/angular/pull/62630)) |
| [593cc8a368](https://github.com/angular/angular/commit/593cc8a3684dfb163bfffa265c5efb3bc7efacd1) | fix | checks if body exists before continuing ([#62768](https://github.com/angular/angular/pull/62768)) |
| [b8e415a717](https://github.com/angular/angular/commit/b8e415a717fd3747c7bab3f6ea652874082a19bb) | fix | fix change tracking for Resource#hasValue ([#62595](https://github.com/angular/angular/pull/62595)) |
| [063b5e166f](https://github.com/angular/angular/commit/063b5e166f66bce1abd06c258242212009e76cca) | fix | switch check to documentElement with chaining ([#62773](https://github.com/angular/angular/pull/62773)) |
### platform-browser
| Commit | Type | Description |
| -- | -- | -- |
| [74d99ed379](https://github.com/angular/angular/commit/74d99ed3796a3ced462e327c9b5857e5de4b7cb9) | fix | resolve component resources before bootstrapping in JIT mode ([#62758](https://github.com/angular/angular/pull/62758)) |
### service-worker
| Commit | Type | Description |
| -- | -- | -- |
| [4ac6171b09](https://github.com/angular/angular/commit/4ac6171b09e449c619e0588c366861f8f3bb59be) | feat | Adds support for updateViaCache in provideServiceWorker ([#62721](https://github.com/angular/angular/pull/62721)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="20.1.3"></a>
# 20.1.3 (2025-07-23)
### core
@@ -205,41 +157,6 @@
<!-- CHANGELOG SPLIT MARKER -->
<a name="20.2.0-next.1"></a>
# 20.2.0-next.1 (2025-07-16)
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [a1e3f2bcd1](https://github.com/angular/angular/commit/a1e3f2bcd14f897e685e11a84e011406dd6f7a33) | fix | incorrect spans for left side of binary operation ([#62641](https://github.com/angular/angular/pull/62641)) |
| [18a675081f](https://github.com/angular/angular/commit/18a675081f945ed4d7f4c0ee83172ca1528e7b2e) | fix | more permissive parsing of @ characters ([#62644](https://github.com/angular/angular/pull/62644)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [527bd778a7](https://github.com/angular/angular/commit/527bd778a7b23c23766bad7fb272d61df9a884b1) | fix | infer type of event target for void elements ([#62648](https://github.com/angular/angular/pull/62648)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [745ea44394](https://github.com/angular/angular/commit/745ea4439465494ab5b7002dd1fa320cd32220fb) | feat | support TypeScript 5.9 ([#62541](https://github.com/angular/angular/pull/62541)) |
| [859958dbfe](https://github.com/angular/angular/commit/859958dbfe5b8b505c84ecfed81d43e6c59e6f0c) | fix | Ensure application remains unstable during bootstrap ([#62631](https://github.com/angular/angular/pull/62631)) |
| [780774f948](https://github.com/angular/angular/commit/780774f94806b8eb895cb2a77c0d2a154f3d2d22) | fix | InputBinding marks component a dirty. ([#62613](https://github.com/angular/angular/pull/62613)) |
### http
| Commit | Type | Description |
| -- | -- | -- |
| [be811fee79](https://github.com/angular/angular/commit/be811fee7925fb482567fa7cd9d485ac28acdade) | feat | add referrer & integrity support for fetch requests in httpResource ([#62461](https://github.com/angular/angular/pull/62461)) |
| [1408baff45](https://github.com/angular/angular/commit/1408baff453e636da05838fa17c6e4abd86c4b72) | fix | Add missing timeout and transferCache options to `HttpClient` ([#62586](https://github.com/angular/angular/pull/62586)) |
| [75a5d08c5e](https://github.com/angular/angular/commit/75a5d08c5e9947f835ef911aacfe6c673e4c9e94) | fix | do not display warnings `Angular detected that a `HttpClient` request with the `keepalive` option was sent using XHR` when option is not true ([#62536](https://github.com/angular/angular/pull/62536)) |
### language-service
| Commit | Type | Description |
| -- | -- | -- |
| [d64dd27a02](https://github.com/angular/angular/commit/d64dd27a02630b631bc9890d7292d4683493cb65) | feat | support to report the deprecated API in the template ([#62054](https://github.com/angular/angular/pull/62054)) |
### router
| Commit | Type | Description |
| -- | -- | -- |
| [9c45c322d1](https://github.com/angular/angular/commit/9c45c322d1ac3b05c916b7c956263066fb9be47f) | fix | ensure preloaded components are properly activated ([#62502](https://github.com/angular/angular/pull/62502)) |
| [e9f215624f](https://github.com/angular/angular/commit/e9f215624f73c6aec6ec78117339c803830f4114) | fix | handle errors from view transition readiness ([#62535](https://github.com/angular/angular/pull/62535)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="20.1.1"></a>
# 20.1.1 (2025-07-16)
### compiler
@@ -267,15 +184,6 @@
<!-- CHANGELOG SPLIT MARKER -->
<a name="20.2.0-next.0"></a>
# 20.2.0-next.0 (2025-07-09)
### http
| Commit | Type | Description |
| -- | -- | -- |
| [1cf9d9064c](https://github.com/angular/angular/commit/1cf9d9064c15c00071ece3b78c8019035a6db6ce) | feat | Add support for fetch referrer & integrity options in HttpClient ([#62417](https://github.com/angular/angular/pull/62417)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="20.1.0"></a>
# 20.1.0 (2025-07-09)
### common
+163
View File
@@ -0,0 +1,163 @@
"""Rules/toolchains for angular with Bazel."""
module(
name = "angular",
)
bazel_dep(name = "rules_pkg", version = "1.1.0")
bazel_dep(name = "rules_nodejs", version = "6.5.0")
bazel_dep(name = "aspect_rules_ts", version = "3.7.0")
bazel_dep(name = "aspect_rules_js", version = "2.4.2")
bazel_dep(name = "aspect_rules_esbuild", version = "0.22.1")
bazel_dep(name = "aspect_rules_jasmine", version = "2.0.0")
bazel_dep(name = "aspect_rules_rollup", version = "2.0.1")
bazel_dep(name = "bazel_skylib", version = "1.8.1")
bazel_dep(name = "aspect_bazel_lib", version = "2.21.0")
bazel_dep(name = "tar.bzl", version = "0.5.5")
bazel_dep(name = "yq.bzl", version = "0.2.0")
bazel_dep(name = "rules_angular")
git_override(
module_name = "rules_angular",
commit = "17eac47ea99057f7473a7d93292e76327c894ed9",
remote = "https://github.com/devversion/rules_angular.git",
)
bazel_dep(name = "devinfra")
git_override(
module_name = "devinfra",
commit = "72f5a5f5bbbdf5bbaf0c8abf33cf6fbaef2ff50c",
remote = "https://github.com/angular/dev-infra.git",
)
bazel_dep(name = "rules_sass")
git_override(
module_name = "rules_sass",
commit = "76078d5e9776a0080dcee496e90b88d8a6179c19",
remote = "https://github.com/devversion/rules_sass.git",
)
bazel_dep(name = "rules_browsers")
git_override(
module_name = "rules_browsers",
commit = "8ee9ae3216ef26516c8ef20537c89857343cdc3a",
remote = "https://github.com/devversion/rules_browsers.git",
)
yq = use_extension("@yq.bzl//yq:extensions.bzl", "yq")
use_repo(yq, "yq_toolchains")
node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node")
node.toolchain(node_version = "20.19.0")
use_repo(node, "nodejs_toolchains")
use_repo(node, "nodejs_darwin_amd64")
use_repo(node, "nodejs_darwin_arm64")
use_repo(node, "nodejs_linux_amd64")
use_repo(node, "nodejs_linux_arm64")
use_repo(node, "nodejs_linux_ppc64le")
use_repo(node, "nodejs_linux_s390x")
use_repo(node, "nodejs_windows_amd64")
pnpm = use_extension("@aspect_rules_js//npm:extensions.bzl", "pnpm")
use_repo(pnpm, "pnpm")
npm = use_extension("@aspect_rules_js//npm:extensions.bzl", "npm")
npm.npm_translate_lock(
name = "npm",
data = [
"//:.pnpmfile.cjs",
"//:package.json",
"//:pnpm-workspace.yaml",
"//:tools/pnpm-patches/dagre-d3-es+7.0.11.patch",
"//adev:package.json",
"//adev/shared-docs:package.json",
"//adev/shared-docs/pipeline/api-gen:package.json",
"//integration:package.json",
"//modules:package.json",
"//packages/animations:package.json",
"//packages/benchpress:package.json",
"//packages/common:package.json",
"//packages/compiler:package.json",
"//packages/compiler-cli:package.json",
"//packages/compiler-cli/linker/babel/test:package.json",
"//packages/core:package.json",
"//packages/core/test/bundling:package.json",
"//packages/elements:package.json",
"//packages/forms:package.json",
"//packages/language-service:package.json",
"//packages/localize:package.json",
"//packages/platform-browser:package.json",
"//packages/platform-browser-dynamic:package.json",
"//packages/platform-server:package.json",
"//packages/router:package.json",
"//packages/service-worker:package.json",
"//packages/upgrade:package.json",
"//tools/bazel/rules_angular_store:package.json",
],
npmrc = "//:.npmrc",
pnpm_lock = "//:pnpm-lock.yaml",
verify_node_modules_ignored = "//:.bazelignore",
)
use_repo(npm, "npm")
rules_ts_ext = use_extension("@aspect_rules_ts//ts:extensions.bzl", "ext")
rules_ts_ext.deps(
name = "angular_npm_typescript",
# Obtained by: curl --silent https://registry.npmjs.org/typescript/5.9.2 | jq -r '.dist.integrity'
ts_integrity = "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
ts_version_from = "//:package.json",
)
use_repo(rules_ts_ext, **{"npm_typescript": "angular_npm_typescript"})
rules_angular = use_extension("@rules_angular//setup:extensions.bzl", "rules_angular")
rules_angular.setup(
name = "components_rules_angular_configurable_deps",
angular_compiler_cli = "//:node_modules/@angular/compiler-cli",
typescript = "//:node_modules/typescript",
)
use_repo(rules_angular, **{"rules_angular_configurable_deps": "components_rules_angular_configurable_deps"})
register_toolchains(
"@devinfra//bazel/git-toolchain:git_linux_toolchain",
"@devinfra//bazel/git-toolchain:git_macos_x86_toolchain",
"@devinfra//bazel/git-toolchain:git_macos_arm64_toolchain",
"@devinfra//bazel/git-toolchain:git_windows_toolchain",
)
CLDR_VERSION = "41"
cldr_json_data = use_repo_rule("//packages/common/locales/generate-locales-tool:cldr-data.bzl", "cldr_json_data_repository")
cldr_json_data(
name = "cldr_json_data",
urls = {
"https://github.com/unicode-org/cldr-json/releases/download/%s.0.0/cldr-%s.0.0-json-full.zip" % (CLDR_VERSION, CLDR_VERSION): "649b76647269e32b1b0a5f7b6eed52e9e63a1581f1afdcf4f6771e49c9713614",
},
)
cldr_xml_data = use_repo_rule("//packages/common/locales/generate-locales-tool:cldr-data.bzl", "cldr_xml_data_repository")
cldr_xml_data(
name = "cldr_xml_data",
urls = {
"https://github.com/unicode-org/cldr/releases/download/release-%s/cldr-common-%s.0.zip" % (CLDR_VERSION, CLDR_VERSION): "823c6170c41e2de2c229574e8a436332d25f1c9723409867fe721e00bc92d853",
},
)
http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# Fetch sauce connect (tool to open Saucelabs tunnel for Saucelabs browser tests)
http_archive(
name = "sauce_connect_linux_amd64",
build_file_content = """exports_files(["bin/sc"], visibility = ["//visibility:public"])""",
sha256 = "26b9c3630f441b47854b6032f7eca6f1d88d3f62e50ee44c27015d71a5155c36",
strip_prefix = "sc-4.8.2-linux",
url = "https://saucelabs.com/downloads/sc-4.8.2-linux.tar.gz",
)
http_archive(
name = "sauce_connect_mac",
build_file_content = """exports_files(["bin/sc"], visibility = ["//visibility:public"])""",
sha256 = "28277ce81ef9ab84f5b87b526258920a8ead44789a5034346e872629bbf38089",
strip_prefix = "sc-4.8.2-osx",
url = "https://saucelabs.com/downloads/sc-4.8.2-osx.zip",
)
+4326
View File
File diff suppressed because it is too large Load Diff
-257
View File
@@ -1,257 +0,0 @@
workspace(
name = "angular",
)
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# The PKG rules are needed to build tar packages for integration tests. The builtin
# rule in `@bazel_tools` is not Windows compatible and outdated.
# NOTE: We cannot move past version 0.6.0 as pkg_tar no longer works on directories, which rules_nodejs
# relies on for node_modules setup.
http_archive(
name = "rules_pkg",
sha256 = "62eeb544ff1ef41d786e329e1536c1d541bb9bcad27ae984d57f18f314018e66",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_pkg/releases/download/0.6.0/rules_pkg-0.6.0.tar.gz",
"https://github.com/bazelbuild/rules_pkg/releases/download/0.6.0/rules_pkg-0.6.0.tar.gz",
],
)
http_archive(
name = "aspect_rules_js",
sha256 = "304c51726b727d53277dd28fcda1b8e43b7e46818530b8d6265e7be98d5e2b25",
strip_prefix = "rules_js-2.3.8",
url = "https://github.com/aspect-build/rules_js/releases/download/v2.3.8/rules_js-v2.3.8.tar.gz",
)
load("@aspect_rules_js//js:repositories.bzl", "rules_js_dependencies")
rules_js_dependencies()
load("@aspect_rules_js//js:toolchains.bzl", "rules_js_register_toolchains")
rules_js_register_toolchains(
node_repositories = {
"20.19.0-darwin_arm64": ("node-v20.19.0-darwin-arm64.tar.gz", "node-v20.19.0-darwin-arm64", "c016cd1975a264a29dc1b07c6fbe60d5df0a0c2beb4113c0450e3d998d1a0d9c"),
"20.19.0-darwin_amd64": ("node-v20.19.0-darwin-x64.tar.gz", "node-v20.19.0-darwin-x64", "a8554af97d6491fdbdabe63d3a1cfb9571228d25a3ad9aed2df856facb131b20"),
"20.19.0-linux_arm64": ("node-v20.19.0-linux-arm64.tar.xz", "node-v20.19.0-linux-arm64", "dbe339e55eb393955a213e6b872066880bb9feceaa494f4d44c7aac205ec2ab9"),
"20.19.0-linux_ppc64le": ("node-v20.19.0-linux-ppc64le.tar.xz", "node-v20.19.0-linux-ppc64le", "84937108f005679e60b486ed8e801cebfe923f02b76d8e710463d32f82181f65"),
"20.19.0-linux_s390x": ("node-v20.19.0-linux-s390x.tar.xz", "node-v20.19.0-linux-s390x", "11f8ee99d792a83bba7b29911e0229dd6cd5e88987d7416346067db1cc76d89a"),
"20.19.0-linux_amd64": ("node-v20.19.0-linux-x64.tar.xz", "node-v20.19.0-linux-x64", "b4e336584d62abefad31baecff7af167268be9bb7dd11f1297112e6eed3ca0d5"),
"20.19.0-windows_amd64": ("node-v20.19.0-win-x64.zip", "node-v20.19.0-win-x64", "be72284c7bc62de07d5a9fd0ae196879842c085f11f7f2b60bf8864c0c9d6a4f"),
},
node_version = "20.19.0",
)
load("@aspect_rules_js//npm:repositories.bzl", "npm_translate_lock")
npm_translate_lock(
name = "npm2",
data = [
"//:.pnpmfile.cjs",
"//:package.json",
"//:pnpm-workspace.yaml",
"//:tools/pnpm-patches/dagre-d3-es+7.0.11.patch",
"//adev:package.json",
"//adev/shared-docs:package.json",
"//adev/shared-docs/pipeline/api-gen:package.json",
"//integration:package.json",
"//modules:package.json",
"//packages/animations:package.json",
"//packages/benchpress:package.json",
"//packages/common:package.json",
"//packages/compiler:package.json",
"//packages/compiler-cli:package.json",
"//packages/compiler-cli/linker/babel/test:package.json",
"//packages/core:package.json",
"//packages/core/test/bundling:package.json",
"//packages/elements:package.json",
"//packages/forms:package.json",
"//packages/language-service:package.json",
"//packages/localize:package.json",
"//packages/platform-browser:package.json",
"//packages/platform-browser-dynamic:package.json",
"//packages/platform-server:package.json",
"//packages/router:package.json",
"//packages/service-worker:package.json",
"//packages/upgrade:package.json",
"//tools/bazel/rules_angular_store:package.json",
],
npmrc = "//:.npmrc",
pnpm_lock = "//:pnpm-lock.yaml",
pnpm_version = "9.15.9",
verify_node_modules_ignored = "//:.bazelignore",
)
load("@npm2//:repositories.bzl", "npm_repositories")
npm_repositories()
http_archive(
name = "aspect_rules_ts",
sha256 = "09af62a0d46918d815b5f48b5ed0f5349b62c15fc42fcc3fef5c246504ff8d99",
strip_prefix = "rules_ts-3.6.3",
url = "https://github.com/aspect-build/rules_ts/releases/download/v3.6.3/rules_ts-v3.6.3.tar.gz",
)
load("@aspect_rules_ts//ts:repositories.bzl", "rules_ts_dependencies")
rules_ts_dependencies(
# Obtained by: curl --silent https://registry.npmjs.org/typescript/5.9.2 | jq -r '.dist.integrity'
ts_integrity = "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
ts_version_from = "//:package.json",
)
http_archive(
name = "aspect_rules_rollup",
sha256 = "0b8ac7d97cd660eb9a275600227e9c4268f5904cba962939d1a6ce9a0a059d2e",
strip_prefix = "rules_rollup-2.0.1",
url = "https://github.com/aspect-build/rules_rollup/releases/download/v2.0.1/rules_rollup-v2.0.1.tar.gz",
)
http_archive(
name = "aspect_rules_jasmine",
sha256 = "0d2f9c977842685895020cac721d8cc4f1b37aae15af46128cf619741dc61529",
strip_prefix = "rules_jasmine-2.0.0",
url = "https://github.com/aspect-build/rules_jasmine/releases/download/v2.0.0/rules_jasmine-v2.0.0.tar.gz",
)
load("@aspect_rules_jasmine//jasmine:dependencies.bzl", "rules_jasmine_dependencies")
rules_jasmine_dependencies()
load("@aspect_bazel_lib//lib:repositories.bzl", "aspect_bazel_lib_dependencies")
aspect_bazel_lib_dependencies()
load("@rules_pkg//:deps.bzl", "rules_pkg_dependencies")
rules_pkg_dependencies()
load("//packages/common/locales/generate-locales-tool:cldr-data.bzl", "cldr_json_data_repository", "cldr_xml_data_repository")
cldr_major_version = "41"
cldr_json_data_repository(
name = "cldr_json_data",
urls = {
"https://github.com/unicode-org/cldr-json/releases/download/%s.0.0/cldr-%s.0.0-json-full.zip" % (cldr_major_version, cldr_major_version): "649b76647269e32b1b0a5f7b6eed52e9e63a1581f1afdcf4f6771e49c9713614",
},
)
cldr_xml_data_repository(
name = "cldr_xml_data",
urls = {
"https://github.com/unicode-org/cldr/releases/download/release-%s/cldr-common-%s.0.zip" % (cldr_major_version, cldr_major_version): "823c6170c41e2de2c229574e8a436332d25f1c9723409867fe721e00bc92d853",
},
)
# Fetch sauce connect (tool to open Saucelabs tunnel for Saucelabs browser tests)
http_archive(
name = "sauce_connect_linux_amd64",
build_file_content = """exports_files(["bin/sc"], visibility = ["//visibility:public"])""",
sha256 = "26b9c3630f441b47854b6032f7eca6f1d88d3f62e50ee44c27015d71a5155c36",
strip_prefix = "sc-4.8.2-linux",
url = "https://saucelabs.com/downloads/sc-4.8.2-linux.tar.gz",
)
http_archive(
name = "sauce_connect_mac",
build_file_content = """exports_files(["bin/sc"], visibility = ["//visibility:public"])""",
sha256 = "28277ce81ef9ab84f5b87b526258920a8ead44789a5034346e872629bbf38089",
strip_prefix = "sc-4.8.2-osx",
url = "https://saucelabs.com/downloads/sc-4.8.2-osx.zip",
)
git_repository(
name = "devinfra",
commit = "17282887a46c27e9f297a3292f1fde5b35dfafc1",
remote = "https://github.com/angular/dev-infra.git",
)
load("@devinfra//bazel:setup_dependencies_1.bzl", "setup_dependencies_1")
setup_dependencies_1()
load("@devinfra//bazel:setup_dependencies_2.bzl", "setup_dependencies_2")
setup_dependencies_2()
git_repository(
name = "rules_angular",
commit = "a1b4985620e2b66b45c590ed5ddda1b346b3f098",
remote = "https://github.com/devversion/rules_angular.git",
)
load("@rules_angular//setup:step_1.bzl", "rules_angular_step1")
rules_angular_step1()
load("@rules_angular//setup:step_2.bzl", "rules_angular_step2")
rules_angular_step2()
load("@rules_angular//setup:step_3.bzl", "rules_angular_step3")
rules_angular_step3(
angular_compiler_cli = "@angular//tools/bazel/rules_angular_store:node_modules/@angular/compiler-cli",
typescript = "@angular//:node_modules/typescript",
)
git_repository(
name = "rules_browsers",
commit = "56ef8007ea07cd1916429bca8bb523433b0e9cdc",
remote = "https://github.com/devversion/rules_browsers.git",
)
load("@rules_browsers//setup:step_1.bzl", "rules_browsers_setup_1")
rules_browsers_setup_1()
load("@rules_browsers//setup:step_2.bzl", "rules_browsers_setup_2")
rules_browsers_setup_2()
http_archive(
name = "aspect_rules_esbuild",
sha256 = "530adfeae30bbbd097e8af845a44a04b641b680c5703b3bf885cbd384ffec779",
strip_prefix = "rules_esbuild-0.22.1",
url = "https://github.com/aspect-build/rules_esbuild/releases/download/v0.22.1/rules_esbuild-v0.22.1.tar.gz",
)
load("@aspect_rules_esbuild//esbuild:dependencies.bzl", "rules_esbuild_dependencies")
rules_esbuild_dependencies()
load("@aspect_rules_esbuild//esbuild:repositories.bzl", "LATEST_ESBUILD_VERSION", "esbuild_register_toolchains")
esbuild_register_toolchains(
name = "esbuild",
esbuild_version = LATEST_ESBUILD_VERSION,
)
# Register git toolchains
register_toolchains(
"@devinfra//bazel/git-toolchain:git_linux_toolchain",
"@devinfra//bazel/git-toolchain:git_macos_x86_toolchain",
"@devinfra//bazel/git-toolchain:git_macos_arm64_toolchain",
"@devinfra//bazel/git-toolchain:git_windows_toolchain",
)
git_repository(
name = "rules_sass",
commit = "cc1e845339fc45d3c8390445014d5824b85a0948",
remote = "https://github.com/devversion/rules_sass.git",
)
load("@rules_sass//src/toolchain:repositories.bzl", "setup_rules_sass")
setup_rules_sass()
http_archive(
name = "jq.bzl",
sha256 = "7b63435aa19cc6a0cfd1a82fbdf2c7a2f0a94db1a79ff7a4469ffa94286261ab",
strip_prefix = "jq.bzl-0.1.0",
url = "https://github.com/bazel-contrib/jq.bzl/releases/download/v0.1.0/jq.bzl-v0.1.0.tar.gz",
)
+5 -5
View File
@@ -1,5 +1,5 @@
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
load("@npm2//:defs.bzl", "npm_link_all_packages")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("@rules_angular//src/architect:ng_application.bzl", "ng_application")
load("@rules_angular//src/architect:ng_config.bzl", "ng_config")
load("@rules_angular//src/architect:ng_test.bzl", "ng_test")
@@ -87,8 +87,8 @@ TEST_DEPS = [
for dep in APPLICATION_DEPS
if dep != "//adev:node_modules/@types/node"
] + [
"@rules_browsers//src/browsers/chromium",
"@rules_browsers//src/browsers/firefox",
"@rules_browsers//browsers/chromium",
"@rules_browsers//browsers/firefox",
"//adev/tools:windows-chromium-path",
]
@@ -155,7 +155,7 @@ ng_test(
node_modules = "//adev:node_modules",
project_name = "angular-dev",
toolchains = [
"@rules_browsers//src/browsers/chromium:toolchain_alias",
"@rules_browsers//src/browsers/firefox:toolchain_alias",
"@rules_browsers//browsers/chromium:toolchain_alias",
"@rules_browsers//browsers/firefox:toolchain_alias",
],
)
+15 -15
View File
@@ -1,21 +1,21 @@
{
"dependencies": {
"@angular-devkit/build-angular": "20.2.0-next.2",
"@angular-devkit/build-angular": "20.2.0",
"@angular/animations": "workspace:*",
"@angular/build": "20.2.0-next.2",
"@angular/cdk": "20.2.0-next.2",
"@angular/cli": "20.2.0-next.2",
"@angular/build": "20.2.0",
"@angular/cdk": "20.2.0",
"@angular/cli": "20.2.0",
"@angular/common": "workspace:*",
"@angular/compiler-cli": "workspace:*",
"@angular/compiler": "workspace:*",
"@angular/core": "workspace:*",
"@angular/docs": "workspace:*",
"@angular/forms": "workspace:*",
"@angular/material": "20.2.0-next.2",
"@angular/material": "20.2.0",
"@angular/platform-browser": "workspace:*",
"@angular/platform-server": "workspace:*",
"@angular/router": "workspace:*",
"@angular/ssr": "20.2.0-next.2",
"@angular/ssr": "20.2.0",
"@codemirror/autocomplete": "6.18.6",
"@codemirror/commands": "6.8.1",
"@codemirror/lang-angular": "0.1.4",
@@ -23,7 +23,7 @@
"@codemirror/lang-html": "6.4.9",
"@codemirror/lang-javascript": "6.2.4",
"@codemirror/lang-sass": "6.0.2",
"@codemirror/language": "6.11.2",
"@codemirror/language": "6.11.3",
"@codemirror/lint": "6.8.5",
"@codemirror/search": "6.5.11",
"@codemirror/state": "6.5.2",
@@ -33,9 +33,9 @@
"@lezer/javascript": "1.5.1",
"@stackblitz/sdk": "1.11.0",
"@types/dom-navigation": "1.0.6",
"@types/jasmine": "5.1.8",
"@types/jasmine": "5.1.9",
"@types/jsdom": "21.1.7",
"@types/node": "24.1.0",
"@types/node": "24.3.0",
"@typescript/vfs": "1.6.1",
"@webcontainer/api": "1.6.1",
"@xterm/addon-fit": "0.10.0",
@@ -52,16 +52,16 @@
"karma-coverage": "2.2.1",
"karma-jasmine-html-reporter": "2.1.0",
"karma-jasmine": "5.1.0",
"marked": "16.1.1",
"mermaid": "11.9.0",
"marked": "16.2.0",
"mermaid": "11.10.0",
"ngx-progressbar": "14.0.0",
"open-in-idx": "0.1.1",
"playwright-core": "1.54.1",
"preact-render-to-string": "6.5.13",
"preact": "10.27.0",
"playwright-core": "1.55.0",
"preact-render-to-string": "6.6.1",
"preact": "10.27.1",
"prettier": "3.6.2",
"rxjs": "7.8.2",
"shiki": "3.9.0",
"shiki": "3.11.0",
"tinyglobby": "0.2.14",
"tslib": "2.8.1",
"typescript": "5.9.2",
@@ -21,6 +21,7 @@ ng_project(
"//adev:node_modules/@angular/common",
"//adev:node_modules/@angular/core",
"//adev:node_modules/@angular/material",
"//adev:node_modules/@angular/platform-browser",
"//adev:node_modules/@angular/router",
"//adev:node_modules/rxjs",
"//adev/shared-docs/components/breadcrumb",
@@ -39,10 +39,11 @@ import {fromEvent} from 'rxjs';
import {Breadcrumb} from '../../breadcrumb/breadcrumb.component';
import {CopySourceCodeButton} from '../../copy-source-code-button/copy-source-code-button.component';
import {ExampleViewer} from '../example-viewer/example-viewer.component';
import {DomSanitizer} from '@angular/platform-browser';
const TOC_HOST_ELEMENT_NAME = 'docs-table-of-contents';
export const ASSETS_EXAMPLES_PATH = 'assets/content/examples';
export const DOCS_VIEWER_SELECTOR = 'docs-viewer';
export const DOCS_VIEWER_SELECTOR = 'docs-viewer, main[docsViewer]';
export const DOCS_CODE_SELECTOR = '.docs-code';
export const DOCS_CODE_MUTLIFILE_SELECTOR = '.docs-code-multifile';
// TODO: Update the branch/sha
@@ -74,6 +75,7 @@ export class DocViewer {
private readonly environmentInjector = inject(EnvironmentInjector);
private readonly injector = inject(Injector);
private readonly appRef = inject(ApplicationRef);
private readonly sanitizer = inject(DomSanitizer);
protected animateContent = false;
private readonly pendingTasks = inject(PendingTasks);
@@ -200,10 +202,10 @@ export class DocViewer {
id: this.countOfExamples,
});
exampleRef.instance.githubUrl = `${GITHUB_CONTENT_URL}/${snippets[0].name}`;
exampleRef.setInput('githubUrl', `${GITHUB_CONTENT_URL}/${snippets[0].name}`);
// TODO: Re-add support for opening examples on StackBlitz
exampleRef.instance.stackblitzUrl = null; // `${ASSETS_EXAMPLES_PATH}/${snippets[0].name}.html`;
exampleRef.setInput('stackblitzUrl', null); // `${ASSETS_EXAMPLES_PATH}/${snippets[0].name}.html`;
placeholder.parentElement!.replaceChild(exampleRef.location.nativeElement, placeholder);
@@ -215,7 +217,7 @@ export class DocViewer {
return tabs.map((tab) => ({
name: tab.getAttribute('path') ?? tab.getAttribute('header') ?? '',
content: tab.innerHTML,
sanitizedContent: this.sanitizer.bypassSecurityTrustHtml(tab.innerHTML),
visibleLinesRange: tab.getAttribute('visibleLines') ?? undefined,
}));
}
@@ -235,7 +237,9 @@ export class DocViewer {
return {
title,
name: path,
content: content?.outerHTML,
sanitizedContent: content?.outerHTML
? this.sanitizer.bypassSecurityTrustHtml(content.outerHTML)
: '',
visibleLinesRange: visibleLines,
};
}
@@ -5,11 +5,7 @@
}
@if (view() === CodeExampleViewMode.MULTI_FILE) {
<mat-tab-group
#codeTabs
animationDuration="0ms"
mat-stretch-tabs="false"
>
<mat-tab-group #codeTabs animationDuration="0ms" mat-stretch-tabs="false">
@for (tab of tabs(); track tab) {
<mat-tab [label]="tab.name"></mat-tab>
}
@@ -87,7 +83,9 @@
[class.docs-example-viewer-multi-file]="view() === CodeExampleViewMode.MULTI_FILE"
>
<button docs-copy-source-code></button>
<docs-viewer [docContent]="snippetCode()?.content" />
@if (snippetCode()?.sanitizedContent; as content) {
<div [innerHTML]="content"></div>
}
</div>
@if (exampleComponent) {
@@ -98,9 +96,9 @@
<ng-template #openCodeInExternalProvider>
@if (exampleComponent) {
@if (githubUrl) {
@if (githubUrl()) {
<a
[href]="githubUrl"
[href]="githubUrl()"
target="_blank"
title="Open example on GitHub"
class="docs-example-github-link"
@@ -125,9 +123,9 @@
</i>
</a>
}
@if (stackblitzUrl) {
@if (stackblitzUrl()) {
<a
[href]="stackblitzUrl"
[href]="stackblitzUrl()"
target="_blank"
class="docs-example-stackblitz-link"
title="Edit this example in StackBlitz"
@@ -1,10 +1,12 @@
:host {
.docs-example-viewer-preview {
.docs-dark-mode & {
background: var(--gray-100);
color: var(--primary-contrast);
background: var(--gray-900);
}
@media screen and (prefers-color-scheme: dark) {
background: var(--gray-100);
color: var(--primary-contrast);
background: var(--gray-900);
}
.docs-light-mode & {
background: var(--page-background);
@@ -53,9 +53,9 @@ describe('ExampleViewer', () => {
'metadata',
getMetadata({
files: [
{name: 'file.ts', content: ''},
{name: 'file.html', content: ''},
{name: 'file.css', content: ''},
{name: 'file.ts', sanitizedContent: ''},
{name: 'file.html', sanitizedContent: ''},
{name: 'file.css', sanitizedContent: ''},
],
}),
);
@@ -73,9 +73,9 @@ describe('ExampleViewer', () => {
'metadata',
getMetadata({
files: [
{name: 'file.ts', content: 'typescript file'},
{name: 'file.html', content: 'html file'},
{name: 'file.css', content: 'css file'},
{name: 'file.ts', sanitizedContent: 'typescript file'},
{name: 'file.html', sanitizedContent: 'html file'},
{name: 'file.css', sanitizedContent: 'css file'},
],
}),
);
@@ -93,9 +93,9 @@ describe('ExampleViewer', () => {
'metadata',
getMetadata({
files: [
{name: 'example.ts', content: 'typescript file'},
{name: 'example.html', content: 'html file'},
{name: 'another-example.ts', content: 'css file'},
{name: 'example.ts', sanitizedContent: 'typescript file'},
{name: 'example.html', sanitizedContent: 'html file'},
{name: 'another-example.ts', sanitizedContent: 'css file'},
],
}),
);
@@ -124,7 +124,7 @@ describe('ExampleViewer', () => {
files: [
{
name: 'example.ts',
content: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
sanitizedContent: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
visibleLinesRange: '[1]',
},
],
@@ -148,7 +148,7 @@ describe('ExampleViewer', () => {
files: [
{
name: 'example.ts',
content: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
sanitizedContent: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
visibleLinesRange: '[1]',
},
],
@@ -198,7 +198,7 @@ describe('ExampleViewer', () => {
By.css('a[aria-label="Open example on GitHub"]'),
);
expect(githubButton).toBeTruthy();
expect(githubButton.nativeElement.href).toBe(component.githubUrl);
expect(githubButton.nativeElement.href).toBe(component.githubUrl());
});
it('should display StackBlitz button when stackblitzUrl is provided and there is preview', async () => {
@@ -210,7 +210,8 @@ describe('ExampleViewer', () => {
preview: true,
}),
);
component.stackblitzUrl = 'https://stackblitz.com/';
componentRef.setInput('stackblitzUrl', 'https://stackblitz.com/');
await component.renderExample();
fixture.detectChanges();
@@ -218,7 +219,7 @@ describe('ExampleViewer', () => {
By.css('a[aria-label="Edit this example in StackBlitz"]'),
);
expect(stackblitzButton).toBeTruthy();
expect(stackblitzButton.nativeElement.href).toBe(component.stackblitzUrl);
expect(stackblitzButton.nativeElement.href).toBe(component.stackblitzUrl());
});
it('should set expanded flag in metadata after toggleExampleVisibility', async () => {
@@ -242,9 +243,9 @@ describe('ExampleViewer', () => {
files: [
{
name: 'example.ts',
content: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
sanitizedContent: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
},
{name: 'example.css', content: ''},
{name: 'example.css', sanitizedContent: ''},
],
}),
);
@@ -278,8 +279,8 @@ const getMetadata = (value: Partial<ExampleMetadata> = {}): ExampleMetadata => {
return {
id: 1,
files: [
{name: 'example.ts', content: ''},
{name: 'example.css', content: ''},
{name: 'example.ts', sanitizedContent: ''},
{name: 'example.css', sanitizedContent: ''},
],
preview: false,
...value,
@@ -14,11 +14,9 @@ import {
computed,
DestroyRef,
ElementRef,
forwardRef,
inject,
Injector,
input,
Input,
signal,
Type,
viewChild,
@@ -30,7 +28,6 @@ import {CopySourceCodeButton} from '../../copy-source-code-button/copy-source-co
import {ExampleMetadata, Snippet} from '../../../interfaces/index';
import {EXAMPLE_VIEWER_CONTENT_LOADER} from '../../../providers/index';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {DocViewer} from '../docs-viewer/docs-viewer.component';
export enum CodeExampleViewMode {
SNIPPET = 'snippet',
@@ -44,16 +41,15 @@ export const HIDDEN_CLASS_NAME = 'hidden';
@Component({
selector: 'docs-example-viewer',
imports: [CommonModule, forwardRef(() => DocViewer), CopySourceCodeButton, MatTabsModule],
imports: [CommonModule, CopySourceCodeButton, MatTabsModule],
templateUrl: './example-viewer.component.html',
styleUrls: ['./example-viewer.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ExampleViewer {
exampleMetadata = input<ExampleMetadata | null>(null, {alias: 'metadata'});
@Input() githubUrl: string | null = null;
@Input() stackblitzUrl: string | null = null;
readonly exampleMetadata = input<ExampleMetadata | null>(null, {alias: 'metadata'});
readonly githubUrl = input<string | null>(null);
readonly stackblitzUrl = input<string | null>(null);
readonly matTabGroup = viewChild<MatTabGroup>('codeTabs');
private readonly changeDetector = inject(ChangeDetectorRef);
@@ -82,7 +78,7 @@ export class ExampleViewer {
this.exampleMetadata()?.files.map((file) => ({
name:
file.title ?? (this.shouldDisplayFullName() ? file.name : this.getFileExtension(file.name)),
code: file.content,
code: file.sanitizedContent,
})),
);
view = computed(() =>
+1
View File
@@ -26,6 +26,7 @@ ts_project(
),
deps = [
"//adev:node_modules/@angular/core",
"//adev:node_modules/@angular/platform-browser",
"//adev:node_modules/@angular/router",
"//adev:node_modules/@types/node",
"//adev:node_modules/@webcontainer/api",
+2 -1
View File
@@ -7,6 +7,7 @@
*/
import {Type} from '@angular/core';
import {SafeHtml} from '@angular/platform-browser';
/**
* Map of the examples, values are functions which returns the promise of the component type, which will be displayed as preview in the ExampleViewer component
@@ -21,7 +22,7 @@ export interface Snippet {
/** Name of the file. */
name: string;
/** Content of code snippet */
content: string;
sanitizedContent: SafeHtml;
/** Text in following format `start-end`. Start and end are numbers, based on them provided range of lines will be displayed in collapsed mode */
visibleLinesRange?: string;
}
+1 -1
View File
@@ -20,7 +20,7 @@
"fflate": "^0.8.2",
"html-entities": "~2.6.0",
"jsdom": "~26.1.0",
"marked": "~16.1.0",
"marked": "~16.2.0",
"mermaid": "^11.0.0",
"shiki": "^3.0.0",
"tinyglobby": "^0.2.12"
+2 -2
View File
@@ -47,13 +47,13 @@ js_binary(
"//adev:node_modules/jsdom",
"//adev:node_modules/mermaid",
"//adev:node_modules/playwright-core",
"@rules_browsers//src/browsers/chromium",
"@rules_browsers//browsers/chromium",
],
entry_point = "//adev/shared-docs/pipeline/guides:guides.mjs",
env = {
"CHROME_HEADLESS_BIN": "$(CHROME-HEADLESS-SHELL)",
},
toolchains = ["@rules_browsers//src/browsers/chromium:toolchain_alias"],
toolchains = ["@rules_browsers//browsers/chromium:toolchain_alias"],
visibility = ["//visibility:public"],
)
@@ -1,4 +1,4 @@
load("@npm2//:defs.bzl", "npm_link_all_packages")
load("@npm//:defs.bzl", "npm_link_all_packages")
package(default_visibility = ["//visibility:public"])
@@ -111,7 +111,7 @@ function main() {
...getEntriesFromMembers(entry).map((member) => [member, moduleName]),
]),
],
} as EntryCollection);
} satisfies EntryCollection);
writeFileSync(outputFilenameExecRootRelativePath, output, {encoding: 'utf8'});
}
@@ -14,18 +14,21 @@ describe('api manifest generation', () => {
it('should generate a manifest from multiple collections', () => {
const manifest: Manifest = generateManifest([
{
repo: 'angular/router',
moduleName: '@angular/router',
entries: [entry({name: 'Router', entryType: EntryType.UndecoratedClass})],
normalizedModuleName: 'angular_router',
moduleLabel: 'router',
},
{
repo: 'angular/core',
moduleName: '@angular/core',
entries: [entry({name: 'PI', entryType: EntryType.Constant})],
normalizedModuleName: 'angular_core',
moduleLabel: 'core',
},
{
repo: 'angular/core',
moduleName: '@angular/core',
entries: [entry({name: 'foo', entryType: EntryType.Constant})],
normalizedModuleName: 'angular_core',
@@ -79,12 +82,14 @@ describe('api manifest generation', () => {
it('should generate a manifest when collections share a symbol with the same name', () => {
const manifest = generateManifest([
{
repo: 'angular/core',
moduleName: '@angular/core',
entries: [entry({name: 'PI', entryType: EntryType.Constant})],
normalizedModuleName: 'angular_core',
moduleLabel: 'core',
},
{
repo: 'angular/router',
moduleName: '@angular/router',
entries: [entry({name: 'PI', entryType: EntryType.Constant})],
normalizedModuleName: 'angular_router',
@@ -129,12 +134,14 @@ describe('api manifest generation', () => {
it('should union collections for the same module into one manifest', () => {
const manifest = generateManifest([
{
repo: 'angular/core',
moduleName: '@angular/core',
entries: [entry({name: 'PI', entryType: EntryType.Constant})],
normalizedModuleName: 'angular_core',
moduleLabel: 'core',
},
{
repo: 'angular/core',
moduleName: '@angular/core',
entries: [entry({name: 'TAO', entryType: EntryType.Constant})],
normalizedModuleName: 'angular_core',
@@ -172,6 +179,7 @@ describe('api manifest generation', () => {
it('should mark a manifest entry as deprecated', () => {
const manifest = generateManifest([
{
repo: 'angular/core',
moduleName: '@angular/core',
entries: [
entry({name: 'PI', entryType: EntryType.Constant, jsdocTags: jsdocTags('deprecated')}),
@@ -212,6 +220,7 @@ describe('api manifest generation', () => {
it('should not mark a function as deprecated if only one overload is deprecated', () => {
const manifest = generateManifest([
{
repo: 'angular/core',
moduleName: '@angular/core',
entries: [
functionEntry({
@@ -271,6 +280,7 @@ describe('api manifest generation', () => {
it('should mark a function as deprecated if all overloads are deprecated', () => {
const manifest = generateManifest([
{
repo: 'angular/core',
moduleName: '@angular/core',
entries: [
functionEntry({
@@ -330,6 +340,7 @@ describe('api manifest generation', () => {
it("should mark a fn as deprecated if there's one w/ the same name in another collection", () => {
const manifest = generateManifest([
{
repo: 'angular/core',
moduleName: '@angular/core',
entries: [
entry({name: 'save', entryType: EntryType.Function, jsdocTags: jsdocTags('deprecated')}),
@@ -338,6 +349,7 @@ describe('api manifest generation', () => {
moduleLabel: 'core',
},
{
repo: 'angular/more',
moduleName: '@angular/more',
entries: [entry({name: 'save', entryType: EntryType.Function})],
normalizedModuleName: 'angular_more',
@@ -382,6 +394,7 @@ describe('api manifest generation', () => {
it('should mark a manifest entry as developerPreview', () => {
const manifest = generateManifest([
{
repo: 'angular/core',
moduleName: '@angular/core',
entries: [
entry({
-12
View File
@@ -1,12 +0,0 @@
// This definition file is a temporary workaround until the toolchain is able to read d.mts definition files
// TODO: delete this file when the toolchains supports .d.mts files
declare module 'shiki' {
function createHighlighter(params: {
themes: any[];
langs: string[];
cssVariablePrefix?: string;
defaultColor?: boolean;
}): unknown;
type HighlighterGeneric<BundledLangKeys, BundledThemeKeys> = any;
}
@@ -24,31 +24,28 @@ export function CliCard(props: {card: CliCardRenderable}) {
{item.aliases?.map((alias) => (
<div class="docs-reference-option-aliases">
<span>Alias</span>
<code>{alias} </code>
<code>{alias}</code>
</div>
))}
</div>
<div dangerouslySetInnerHTML={{__html: item.description}}></div>
</div>
<div class="docs-reference-type-and-default">
{/* Display the enum values if there are some, else the type expected for the option */}
{/* Display the type expected for the option and the enum values if there are some. */}
<span>Value Type</span>
<code>{item.type}</code>
{item.enum ? (
<>
<span>Allowed Values</span>
<span>
{item.enum.map((val, i, items) => (
<>
<code>{val}</code>
{i < items.length - 1 && ', '}
</>
))}
</span>
{item.enum.map((val, i, items) => (
<>
<code>{val}</code>
{i < items.length - 1 && ', '}
</>
))}
</>
) : (
<>
<span>Value Type</span>
<code>{item.type}</code>
</>
<></>
)}
{/* Default Value */}
{item.default !== undefined ? <span>Default</span> : <></>}
@@ -177,8 +177,7 @@
"enum": [
"Emulated",
"None",
"ShadowDom",
"IsolatedShadowDom"
"ShadowDom"
],
"description": "The view encapsulation strategy to use in the new application."
}
@@ -368,8 +367,7 @@
"enum": [
"Emulated",
"None",
"ShadowDom",
"IsolatedShadowDom"
"ShadowDom"
],
"description": "The view encapsulation strategy to use in the new component."
}
@@ -33,7 +33,7 @@ function getMermaidScriptTagData() {
}
return (mermaidScriptTagData = {
path: resolve(join(runfilesDir, 'angular/adev/node_modules/mermaid/dist/mermaid.js')),
path: resolve(join(runfilesDir, '_main/adev/node_modules/mermaid/dist/mermaid.js')),
});
}
-12
View File
@@ -1,12 +0,0 @@
// This definition file is a temporary workaround until the toolchain is able to read d.mts definition files
// TODO: delete this file when the toolchains supports .d.mts files
declare module 'shiki' {
function createHighlighter(params: {
themes: any[];
langs: string[];
cssVariablePrefix?: string;
defaultColor?: boolean;
}): unknown;
type HighlighterGeneric<BundledLangKeys, BundledThemeKeys> = any;
}
@@ -18,7 +18,7 @@ zoneless_jasmine_test(
name = "unit_tests",
data = [
":unit_test_lib",
"@rules_browsers//src/browsers/chromium",
"@rules_browsers//browsers/chromium",
] + glob([
"**/*.md",
"**/*.svg",
@@ -27,5 +27,5 @@ zoneless_jasmine_test(
env = {
"CHROME_HEADLESS_BIN": "$(CHROME-HEADLESS-SHELL)",
},
toolchains = ["@rules_browsers//src/browsers/chromium:toolchain_alias"],
toolchains = ["@rules_browsers//browsers/chromium:toolchain_alias"],
)
+6 -1
View File
@@ -373,6 +373,12 @@
// "CLI member card"-specific styles
.docs-reference-member-card {
.docs-reference-option-aliases {
span {
padding-right: 0.4rem;
}
}
.docs-ref-content {
padding: 1rem 0;
@@ -387,7 +393,6 @@
display: block;
font-size: 0.875rem;
margin-block-end: 0.2rem;
white-space: nowrap;
&:not(:first-child) {
margin-block-start: 1rem;
-1
View File
@@ -11,7 +11,6 @@ import {provideHttpClient, withFetch} from '@angular/common/http';
import {
ApplicationConfig,
ErrorHandler,
VERSION,
inject,
provideZonelessChangeDetection,
provideEnvironmentInitializer,
+9 -6
View File
@@ -6,9 +6,12 @@
* found in the LICENSE file at https://angular.dev/license
*/
export const GITHUB = 'https://github.com/angular/angular';
export const X = 'https://x.com/angular';
export const MEDIUM = 'https://blog.angular.dev';
export const YOUTUBE = 'https://www.youtube.com/angular';
export const DISCORD = 'https://discord.gg/angular';
export const BLUESKY = 'https://bsky.app/profile/angular.dev';
export const ANGULAR_LINKS = {
GITHUB: 'https://github.com/angular/angular',
X: 'https://x.com/angular',
MEDIUM: 'https://blog.angular.dev',
YOUTUBE: 'https://www.youtube.com/angular',
DISCORD: 'https://discord.gg/angular',
BLUESKY: 'https://bsky.app/profile/angular.dev',
STACKOVERFLOW: 'https://stackoverflow.com/questions/tagged/angular',
} as const;
@@ -4,31 +4,31 @@
<h2>Social Media</h2>
<ul>
<li>
<a [href]="MEDIUM" title="Angular blog">Blog</a>
<a [href]="ngLinks.MEDIUM" title="Angular blog">Blog</a>
</li>
<li>
<a [href]="X" title="X (formerly Twitter)">X (formerly Twitter)</a>
<a [href]="ngLinks.X" title="X (formerly Twitter)">X (formerly Twitter)</a>
</li>
<li>
<a [href]="BLUESKY" title="Bluesky">Bluesky</a>
<a [href]="ngLinks.BLUESKY" title="Bluesky">Bluesky</a>
</li>
<li>
<a [href]="YOUTUBE" title="YouTube">YouTube</a>
<a [href]="ngLinks.YOUTUBE" title="YouTube">YouTube</a>
</li>
<li>
<a
href="https://discord.gg/angular"
[href]="ngLinks.DISCORD"
title="Join the discussions at Angular Community Discord server."
>
Discord
</a>
</li>
<li>
<a [href]="GITHUB" title="GitHub">GitHub</a>
<a [href]="ngLinks.GITHUB" title="GitHub">GitHub</a>
</li>
<li>
<a
href="https://stackoverflow.com/questions/tagged/angular"
[href]="ngLinks.STACKOVERFLOW"
title="Stack Overflow: where the community answers your technical Angular questions."
>
Stack Overflow
@@ -9,7 +9,7 @@
import {ChangeDetectionStrategy, Component} from '@angular/core';
import {ExternalLink} from '@angular/docs';
import {RouterLink} from '@angular/router';
import {GITHUB, X, MEDIUM, YOUTUBE, BLUESKY} from './../../constants/links';
import {ANGULAR_LINKS} from '../../constants/links';
@Component({
selector: 'footer[adev-footer]',
@@ -19,9 +19,5 @@ import {GITHUB, X, MEDIUM, YOUTUBE, BLUESKY} from './../../constants/links';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class Footer {
readonly GITHUB = GITHUB;
readonly X = X;
readonly YOUTUBE = YOUTUBE;
readonly MEDIUM = MEDIUM;
readonly BLUESKY = BLUESKY;
protected ngLinks = ANGULAR_LINKS;
}
@@ -305,7 +305,7 @@
<ul class="adev-mini-menu" cdkMenu>
<li>
<a
[href]="YOUTUBE"
[href]="ngLinks.YOUTUBE"
cdkMenuItem
title="Angular YouTube channel"
target="_blank"
@@ -327,7 +327,7 @@
</li>
<li>
<a
[href]="X"
[href]="ngLinks.X"
cdkMenuItem
title="Angular X (formerly Twitter) profile"
target="_blank"
@@ -349,7 +349,7 @@
</li>
<li>
<a
[href]="BLUESKY"
[href]="ngLinks.BLUESKY"
cdkMenuItem
title="Angular Bluesky profile"
target="_blank"
@@ -370,7 +370,7 @@
</li>
<li>
<a
[href]="MEDIUM"
[href]="ngLinks.MEDIUM"
cdkMenuItem
title="Angular Medium blog"
target="_blank"
@@ -385,7 +385,7 @@
</a>
</li>
<li>
<a [href]="GITHUB" cdkMenuItem title="Angular Github" target="_blank" rel="noopener">
<a [href]="ngLinks.GITHUB" cdkMenuItem title="Angular Github" target="_blank" rel="noopener">
<!-- Github Icon -->
<svg
width="20"
@@ -403,7 +403,7 @@
</a>
</li>
<li>
<a [href]="DISCORD" cdkMenuItem title="Angular Discord" target="_blank" rel="noopener">
<a [href]="ngLinks.DISCORD" cdkMenuItem title="Angular Discord" target="_blank" rel="noopener">
<!-- Discord Icon -->
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -21,12 +21,12 @@ import {
import {NavigationEnd, Router, RouterLink} from '@angular/router';
import {filter, map, startWith} from 'rxjs/operators';
import {DOCS_ROUTES, REFERENCE_ROUTES, TUTORIALS_ROUTES} from '../../../routes';
import {GITHUB, MEDIUM, X, YOUTUBE, DISCORD, BLUESKY} from '../../constants/links';
import {PagePrefix} from '../../enums/pages';
import {Theme, ThemeManager} from '../../services/theme-manager.service';
import {VersionManager} from '../../services/version-manager.service';
import {PRIMARY_NAV_ID, SECONDARY_NAV_ID} from '../../constants/element-ids';
import {ConnectionPositionPair} from '@angular/cdk/overlay';
import {ANGULAR_LINKS} from '../../constants/links';
import {PRIMARY_NAV_ID, SECONDARY_NAV_ID} from '../../constants/element-ids';
import {COMMAND, CONTROL, SEARCH_TRIGGER_KEY} from '../../constants/keys';
type MenuType = 'social' | 'theme-picker' | 'version-picker';
@@ -55,12 +55,7 @@ export class Navigation {
readonly REFERENCE_ROUTE = PagePrefix.REFERENCE;
readonly TUTORIALS_ROUTE = PagePrefix.TUTORIALS;
readonly GITHUB = GITHUB;
readonly X = X;
readonly MEDIUM = MEDIUM;
readonly YOUTUBE = YOUTUBE;
readonly DISCORD = DISCORD;
readonly BLUESKY = BLUESKY;
protected ngLinks = ANGULAR_LINKS;
readonly PRIMARY_NAV_ID = PRIMARY_NAV_ID;
readonly SECONDARY_NAV_ID = SECONDARY_NAV_ID;
@@ -19,7 +19,7 @@ import {
import {EditorView} from '@codemirror/view';
import {Subject, filter, take} from 'rxjs';
import {EditorFile} from '../code-mirror-editor.service';
import type {EditorFile} from '../code-mirror-editor.service';
import {TsVfsWorkerActions} from '../workers/enums/actions';
import {AutocompleteRequest} from '../workers/interfaces/autocomplete-request';
import {AutocompleteItem, AutocompleteResponse} from '../workers/interfaces/autocomplete-response';
@@ -9,7 +9,7 @@
import {Diagnostic, linter} from '@codemirror/lint';
import {TsVfsWorkerActions} from '../workers/enums/actions';
import {Signal} from '@angular/core';
import {EditorFile} from '../code-mirror-editor.service';
import type {EditorFile} from '../code-mirror-editor.service';
import {ActionMessage} from '../workers/interfaces/message';
import {DiagnosticsRequest} from '../workers/interfaces/diagnostics-request';
import {Subject, filter, take} from 'rxjs';
@@ -13,7 +13,7 @@ import {Subject, filter, take} from 'rxjs';
import ts from 'typescript';
import {EditorFile} from '../code-mirror-editor.service';
import type {EditorFile} from '../code-mirror-editor.service';
import {TsVfsWorkerActions} from '../workers/enums/actions';
import {DisplayTooltipRequest} from '../workers/interfaces/display-tooltip-request';
import {DisplayTooltipResponse} from '../workers/interfaces/display-tooltip-response';
@@ -0,0 +1,10 @@
/*!
* @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
*/
export const DEV_SERVER_READY_MSG = 'Watch mode enabled. Watching for file changes...';
export const OUT_OF_MEMORY_MSG = 'Out of memory';
@@ -15,15 +15,11 @@ import {FakeWebContainer, FakeWebContainerProcess, TutorialType} from '@angular/
import {AlertManager} from './alert-manager.service';
import {EmbeddedTutorialManager} from './embedded-tutorial-manager.service';
import {LoadingStep} from './enums/loading-steps';
import {
DEV_SERVER_READY_MSG,
NodeRuntimeSandbox,
OUT_OF_MEMORY_MSG,
PACKAGE_MANAGER,
} from './node-runtime-sandbox.service';
import {NodeRuntimeSandbox, PACKAGE_MANAGER} from './node-runtime-sandbox.service';
import {NodeRuntimeState} from './node-runtime-state.service';
import {TerminalHandler} from './terminal/terminal-handler.service';
import {TypingsLoader} from './typings-loader.service';
import {DEV_SERVER_READY_MSG, OUT_OF_MEMORY_MSG} from './node-runtime-errors';
describe('NodeRuntimeSandbox', () => {
let testBed: TestBed;
@@ -19,9 +19,7 @@ import {LoadingStep} from './enums/loading-steps';
import {ErrorType, NodeRuntimeState} from './node-runtime-state.service';
import {TerminalHandler} from './terminal/terminal-handler.service';
import {TypingsLoader} from './typings-loader.service';
export const DEV_SERVER_READY_MSG = 'Watch mode enabled. Watching for file changes...';
export const OUT_OF_MEMORY_MSG = 'Out of memory';
import {DEV_SERVER_READY_MSG, OUT_OF_MEMORY_MSG} from './node-runtime-errors';
const enum PROCESS_EXIT_CODE {
SUCCESS = 0, // process exited successfully
@@ -9,7 +9,7 @@
import {TestBed} from '@angular/core/testing';
import {ErrorType, NodeRuntimeState} from './node-runtime-state.service';
import {OUT_OF_MEMORY_MSG} from './node-runtime-sandbox.service';
import {OUT_OF_MEMORY_MSG} from './node-runtime-errors';
describe('NodeRuntimeState', () => {
let service: NodeRuntimeState;
@@ -7,10 +7,10 @@
*/
import {Injectable, signal} from '@angular/core';
import {isFirefox, isIos} from '@angular/docs';
import {isIos} from '@angular/docs';
import {LoadingStep} from './enums/loading-steps';
import {OUT_OF_MEMORY_MSG} from './node-runtime-sandbox.service';
import {OUT_OF_MEMORY_MSG} from './node-runtime-errors';
export const MAX_RECOMMENDED_WEBCONTAINERS_INSTANCES = 3;
export const WEBCONTAINERS_COUNTER_KEY = 'numberOfWebcontainers';
@@ -1,8 +1,7 @@
@let docContent = this.docContent();
@if (docContent) {
<docs-viewer
<main docsViewer
class="docs-viewer"
[docContent]="docContent.contents"
[hasToc]="true"
/>
[hasToc]="true"></main>
}
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.dev/license
*/
import {Animation} from '../animation';
import type {Animation} from '../animation';
/**
* Animation plugin interface.
@@ -1,9 +1,9 @@
@if (docContent(); as docContent) {
<docs-viewer
<main docsViewer
[docContent]="docContent.contents"
[hasToc]="true"
(contentLoaded)="onContentLoaded()"
/>
></main>
}
<div id="jump-msg" class="cdk-visually-hidden">Jump to details</div>
@@ -10,19 +10,19 @@
padding-bottom: var(--layout-padding);
//applying styles when TOC position got translated to the top right
//applying styles when TOC position got translated to the top right
@include mq.for-large-desktop-up {
// take the available space except a reserved area for TOC
width: calc(100% - 16rem);
}
docs-viewer {
main {
display: block;
padding-inline: var(--layout-padding);
width: 100%;
//applying styles when TOC position got translated to the top right
//applying styles when TOC position got translated to the top right
@include mq.for-large-desktop-up {
// take the available space except a reserved area for TOC
max-width: var(--page-width);
@@ -74,4 +74,4 @@
::ng-deep {
@include ref.reference-common();
@include ref.api-reference();
}
}
@@ -64,7 +64,7 @@ describe('ApiReferenceDetailsPage', () => {
it('should load the doc content', () => {
expect(component.docContent()?.contents).toBeTruthy();
const docsViewer = fixture.nativeElement.querySelector('docs-viewer');
const docsViewer = fixture.nativeElement.querySelector('main');
expect(docsViewer).toBeTruthy();
});
});
@@ -1,5 +1,5 @@
@if (docContent(); as docContent) {
<docs-viewer [docContent]="docContent.contents" [hasToc]="true" />
<main docsViewer [docContent]="docContent.contents" [hasToc]="true"></main>
}
<div id="jump-msg" class="cdk-visually-hidden">Jump to details</div>
@@ -11,19 +11,19 @@
//applying styles when TOC position got translated to the top right
//applying styles when TOC position got translated to the top right
@include mq.for-large-desktop-up{
// take the available space except a reserved area for TOC
width: calc(100% - 16rem);
}
docs-viewer {
main {
display: block;
padding-inline: var(--layout-padding);
width: 100%;
//applying styles when TOC position got translated to the top right
//applying styles when TOC position got translated to the top right
@include mq.for-large-desktop-up{
// take the available space except a reserved area for TOC
max-width: var(--page-width);
@@ -44,4 +44,4 @@
::ng-deep {
@include ref.reference-common();
@include ref.cli-reference();
}
}
@@ -64,7 +64,7 @@ describe('CliReferenceDetailsPage', () => {
it('should load the doc content', () => {
expect(component.docContent()?.contents).toBeTruthy();
const docsViewer = fixture.nativeElement.querySelector('docs-viewer');
const docsViewer = fixture.nativeElement.querySelector('main');
expect(docsViewer).toBeTruthy();
});
});
@@ -7,10 +7,9 @@
<!-- Tutorial Content -->
@if (documentContent(); as documentContent) {
<docs-viewer
<main docsViewer
[docContent]="documentContent"
class="docs-viewer docs-viewer-scroll-margin-large"
/>
class="docs-viewer docs-viewer-scroll-margin-large"></main>
}
</div>
}
@@ -1032,7 +1032,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Advanced,
step: 'viewencapsulation native removed',
action:
'The component view encapsulation option `ViewEncapsulation.Native` has been removed. Use `ViewEncapsulation.ShadowDom` or `ViewEncapsulation.IsolatedShadowDom` instead. `ng update` will migrate you automatically.',
'The component view encapsulation option `ViewEncapsulation.Native` has been removed. Use `ViewEncapsulation.ShadowDom` instead. `ng update` will migrate you automatically.',
},
{
possibleIn: 1100,
+2 -2
View File
@@ -106,7 +106,7 @@ const initializeNavigationAdapter = () => {
return;
}
clearNavigation = undefined;
router.getCurrentNavigation()?.abort();
router.currentNavigation()?.abort();
});
navigation.addEventListener('navigate', (navigateEvent) => {
if (!intercept) {
@@ -127,7 +127,7 @@ const initializeNavigationAdapter = () => {
// Skip this for popstate/traversals that are already committed.
// The rollback is problematic so we only do it for navigations that
// defer the actual update (pushState) on the browser.
const currentNavigation = router.getCurrentNavigation();
const currentNavigation = router.currentNavigation();
if (currentNavigation?.trigger === 'popstate' || currentNavigation?.extras.replaceUrl) {
return;
}
+32
View File
@@ -388,6 +388,12 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
path: 'guide/routing/routing-with-urlmatcher',
contentPath: 'guide/routing/routing-with-urlmatcher',
},
{
label: 'Rendering strategies',
path: 'guide/routing/rendering-strategies',
contentPath: 'guide/routing/rendering-strategies',
status: 'new',
},
{
label: 'Router reference',
path: 'guide/routing/router-reference',
@@ -533,6 +539,12 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
path: 'guide/testing/pipes',
contentPath: 'guide/testing/pipes',
},
{
label: 'Testing routing and navigation',
path: 'guide/routing/testing',
contentPath: 'guide/routing/testing',
status: 'new',
},
{
label: 'Debugging tests',
path: 'guide/testing/debugging',
@@ -673,6 +685,11 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
path: 'ai/develop-with-ai',
contentPath: 'ai/develop-with-ai',
},
{
label: 'Design Patterns',
path: 'ai/design-patterns',
contentPath: 'ai/design-patterns',
},
{
label: 'Angular CLI MCP Server setup',
path: 'ai/mcp',
@@ -940,6 +957,11 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
path: 'ecosystem/rxjs-interop/output-interop',
contentPath: 'ecosystem/rxjs-interop/output-interop',
},
{
label: 'Unsubscribing with takeUntilDestroyed',
path: 'ecosystem/rxjs-interop/take-until-destroyed',
contentPath: 'ecosystem/rxjs-interop/take-until-destroyed',
},
],
},
{
@@ -992,6 +1014,12 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
path: 'ecosystem/custom-build-pipeline',
contentPath: 'ecosystem/custom-build-pipeline',
},
{
label: 'Tailwind',
path: 'guide/tailwind',
contentPath: 'guide/tailwind',
status: 'new',
},
{
label: 'Angular Fire',
path: 'https://github.com/angular/angularfire#readme',
@@ -1153,6 +1181,10 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [
label: 'Overview',
path: 'cli/generate',
},
{
label: 'ai-config',
path: 'cli/generate/ai-config',
},
{
label: 'app-shell',
path: 'cli/generate/app-shell',
+172
View File
@@ -0,0 +1,172 @@
# Design patterns for AI SDKs and signal APIs
Interacting with AI and Large Language Model (LLM) APIs introduces unique challenges, such as managing asynchronous operations, handling streaming data, and designing a responsive user experience for potentially slow or unreliable network requests. Angular [signals](guide/signals) and the [`resource`](guide/signals/resource) API provide powerful tools to solve these problems elegantly.
## Triggering requests with signals
A common pattern when working with user-provided prompts is to separate the user's live input from the submitted value that triggers the API call.
1. Store the user's raw input in one signal as they type
2. When the user submits (e.g., by clicking a button), update a second signal with contents of the first signal.
3. Use the second signal in the **`params`** field of your `resource`.
This setup ensures the resource's **`loader`** function only runs when the user explicitly submits their prompt, not on every keystroke. You can use additional signal parameters, like a `sessionId` or `userId` (which can be useful for creating persistent LLM sessions), in the `loader` field. This way, the request always uses these parameters' current values without re-triggering the asyncronous function defined in the `loader` field.
Many AI SDKs provide helper methods for making API calls. For example, the Genkit client library exposes a `runFlow` method for calling Genkit flows, which you can call from a resource's `loader`. For other APIs, you can use the [`httpResource`](guide/signals/resource#reactive-data-fetching-with-httpresource).
The following example shows a `resource` that fetches parts of an AI-generated story. The `loader` is triggered only when the `storyInput` signal changes.
```ts
// A resource that fetches three parts of an AI generated story
storyResource = resource({
// The default value to use before the first request or on error
defaultValue: DEFAULT_STORY,
// The loader is re-triggered when this signal changes
params: () => this.storyInput(),
// The async function to fetch data
loader: ({params}): Promise<StoryData> => {
// The params value is the current value of the storyInput signal
const url = this.endpoint();
return runFlow({ url, input: {
userInput: params,
sessionId: this.storyService.sessionId() // Read from another signal
}});
}
});
```
## Preparing LLM data for templates
You can configure LLM APIs to return structured data. Strongly typing your `resource` to match the expected output from the LLM provides better type safety and editor autocompletion.
To manage state derived from a resource, use a `computed` signal or `linkedSignal`. Because `linkedSignal` [provides access to prior values](guide/signals/linked-signal), it can serve a variety of AI-related use cases, including
* building a chat history
* preserving or customizing data that templates display while LLMs generate content
In the example below, `storyParts` is a `linkedSignal` that appends the latest story parts returned from `storyResource` to the existing array of story parts.
```ts
storyParts = linkedSignal<string[], string[]>({
// The source signal that triggers the computation
source: () => this.storyResource.value().storyParts,
// The computation function
computation: (newStoryParts, previous) => {
// Get the previous value of this linkedSignal, or an empty array
const existingStoryParts = previous?.value || [];
// Return a new array with the old and new parts
return [...existingStoryParts, ...newStoryParts];
}
});
```
## Performance and user experience
LLM APIs may be slower and more error-prone than conventional, more deterministic APIs. You can use several Angular features to build a performant and user-friendly interface.
* **Scoped Loading:** place the `resource` in the component that directly uses the data. This helps limit change detection cycles (especially in zoneless applications) and prevents blocking other parts of your application. If data needs to be shared across multiple components, provide the `resource` from a service.
* **SSR and Hydration:** use Server-Side Rendering (SSR) with incremental hydration to render the initial page content quickly. You can show a placeholder for the AI-generated content and defer fetching the data until the component hydrates on the client.
* **Loading State:** use the `resource` `LOADING` [status](guide/signals/resource#resource-status) to show an indicator, like a spinner, while the request is in flight. This status covers both initial loads and reloads.
* **Error Handling and Retries:** use the `resource` [**`reload()`**](guide/signals/resource#reloading) method as a simple way for users to retry failed requests, may be more prevalent when relying on AI generated content.
The following example demonstrates how to create a responsive UI to dynamically display an AI generated image with loading and retry functionality.
```angular-html
<!-- Display a loading spinner while the LLM generates the image -->
@if (imgResource.isLoading()) {
<div class="img-placeholder">
<mat-spinner [diameter]="50" />
</div>
<!-- Dynamically populates the src attribute with the generated image URL -->
} @else if (imgResource.hasValue()) {
<img [src]="imgResource.value()" />
<!-- Provides a retry option if the request fails -->
} @else {
<div class="img-placeholder" (click)="imgResource.reload()">
<mat-icon fontIcon="refresh" />
<p>Failed to load image. Click to retry.</p>
</div>
}
```
## AI patterns in action: streaming chat responses
Interfaces often display partial results from LLM-based APIs incrementally as response data arrives. Angular's resource API provides the ability to stream responses to support this type of pattern. The `stream` property of `resource` accepts an asyncronous function you can use to apply updates to a signal value over time. The signal being updated represents the data being streamed.
```ts
characters = resource({
stream: async () => {
const data = signal<ResourceStreamItem<string>>({value: ''});
// Calls a Genkit streaming flow using the streamFlow method
// expose by the Genkit client SDK
const response = streamFlow({
url: '/streamCharacters',
input: 10
});
(async () => {
for await (const chunk of response.stream) {
data.update((prev) => {
if ('value' in prev) {
return { value: `${prev.value} ${chunk}` };
} else {
return { error: chunk as unknown as Error };
}
});
}
})();
return data;
}
});
```
The `characters` member is updated asynchronously and can be displayed in the template.
```angular-html
@if (characters.isLoading()) {
<p>Loading...</p>
} @else if (characters.hasValue()) {
<p>{{characters.value()}}</p>
} @else {
<p>{{characters.error()}}</p>
}
```
On the server side, in `server.ts` for example, the defined endpoint sends the data to be streamed to the client. The following code uses Gemini with the Genkit framework but this technique is applicable to other APIs that support streaming responses from LLMs:
```ts
import { startFlowServer } from '@genkit-ai/express';
import { genkit } from "genkit/beta";
import { googleAI, gemini20Flash } from "@genkit-ai/googleai";
const ai = genkit({ plugins: [googleAI()] });
export const streamCharacters = ai.defineFlow({
name: 'streamCharacters',
inputSchema: z.number(),
outputSchema: z.string(),
streamSchema: z.string(),
},
async (count, { sendChunk }) => {
const { response, stream } = ai.generateStream({
model: gemini20Flash,
config: {
temperature: 1,
},
prompt: `Generate ${count} different RPG game characters.`,
});
(async () => {
for await (const chunk of stream) {
sendChunk(chunk.content[0].text!);
}
})();
return (await response).text;
});
startFlowServer({
flows: [streamCharacters],
});
```
+78 -32
View File
@@ -1,4 +1,5 @@
# Angular CLI MCP Server setup
The Angular CLI includes an experimental [Model Context Protocol (MCP) server](https://modelcontextprotocol.io/) enabling AI assistants in your development environment to interact with the Angular CLI. We've included support for CLI powered code generation, adding packages, and more.
To get started, run the following command in your terminal:
@@ -7,23 +8,55 @@ To get started, run the following command in your terminal:
ng mcp
```
Use this command to create the base JSON configuration for your environment. Note that the file structure differs depending on your IDE. The following sections provide the configurations for several popular editors.
When run from an interactive terminal, this command displays instructions on how to configure a host environment to use the MCP server. The following sections provide example configurations for several popular editors and tools.
### VS Code
In your project's root, create a file named `.vscode/mcp.json` and add the following configuration. Note the use of the `servers` property.
### Cursor
Create a file named `.cursor/mcp.json` in your project's root and add the following configuration. You can also configure it globally in `~/.cursor/mcp.json`.
```json
{
"servers": {
"mcpServers": {
"angular-cli": {
"command": "npx",
"args": ["@angular/cli", "mcp"]
"args": ["-y", "@angular/cli", "mcp"]
}
}
}
```
### Firebase Studio
Create a file named `.idx/mcp.json` in your project's root and add the following configuration:
```json
{
"mcpServers": {
"angular-cli": {
"command": "npx",
"args": ["-y", "@angular/cli", "mcp"]
}
}
}
```
### Gemini CLI
Create a file named `.gemini/settings.json` in your project's root and add the following configuration:
```json
{
"mcpServers": {
"angular-cli": {
"command": "npx",
"args": ["-y", "@angular/cli", "mcp"]
}
}
}
```
### JetBrains IDEs
In JetBrains IDEs (like IntelliJ IDEA or WebStorm), after installing the JetBrains AI Assistant plugin, go to `Settings | Tools | AI Assistant | Model Context Protocol (MCP)`. Add a new server and select `As JSON`. Paste the following configuration, which does not use a top-level property for the server list.
```json
@@ -31,36 +64,61 @@ In JetBrains IDEs (like IntelliJ IDEA or WebStorm), after installing the JetBrai
"name": "Angular CLI",
"command": "npx",
"args": [
"-y",
"@angular/cli",
"mcp"
]
}
```
### Firebase Studio
Create a file named `.idx/mcp.json` in your project's root and add the following configuration:
### VS Code
In your project's root, create a file named `.vscode/mcp.json` and add the following configuration. Note the use of the `servers` property.
```json
{
"mcpServers": {
"servers": {
"angular-cli": {
"command": "npx",
"args": ["@angular/cli", "mcp"]
"args": ["-y", "@angular/cli", "mcp"]
}
}
}
```
### Other IDEs
For these IDEs, create a configuration file and add the following snippet. Note the use of the `mcpServers` property.
* **Cursor:** Create a file named `.cursor/mcp.json` in your project's root. You can also configure it globally in `~/.cursor/mcp.json`.
* **Other IDEs:** Check your IDE's documentation for the proper location of the MCP configuration file (often `mcp.json`).
For other IDEs, check your IDE's documentation for the proper location of the MCP configuration file (often `mcp.json`). The configuration should contain the following snippet.
```json
{
"mcpServers": {
"angular-cli": {
"command": "npx",
"args": ["@angular/cli", "mcp"]
"args": ["-y", "@angular/cli", "mcp"]
}
}
}
```
## Command Options
The `mcp` command can be configured with the following options passed as arguments in your IDE's MCP configuration:
| Option | Type | Description | Default |
| :------------- | :-------- | :--------------------------------------------------------------------------------------------------------- | :------ |
| `--read-only` | `boolean` | Only register tools that do not make changes to the project. Your editor or coding agent may still perform edits. | `false` |
| `--local-only` | `boolean` | Only register tools that do not require an internet connection. Your editor or coding agent may still send data over the network. | `false` |
For example, to run the server in read-only mode in VS Code, you would update your `mcp.json` like this:
```json
{
"servers": {
"angular-cli": {
"command": "npx",
"args": ["-y", "@angular/cli", "mcp", "--read-only"]
}
}
}
@@ -68,26 +126,14 @@ For these IDEs, create a configuration file and add the following snippet. Note
## Available Tools
The Angular CLI MCP server provides several tools to assist you in your development workflow. Here's an overview of the available tools:
The Angular CLI MCP server provides several tools to assist you in your development workflow. By default, the following tools are enabled:
### Get Angular Coding Best Practices Guide (`get_best_practices`)
This tool provides a guide on modern Angular coding best practices. Before you start writing or modifying code, you can use this tool to ensure your work aligns with current standards, such as using standalone components, typed forms, and the latest control flow syntax.
* **Outputs:** The content of the best practices guide.
### Search Angular Documentation (`search_documentation`)
This tool allows you to search the official Angular documentation at [angular.dev](https://angular.dev). It's the recommended way to find up-to-date information on Angular APIs, tutorials, and guides.
* **Outputs:** A list of search results, including title, breadcrumbs, and URL. May also include the content of the top-ranked page.
### List Angular Projects (`list_projects`)
This tool lists all the applications and libraries in your current Angular workspace. It reads the `angular.json` file to identify and provide details about each project.
* **Outputs:** A list of project objects, with details for each project like its name, type (`application` or `library`), root directory, and component selector prefix.
| Name | Description | `local-only` | `read-only` |
| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------: | :---------: |
| `get_best_practices` | Retrieves the Angular Best Practices Guide. This guide is essential for ensuring that all code adheres to modern standards, including standalone components, typed forms, and modern control flow. | ✅ | ✅ |
| `list_projects` | Lists the names of all applications and libraries defined within an Angular workspace. It reads the `angular.json` configuration file to identify the projects. | ✅ | ✅ |
| `search_documentation` | Searches the official Angular documentation at https://angular.dev. This tool should be used to answer any questions about Angular, such as for APIs, tutorials, and best practices. | ❌ | ✅ |
## Feedback and New Ideas
The Angular team welcomes your feedback on the existing MCP capabilities and any ideas you have for new tools or features. Please share your thoughts by opening an issue on the [angular/angular GitHub repository](https://github.com/angular/angular/issues).
The Angular team welcomes your feedback on the existing MCP capabilities and any ideas you have for new tools or features. Please share your thoughts by opening an issue on the [angular/angular GitHub repository](https://github.com/angular/angular/issues).
-54
View File
@@ -60,60 +60,6 @@ The [Gemini API](https://ai.google.dev/gemini-api/docs) provides access to state
* [AI Chatbot app template](https://github.com/FirebaseExtended/firebase-framework-tools/tree/main/starters/angular/ai-chatbot) - This template starts with a chatbot user interface that communicates with the Gemini API via HTTP.
## AI patterns in action: Streaming chat responses
Having text appear as the response is received from the model is a common UI pattern for web apps using AI. You can achieve this asynchronous task with Angular's `resource` API. The `stream` property of `resource` accepts an asynchronous function you can use to apply updates to a signal value over time. The signal being updated represents the data being streamed.
```ts
characters = resource({
stream: async () => {
const data = signal<{ value: string } | { error: unknown }>({
value: "",
});
fetch(this.url).then(async (response) => {
if (!response.body) return;
for await (const chunk of response.body) {
const chunkText = this.decoder.decode(chunk);
data.update((prev) => {
if ("value" in prev) {
return { value: `${prev.value} ${chunkText}` };
} else {
return { error: chunkText };
}
});
}
});
return data;
},
});
```
The `characters` member is updated asynchronously and can be displayed in the template.
```html
<p>{{ characters.value() }}</p>
```
On the server side, in `server.ts` for example, the defined endpoint sends the data to be streamed to the client. The following code uses the Gemini API but this technique is applicable to other tools and frameworks that support streaming responses from LLMs:
```ts
app.get("/api/stream-response", async (req, res) => {
ai.models.generateContentStream({
model: "gemini-2.0-flash",
contents: "Explain how AI works",
}).then(async (response) => {
for await (const chunk of response) {
res.write(chunk.text);
}
});
});
```
This example connects to the Gemini API but other APIs that support streaming responses can be used here as well. [You can find the complete example on the Angular Github](https://github.com/angular/examples/tree/main/streaming-example).
## Best Practices
### Connecting to model providers and keeping your API Credentials Secure
When connecting to model providers, it is important to keep your API secrets safe. *Never put your API key in a file that ships to the client, such as `environments.ts`*.
+2 -2
View File
@@ -1,4 +1,4 @@
{
"branchName": "refs/heads/main",
"sha": "0a154078b28bfd4254c6ad7a25a232032ac404fb"
"branchName": "refs/heads/20.2.x",
"sha": "d90448f54816b8be9343ecaefd948aba5dc9ba98"
}
+9 -9
View File
@@ -59,8 +59,8 @@
"type": "string",
"default": "none",
"enum": [
"none",
"anonymous",
"none",
"use-credentials"
],
"description": "Define the crossorigin attribute setting of elements that provide CORS support."
@@ -102,9 +102,9 @@
"type": "string",
"default": "warning",
"enum": [
"warning",
"error",
"ignore"
"ignore",
"warning"
],
"description": "How to handle duplicate translations for i18n."
},
@@ -113,9 +113,9 @@
"type": "string",
"default": "warning",
"enum": [
"warning",
"error",
"ignore"
"ignore",
"warning"
],
"description": "How to handle missing translations for i18n."
},
@@ -158,10 +158,10 @@
"type": "string",
"default": "none",
"enum": [
"none",
"all",
"bundles",
"media",
"bundles"
"none"
],
"description": "Define the output filename cache-busting hashing mode."
},
@@ -169,8 +169,8 @@
"name": "output-mode",
"type": "string",
"enum": [
"static",
"server"
"server",
"static"
],
"description": "Defines the build output target. 'static': Generates a static site for deployment on any static hosting service. 'server': Produces an application designed for deployment on a server that supports server-side rendering (SSR)."
},
+7 -7
View File
@@ -23,15 +23,15 @@
"type": "string",
"default": "xlf",
"enum": [
"xmb",
"arb",
"json",
"legacy-migrate",
"xlf",
"xlf2",
"xlif",
"xliff",
"xlf2",
"xliff2",
"json",
"arb",
"legacy-migrate"
"xmb"
],
"description": "Output format for the generated file."
},
@@ -45,8 +45,8 @@
"type": "string",
"enum": [
"error",
"warning",
"ignore"
"ignore",
"warning"
],
"description": "How to handle duplicate translations."
},
+38 -8
View File
@@ -47,6 +47,30 @@
}
],
"subcommands": [
{
"name": "ai-config",
"command": "ai-config",
"shortDescription": "Generates AI configuration files for Angular projects. This schematic creates configuration files that help AI tools follow Angular best practices, improving the quality of AI-generated code and suggestions.",
"options": [
{
"name": "tool",
"type": "array",
"default": "none",
"enum": [
"claude",
"copilot",
"cursor",
"gemini",
"jetbrains",
"none",
"windsurf"
],
"description": "Specifies which AI tools to generate configuration files for. These file are used to improve the outputs of AI tools by following the best practices."
}
],
"aliases": [],
"deprecated": false
},
{
"name": "app-shell",
"command": "app-shell",
@@ -159,9 +183,9 @@
"default": "css",
"enum": [
"css",
"scss",
"less",
"sass",
"less"
"scss"
],
"description": "The type of stylesheet files to be created for components in the application."
},
@@ -351,10 +375,10 @@
"default": "css",
"enum": [
"css",
"scss",
"sass",
"less",
"none"
"none",
"sass",
"scss"
],
"description": "Specify the type of stylesheet to be created for the component, or `none` to skip creating a stylesheet."
},
@@ -396,8 +420,8 @@
"name": "type",
"type": "string",
"enum": [
"karma",
"browserslist"
"browserslist",
"karma"
],
"description": "Specifies the type of configuration file to generate.",
"positional": 0
@@ -548,6 +572,12 @@
"aliases": [
"guardType"
],
"enum": [
"CanActivate",
"CanActivateChild",
"CanDeactivate",
"CanMatch"
],
"description": "Specifies the type(s) of guard to create. You can choose one or more of the following: `CanActivate` (controls access to a route), `CanActivateChild` (controls access to child routes), `CanDeactivate` (asks for confirmation before leaving a route), `CanMatch` (determines if a route can be matched)."
},
{
@@ -998,4 +1028,4 @@
"deprecated": false
}
]
}
}
+21 -8
View File
@@ -9,6 +9,20 @@
],
"deprecated": false,
"options": [
{
"name": "ai-config",
"type": "array",
"enum": [
"claude",
"copilot",
"cursor",
"gemini",
"jetbrains",
"none",
"windsurf"
],
"description": "Specifies which AI tools to generate configuration files for. These file are used to improve the outputs of AI tools by following the best practices."
},
{
"name": "collection",
"type": "string",
@@ -104,11 +118,11 @@
"name": "package-manager",
"type": "string",
"enum": [
"npm",
"yarn",
"pnpm",
"bun",
"cnpm",
"bun"
"npm",
"pnpm",
"yarn"
],
"description": "The package manager used to install dependencies."
},
@@ -172,9 +186,9 @@
"type": "string",
"enum": [
"css",
"scss",
"less",
"sass",
"less"
"scss"
],
"description": "The type of stylesheet files to be created for components in the initial project."
},
@@ -191,8 +205,7 @@
{
"name": "zoneless",
"type": "boolean",
"default": false,
"description": "Create an initial application that does not utilize `zone.js`."
}
]
}
}
@@ -69,7 +69,7 @@ Use the `toObservable` utility to create an `Observable` which tracks the value
import { Component, signal } from '@angular/core';
import { toObservable } from '@angular/core/rxjs-interop';
@Component(...)
@Component(/* ... */)
export class SearchResults {
query: Signal<string> = inject(QueryService).query;
query$ = toObservable(this.query);
@@ -102,3 +102,34 @@ mySignal.set(3);
```
Here, only the last value (3) will be logged.
## Using `rxResource` for async data
IMPORTANT: `rxResource` is [experimental](reference/releases#experimental). It's ready for you to try, but it might change before it is stable.
Angular's [`resource` function](/guide/signals/resource) gives you a way to incorporate async data into your application's signal-based code. Building on top of this pattern, `rxResource` lets you define a resource where the source of your data is defined in terms of an RxJS `Observable`. Instead of accepting a `loader` function, `rxResource` accepts a `stream` function that accepts an RxJS `Observable`.
```typescript
import {Component, inject} from '@angular/core';
import {rxResource} from '@angular/core/rxjs-interop';
@Component(/* ... */)
export class UserProfile {
// This component relies on a service that exposes data through an RxJS Observable.
private userData = inject(MyUserDataClient);
protected userId = input<string>();
private userResource = rxResource({
params: () => this.userId(),
// The `stream` property expects a factory function that returns
// a data stream as an RxJS Observable.
stream: ({userId}) => this.userData.load(userId),
});
}
```
The `stream` property accepts a factory function for an RxJS `Observable`. This factory function is passed the resource's `params` value and returns an `Observable`. The resource calls this factory function every time the `params` computation produces a new value. See [Resource loaders](/guide/signals/resource#resource-loaders) for more details on the parameters passed to the factory function.
In all other ways, `rxResource` behaves like and provides the same APIs as `resource` for specifying parameters, reading values, checking loading state, and examining errors.
@@ -0,0 +1,46 @@
# Unsubscribing with `takeUntilDestroyed`
TIP: This guide assumes you're familiar with [component and directive lifecycle](guide/components/lifecycle).
The `takeUntilDestroyed` operator, from `@angular/core/rxjs-interop`, provides a concise and reliable way to automatically unsubscribe from an Observable when a component or directive is destroyed. This prevents common memory leaks with RxJS subscriptions. It works similarly to the RxJS [`takeUntil`](https://rxjs.dev/api/operators/takeUntil) operator but without the need for a separate Subject.
```typescript
import {Component, inject} from '@angular/core';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {NotificationDispatcher, CustomPopupShower} from './some-shared-project-code';
@Component(/* ... */)
export class UserProfile {
private dispatcher = inject(NotificationDispatcher);
private popup = inject(CustomPopupShower);
constructor() {
// This subscription the 'notifications' Observable is automatically
// unsubscribed when the 'UserProfile' component is destroyed.
const messages: Observable<string> = this.dispatcher.notifications;
messages.pipe(takeUntilDestroyed()).subscribe(message => {
this.popup.show(message);
});
}
}
```
The `takeUntilDestroyed` operator accepts a single optional [`DestroyRef`](https://angular.dev/api/core/DestroyRef) argument. The operator uses `DestroyRef` to know when the component or directive has been destroyed. You can omit this argument when calling `takeUntilDestroyed` in an [injection context](https://angular.dev/guide/di/dependency-injection-context), typically the constructor of a component or directive. Always provide a `DestroyRef` if your code may call `takeUntilDestroyed` outside of an injection context.
```typescript
@Component(/* ... */)
export class UserProfile {
private dispatcher = inject(NotificationDispatcher);
private popup = inject(CustomPopupShower);
private destroyRef = inject(DestroyRef);
startListeningToNotifications() {
// Always pass a `DestroyRef` if you call `takeUntilDestroyed` outside
// of an injection context.
const messages: Observable<string> = this.dispatcher.notifications;
messages.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(message => {
this.popup.show(message);
});
}
}
```
@@ -7,7 +7,6 @@
border: 1px solid #dddddd;
margin-top: 1em;
padding: 20px 20px 0px 20px;
color: #000000;
font-weight: bold;
font-size: 20px;
}
@@ -7,7 +7,6 @@
border: 1px solid #dddddd;
margin-top: 1em;
padding: 20px 20px 0px 20px;
color: #000000;
font-weight: bold;
font-size: 20px;
}
@@ -7,7 +7,6 @@
border: 1px solid #dddddd;
margin-top: 1em;
padding: 20px 20px 0px 20px;
color: #000000;
font-weight: bold;
font-size: 20px;
opacity: 1;
@@ -7,7 +7,6 @@
border: 1px solid #dddddd;
margin-top: 1em;
padding: 20px 20px 0px 20px;
color: #000000;
font-weight: bold;
font-size: 20px;
opacity: 1;
@@ -7,7 +7,6 @@
border: 1px solid #dddddd;
margin-top: 1em;
padding: 20px 20px 0px 20px;
color: #000000;
font-weight: bold;
font-size: 20px;
opacity: 1;
@@ -6,7 +6,6 @@
border: 1px solid #dddddd;
margin-top: 1em;
padding: 20px 20px 0px 20px;
color: #000000;
font-weight: bold;
font-size: 20px;
}
@@ -6,7 +6,6 @@
border: 1px solid #dddddd;
margin-top: 1em;
padding: 20px 20px 0px 20px;
color: #000000;
font-weight: bold;
font-size: 20px;
opacity: 1;
@@ -1,10 +0,0 @@
import {Component, inject} from '@angular/core';
import {ParentComponent} from './parent.component';
@Component({
selector: 'app-child',
template: 'The child!',
})
export class ChildComponent {
private parent = inject(ParentComponent);
}
@@ -1,9 +0,0 @@
import {Component} from '@angular/core';
import {ChildComponent} from './child.component';
@Component({
selector: 'app-parent',
imports: [ChildComponent],
template: '<app-child/>',
})
export class ParentComponent {}
@@ -1,5 +1,5 @@
// #docregion
import {Directive, input} from '@angular/core';
import {Directive, forwardRef, input} from '@angular/core';
import {
AbstractControl,
NG_VALIDATORS,
@@ -22,7 +22,13 @@ export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
@Directive({
selector: '[appForbiddenName]',
// #docregion directive-providers
providers: [{provide: NG_VALIDATORS, useExisting: ForbiddenValidatorDirective, multi: true}],
providers: [
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => ForbiddenValidatorDirective),
multi: true,
},
],
})
export class ForbiddenValidatorDirective implements Validator {
forbiddenName = input<string>('', {alias: 'appForbiddenName'});
@@ -1,5 +1,5 @@
// #docregion
import {Directive} from '@angular/core';
import {Directive, forwardRef} from '@angular/core';
import {
AbstractControl,
NG_VALIDATORS,
@@ -24,7 +24,11 @@ export const unambiguousRoleValidator: ValidatorFn = (
@Directive({
selector: '[appUnambiguousRole]',
providers: [
{provide: NG_VALIDATORS, useExisting: UnambiguousRoleValidatorDirective, multi: true},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => UnambiguousRoleValidatorDirective),
multi: true,
},
],
})
export class UnambiguousRoleValidatorDirective implements Validator {
@@ -1,5 +1,5 @@
// #docregion
import {Directive} from '@angular/core';
import {Directive, forwardRef} from '@angular/core';
import {
AbstractControl,
NG_VALIDATORS,
@@ -24,7 +24,11 @@ export const unambiguousRoleValidator: ValidatorFn = (
@Directive({
selector: '[appUnambiguousRole]',
providers: [
{provide: NG_VALIDATORS, useExisting: UnambiguousRoleValidatorDirective, multi: true},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => UnambiguousRoleValidatorDirective),
multi: true,
},
],
})
export class UnambiguousRoleValidatorDirective implements Validator {
@@ -28,7 +28,6 @@ describe('AppComponent & router testing', () => {
Object.assign({}, appConfig, {
providers: [
{provide: HeroService, useClass: TestHeroService},
UserService,
TwainService,
provideHttpClient(),
provideLocationMocks(),
@@ -1,12 +1,13 @@
// #docplaster
import {Component, DebugElement, NO_ERRORS_SCHEMA} from '@angular/core';
import {ComponentFixture, fakeAsync, TestBed, tick, waitForAsync} from '@angular/core/testing';
import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
import {By} from '@angular/platform-browser';
import {provideRouter, Router, RouterLink} from '@angular/router';
import {provideRouter, Router, RouterLink, RouterOutlet} from '@angular/router';
import {AppComponent} from './app.component';
import {appConfig} from './app.config';
import {UserService} from './model';
import {WelcomeComponent} from './welcome/welcome.component';
// #docregion component-stubs
@Component({selector: 'app-banner', template: ''})
@@ -23,54 +24,67 @@ let comp: AppComponent;
let fixture: ComponentFixture<AppComponent>;
describe('AppComponent & TestModule', () => {
beforeEach(waitForAsync(() => {
beforeEach(() => {
// #docregion testbed-stubs
TestBed.configureTestingModule(
Object.assign({}, appConfig, {
imports: [
AppComponent,
BannerStubComponent,
RouterLink,
RouterOutletStubComponent,
WelcomeStubComponent,
],
providers: [provideRouter([]), UserService],
}),
)
// #enddocregion testbed-stubs
).overrideComponent(AppComponent, {
set: {
imports: [BannerStubComponent, RouterLink, RouterOutletStubComponent, WelcomeStubComponent],
},
});
// #enddocregion testbed-stubs
.then(() => {
fixture = TestBed.createComponent(AppComponent);
comp = fixture.componentInstance;
});
}));
fixture = TestBed.createComponent(AppComponent);
comp = fixture.componentInstance;
});
tests();
});
//////// Testing w/ NO_ERRORS_SCHEMA //////
describe('AppComponent & NO_ERRORS_SCHEMA', () => {
beforeEach(waitForAsync(() => {
// #docregion no-errors-schema, mixed-setup
beforeEach(() => {
// #docregion no-errors-schema
TestBed.configureTestingModule(
Object.assign({}, appConfig, {
imports: [
AppComponent,
// #enddocregion no-errors-schema
BannerStubComponent,
// #docregion no-errors-schema
RouterLink,
],
providers: [provideRouter([]), UserService],
schemas: [NO_ERRORS_SCHEMA],
}),
)
// #enddocregion no-errors-schema, mixed-setup
).overrideComponent(AppComponent, {
set: {
imports: [], // resets all imports
schemas: [NO_ERRORS_SCHEMA],
},
});
// #enddocregion no-errors-schema
.then(() => {
fixture = TestBed.createComponent(AppComponent);
comp = fixture.componentInstance;
});
}));
fixture = TestBed.createComponent(AppComponent);
comp = fixture.componentInstance;
});
tests();
});
describe('AppComponent & NO_ERRORS_SCHEMA', () => {
beforeEach(() => {
// #docregion mixed-setup
TestBed.configureTestingModule(
Object.assign({}, appConfig, {
providers: [provideRouter([]), UserService],
}),
).overrideComponent(AppComponent, {
remove: {
imports: [RouterOutlet, WelcomeComponent],
},
set: {
schemas: [NO_ERRORS_SCHEMA],
},
});
// #enddocregion mixed-setup
fixture = TestBed.createComponent(AppComponent);
comp = fixture.componentInstance;
});
tests();
});
@@ -28,7 +28,7 @@ describe('BannerComponent (external files)', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [BannerComponent],
}); // compile template and css
}).compileComponents(); // compile template and css
});
// #enddocregion async-before-each
@@ -11,9 +11,6 @@ describe('BannerComponent (inline template)', () => {
let h1: HTMLElement;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [BannerComponent],
});
fixture = TestBed.createComponent(BannerComponent);
component = fixture.componentInstance; // BannerComponent test instance
h1 = fixture.nativeElement.querySelector('h1');
@@ -109,7 +109,6 @@ describe('DashboardHeroComponent when inside a test host', () => {
// #docregion test-host-setup
TestBed.configureTestingModule({
providers: appProviders,
imports: [DashboardHeroComponent, TestHostComponent],
});
// #enddocregion test-host-setup
}));
@@ -69,7 +69,6 @@ function compileAndCreate() {
// #docregion router-harness
TestBed.configureTestingModule(
Object.assign({}, appConfig, {
imports: [DashboardComponent],
providers: [
provideRouter([{path: '**', component: DashboardComponent}]),
provideHttpClient(),
@@ -13,7 +13,7 @@ import {HeroDetailService} from './hero-detail.service';
templateUrl: './hero-detail.component.html',
styleUrls: ['./hero-detail.component.css'],
providers: [HeroDetailService],
imports: [sharedImports, RouterLink],
imports: [...sharedImports],
})
export class HeroDetailComponent {
// #docregion inject

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