Compare commits

...

171 Commits

Author SHA1 Message Date
Jessica Janiuk 64ddde21af release: cut the v20.2.3 release 2025-08-29 14:33:36 +02:00
Jessica Janiuk 479a919f42 fix(compiler): fixes regression with event parsing and animate prefix (#63470)
The new animations was not correctly looking for the `.` when parsing bindings. This resulted in arbitrary event bindings creating animate.leave instruction calls.

fixes: #63466

PR Close #63470
2025-08-29 11:53:30 +00:00
Angular Robot 98468c0d7a build: update cross-repo angular dependencies (#63444)
See associated pull request for more information.

PR Close #63444
2025-08-28 09:21:54 -07:00
Hongxu Xu b549cd28ae refactor(bazel): reduce build deps (#63348)
clean up deps in bazel build scripts

PR Close #63348
2025-08-28 09:16:10 -07:00
Angular Robot cef1449ac7 docs: update Angular CLI help (#63446)
Updated Angular CLI help contents.

PR Close #63446
2025-08-28 09:11:46 -07:00
Alan Agius 05a9322c75 build: remove rulesJsInteropMode (#63448)
This is no longer needed.

PR Close #63448
2025-08-28 08:49:25 -07:00
Matthieu Riegler df89611bf2 docs(docs-infra): remove unused example (#63426)
PR Close #63426
2025-08-28 08:47:54 -07:00
Milo 35dea23580 build: simplify pnpm scripts in package.json (#63310)
remove unnecessary pnpm prefix for bin scripts from node_modules

PR Close #63310
2025-08-28 08:46:23 -07:00
Vincent 596b545130 fix(core): Prevent an error on cleanup when an rxResource stream threw before returning an Observable (#63342)
Before this commit, it was wrongly assumed that the stream subscription could not be `undefined`.

Fixes #63341

PR Close #63342
2025-08-28 08:44:52 -07:00
arturovt 1e3999ec36 refactor(core): replace Optional/SkipSelf deps with inject() flags (#63386)
This commit updates provider definitions that relied on the `deps` array
with `new Optional()` and `new SkipSelf()` to instead use the modern
`inject(..., { optional: true, skipSelf: true })` API.

Previously:
  deps: [[KeyValueDiffers, new SkipSelf(), new Optional()]]

Now:
  const parent = inject(KeyValueDiffers, { optional: true, skipSelf: true });

**Bundle size reduction**: `Optional` and `SkipSelf` are runtime values
created by `makeParamDecorator()`. Even in production builds, esbuild
and other bundlers must keep their factory code because they are
referenced with `new Optional()` / `new SkipSelf()`. With `inject()`,
those classes are no longer referenced, allowing them and the
`makeParamDecorator` scaffolding to be tree-shaken when unused.

As a result, production bundles can drop both `Optional`, `SkipSelf`, and
their supporting factory code when not used elsewhere, reducing code size
while keeping the same behavior.

PR Close #63386
2025-08-28 08:43:17 -07:00
Jessica Janiuk 114906d2d6 fix(core): Fix cancellation of animation enter classes (#63442)
When toggling visibility on an element over and over, the enter animations were supposed to be cancelled and then the classes removed. There was a race condition happening that resulted in the cancelled animation being the leave animation. Rather than using the animation.cancel functionality, it's safer to just remove the enter classes.

fixes: #63439

PR Close #63442
2025-08-28 14:11:06 +00:00
Alan Agius 2e05deaffb ci: remove old options from workflows (#63441)
The `cache-node-modules` option has been removed as pnpm store cache is enabled by default.

PR Close #63441
2025-08-28 14:05:45 +00:00
Alan Agius 2fb029de04 ci: fix and improve devtools step (#63441)
This commit updates the devtools step by disabling the package manager cache. This change is necessary because Cypress downloads its binary to a cache directory during installation, which requires a post-install script. However, when the cache is hit this is skipped.

This update also disables `pnpm install` in the Cypress action to avoid a redundant installation step. And adds a seperate cache for the downloaded Cypress binary.

See: https://docs.cypress.io/app/get-started/install-cypress#pnpm-configuration

PR Close #63441
2025-08-28 14:05:45 +00:00
SkyZeroZx 690405b253 docs: Add docs service worker to new options (#63436)
Add docs service worker to new options

PR Close #63436
2025-08-28 10:20:52 +00:00
Angular Robot fe533cd244 docs: update Angular CLI help (#63420)
Updated Angular CLI help contents.

PR Close #63420
2025-08-28 10:09:09 +00:00
Matthieu Riegler 421edfe04b build: update @bazel/ibazel to 0.26.10 (#63435)
To fix failing devtools tests

PR Close #63435
2025-08-28 10:02:02 +00:00
Joey Perrott 87bfe164e3 build: define typescript version via string in module.bazel file (#63434)
Within our module.bazel file when describing the version of typescript to use for rules_ts, we use ts_version instead of ts_version_from to prevent our package.json file from being
part of the set of files used to calculate the sha for the lock file.  Any unrelated change to the version of the typescript file would end up causing our lockfile to be out of date.
This amount of churn has proven to be too much for our current setup. We instead now test to validate the versions defined in the package.json and MODULE.bazel files match.

PR Close #63434
2025-08-28 09:55:37 +00:00
Shuaib Hasan Akib a6a46e9839 docs(docs-infra): tooltip on hover and message after copied (#63167)
PR Close #63167
2025-08-27 16:56:45 -07:00
Ben Hong 9de2f078d5 docs: add customizing route behavior guide for router (#63398)
PR Close #63398
2025-08-27 16:18:39 -07:00
Shuaib Hasan Akib 40844876ea docs(docs-infra): mark properties as readonly if they shouldn't change (#63200)
PR Close #63200
2025-08-27 16:16:25 -07:00
Angular Robot ca61366218 build: update cross-repo angular dependencies (#63396)
See associated pull request for more information.

PR Close #63396
2025-08-27 16:14:31 -07:00
Matthieu Riegler cd748aad47 docs: remove the ng-class migration entry (#63430)
That migration is only available in v21 / on the main branch for now.

fixes #63428

PR Close #63430
2025-08-27 16:10:18 -07:00
arturovt fce5602b53 refactor(core): mark VERSION as @__PURE__ for better tree-shaking (#63400)
Annotate the `new Version(...)` call with `/* @__PURE__ */` to signal to
optimizers that the constructor is side-effect free.

Without this hint, bundlers such as Terser or ESBuild may conservatively
retain the `VERSION` instantiation even when unused. With the annotation,
the constant can be tree-shaken away in production builds if not referenced,
reducing bundle size.

PR Close #63400
2025-08-27 11:39:07 -07:00
arturovt f87fad3fff fix(core): avoid injecting internal error handler from a destroyed injector (#62275)
This commit prevents lazy injection of the internal `ErrorHandler` from a destroyed injector, which would otherwise result in a secondary "destroyed injector" error.

The `handleUncaughtError` function is used in a wrapped event listener that invokes the `ErrorHandler` if the listener throws. A simple case in a micro-frontend application:

```ts
onNavigationToAnotherApp() {
  this.appRef.destroy();
  do_some_stuff_ie_loggin_that_may_throw();
}
```

If the function throws an error, Angular attempts to inject the `ErrorHandler` from a destroyed injector.

PR Close #62275
2025-08-27 11:35:55 -07:00
Alexander Melde 06c53679ba docs: update to new standalone default behavior (#63329)
When declaring directives, the standalone flag is set to true by default in current Angular versions.

The docs for the directive decorator should correctly explain the default behavior, while still mentioning when to set it to false.

PR Close #63329
2025-08-27 11:26:13 -07:00
Matthieu Riegler e8d9bc5119 refactor(http): rework the HttpEvent union to improve narrowing. (#63267)
Prior to this change, `HttpProgressEvent` could not be narrowed to `HttpDownloadProgressEvent` or `HttpUploadProgressEvent`

PR Close #63267
2025-08-27 11:25:02 -07:00
Joey Perrott 26072bba9c build: move macros/build set up for zone.js into zone.js directories (#63421)
Move the zone_bundle and configurations into zone.js's tool directory

PR Close #63421
2025-08-27 11:23:58 -07:00
Joey Perrott 00bfff52c2 build: remove unused macros (#63421)
Remove unused macro files

PR Close #63421
2025-08-27 11:23:57 -07:00
Joey Perrott 0bc7f154c8 build: remove ts_project_interop file (#63421)
Remove the ts_project_interop.bzl file that no longer does interop work

PR Close #63421
2025-08-27 11:23:57 -07:00
Joey Perrott 705b94bd21 refactor: remove TODOs which have been corrected (#63421)
Remove TODOs which were addressed but the comment was not removed

PR Close #63421
2025-08-27 11:23:57 -07:00
Jessica Janiuk ed6a347109 refactor(core): prevent timeout from applying to non-event animation bindings (#63393)
The 4 second removal timeout was applying in all cases, but it should only actually apply to the situation where the event binding syntax is used for animate.leave. This ensures that's the only case in which it'll apply.

PR Close #63393
2025-08-27 11:17:40 -07:00
Andrew Scott 6d6b0278a8 refactor(core): Reorder resolve/reject in relation to navigate[error/success] (#63377)
Order was changed in https://github.com/whatwg/html/pull/11512 (see that
PR for details as to why).

https://whatpr.org/html/10919/nav-history-apis.html#abort-a-navigateevent

PR Close #63377
2025-08-27 11:16:53 -07:00
Andrew Kushnir 6e0b66d702 release: cut the v20.2.2 release 2025-08-27 10:53:04 -07:00
Matthieu Riegler 47caed9ada ci: pin create-pull-request version to sha (#63409)
This is a new security requirement to prevent dependency compromission.

PR Close #63409
2025-08-27 07:36:12 -07:00
Taygan Caldwell 23d1ace339 refactor(core): Create a base effect interface and prototype to be used by both angular and wiz. (#62931)
Add a common effect interface and prototype to be used to create the wiz and angular effects.

PR Close #62931
2025-08-26 14:48:33 -07:00
Matthieu Riegler e220a615d1 docs(docs-infra): patch port changes from main (#63394)
This sync some of the changes we have on the main branch will allow more upcomming changes to land via a single PR.

PR Close #63394
2025-08-26 09:48:03 -07:00
Jessica Janiuk d7b6045d61 fix(compiler): fixes animations on elements with structural directives (#63390)
The animate instructions were getting applied to the container comment nodes as well as the element nodes. This prevents that on the compiler level.

fixes: #63371

PR Close #63390
2025-08-26 09:47:08 -07:00
Avcharov Hryhorii c9b0f45690 fix(devtools): prevent profiler bars flickering after change detection (#63350)
Without trackBy cdkVirtualFor rerenders full list after in each update

PR Close #63350
2025-08-26 09:41:09 -07:00
Angular Robot 15395a576f build: update cross-repo angular dependencies (#63380)
See associated pull request for more information.

PR Close #63380
2025-08-25 16:29:57 -07:00
Joey Perrott 9a27c5befb build: rename defaults2.bzl to defaults.bzl (#63384)
Use defaults.bzl for the common macros

PR Close #63384
2025-08-25 15:45:46 -07:00
Joey Perrott a26d94d979 build: enable strict deps enforcement for ts_project (#63376)
Enable strict_deps testings for all ts_project and ng_project targets in the repo

PR Close #63376
2025-08-25 15:38:12 -07:00
Angular Robot 328e588bcd build: lock file maintenance (#63360)
See associated pull request for more information.

PR Close #63360
2025-08-25 15:37:25 -07:00
Angular Robot 454a269254 build: update cross-repo angular dependencies (#63339)
See associated pull request for more information.

PR Close #63339
2025-08-25 10:50:36 -07:00
Angular Robot f881082e80 build: update bazel dependencies (#63345)
See associated pull request for more information.

PR Close #63345
2025-08-25 08:36:53 -07:00
Jessica Janiuk c8f07daf8f fix(core): Fixes animate.leave binding to a string with spaces (#63366)
This fixes the rare case that someone uses binding syntax with `animate.leave` providing a value with a string that has spaces in it. For example:

```
<example `[animate.leave]="'class-a class-b"` />
```

fixes: #63365

PR Close #63366
2025-08-25 08:33:31 -07:00
AleksanderBodurri 3f247f1256 fix(devtools): correct path to load fonts for devtools devserver (#63358)
This broke in c35c0c7f2f. This commit changes the path to load the external stylesheet to reflect the new directory path.

PR Close #63358
2025-08-25 08:31:56 -07:00
Jessica Janiuk aabe146c30 docs: update paths and references to animations guides (#63370)
This updates the adev navigation to consider the new enter-and-leave path to be the definitive animations guide.
It also prefixes all the prior animations package docs with legacy and updates all links.

PR Close #63370
2025-08-25 08:22:32 -07:00
Jessica Janiuk 650ad1f7fb docs: add important service worker note (#63364)
This adds an important note about the service worker to indicate we are not accepting new features.

PR Close #63364
2025-08-25 08:18:32 -07:00
Jessica Janiuk 269f344d45 docs: update animations guide important note (#63363)
PR Close #63363
2025-08-25 08:17:44 -07:00
Matthieu Riegler a649d85de1 refactor(docs-infra): ensure we're not creating nested anchor elements. (#63352)
With #63162, we added automatic link creation on API symbols. The side effect was that we created HTML in some specific cases. For example with the docs-card we could have nested anchor elements which is invalid.

This commit prevent creating nested links inside docs-cards.
fixes #63351

PR Close #63352
2025-08-25 08:16:21 -07:00
Matthieu Riegler 020e0f0424 refactor(docs-infra): rename testing into test. (#63352)
We usually name `test` our test directories and `testing` for the testing helpers.

PR Close #63352
2025-08-25 08:16:21 -07:00
Joey Perrott 10b0927e15 refactor: various build and import specificer fixes for strict deps (#63324)
Change direct deps in bazel targets and import specifiers within files to maintain strict deps requirements ahead of enabling strict deps tests in the repo

PR Close #63324
2025-08-22 14:45:34 -07:00
Shuaib Hasan Akib 28c28a0aa4 docs(docs-infra): Replace page enums by constants (#63335)
PR Close #63335
2025-08-22 14:42:52 -07:00
Matthieu Riegler eef93f5a7b docs(docs-infra): auto-links to API entries (#63283)
This is a first step to create links to API entries automatically.
It adds support for
- code spans (`` `symbol` ``)
- code blocks (`` ```some code here``` ``)

Links are generated from on a K/V map of API entries (symbol => package name).
The map is generated from the API manifest that we're already generating for the API docs.

For the moment, entries with identical names are skipped.

This is a backport of #63162

PR Close #63283
2025-08-22 14:42:17 -07:00
Matthieu Riegler e1481d89dc ci: add myself to review fw-general (#63337)
Also adding myself to be assigned some adev PRs

PR Close #63337
2025-08-22 12:27:37 -07:00
Shuaib Hasan Akib e8aa7d3ce3 docs(docs-infra): fix spelling (#63334)
PR Close #63334
2025-08-22 12:01:49 -07:00
Angular Robot b02042301a build: update cross-repo angular dependencies (#63332)
See associated pull request for more information.

PR Close #63332
2025-08-22 11:29:11 -07:00
Angular Robot 551c99fd5f build: update github/codeql-action action to v3.29.11 (#63326)
See associated pull request for more information.

PR Close #63326
2025-08-22 11:28:31 -07:00
Jessica Janiuk 6c421ed65d fix(core): Ensures @for loop animations never get cancelled (#63328)
There's special logic in place to prevent duplicate nodes from showing up in the case when an `@if` toggles a view quickly. This had the unfortunate side effect of causing `@for` leave animations to get cancelled when an add and remove happened simultaneously, even if it was a different index. This fix prevents that from happening in the `@for` loop case.

fixes: #63307

PR Close #63328
2025-08-22 11:23:16 -07:00
Jessica Janiuk 9093e0e132 fix(core): fix memory leak with leaving nodes tracking (#63328)
This ensures the nodes are properly cleaned up from the leaving nodes map.

PR Close #63328
2025-08-22 11:23:16 -07:00
Angular Robot 040cba0b09 build: update cross-repo angular dependencies (#63319)
See associated pull request for more information.

PR Close #63319
2025-08-21 14:12:40 -07:00
Angular Robot 6213c7d998 build: update cross-repo angular dependencies (#63316)
See associated pull request for more information.

PR Close #63316
2025-08-21 11:45:18 -07:00
Matthieu Riegler 49e00b306a docs(docs-infra): fix mermaid rendering (#63311)
A recent update of mermaid change the html output. `rect` became `path`.

fixes #63308

PR Close #63311
2025-08-21 10:06:32 -07:00
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
949 changed files with 21100 additions and 13871 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
+1 -1
View File
@@ -1,4 +1,4 @@
load("//tools:defaults2.bzl", "esbuild_checked_in", "ts_config", "ts_project")
load("//tools:defaults.bzl", "esbuild_checked_in", "ts_config", "ts_project")
package(default_visibility = ["//.github/actions/deploy-docs-site:__subpackages__"])
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@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Saucelabs Variables
uses: angular/dev-infra/github-actions/saucelabs@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/saucelabs@ae4e34835e566bbcc12bec8f2191b069f307ece2
- 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@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
- 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@ae4e34835e566bbcc12bec8f2191b069f307ece2
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@ae4e34835e566bbcc12bec8f2191b069f307ece2
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@ae4e34835e566bbcc12bec8f2191b069f307ece2
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@ae4e34835e566bbcc12bec8f2191b069f307ece2
with:
bazelrc: ./.bazelrc.user
+29 -37
View File
@@ -21,9 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
with:
cache-node-modules: true
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Check code lint
@@ -41,15 +39,20 @@ 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@ae4e34835e566bbcc12bec8f2191b069f307ece2
with:
cache-node-modules: true
disable-package-manager-cache: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Cache downloaded Cypress binary
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: '~/.cache/Cypress'
key: cypress-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Run unit tests
@@ -63,18 +66,17 @@ jobs:
start: pnpm bazel run //devtools/src:devserver
wait-on: 'http://localhost:4200'
wait-on-timeout: 300
install: false
test:
runs-on: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
with:
cache-node-modules: true
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
@@ -86,13 +88,11 @@ jobs:
runs-on: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
with:
cache-node-modules: true
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
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@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
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@ae4e34835e566bbcc12bec8f2191b069f307ece2
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@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Install node modules
run: pnpm install --frozen-lockfile
- run: echo "https://${{secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN}}:@github.com" > ${HOME}/.git_credentials
@@ -142,17 +142,11 @@ jobs:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
with:
cache-node-modules: true
node-module-directories: |
./node_modules
./packages/zone.js/node_modules
./packages/zone.js/test/typings/node_modules
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
@@ -192,8 +186,6 @@ jobs:
# steps:
# - name: Initialize environment
# uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b5a3609f89c06eb4037dce22a93641213a5d1508
# with:
# cache-node-modules: true
# - name: Install node modules
# run: pnpm install --frozen-lockfile
# - uses: ./.github/actions/saucelabs-legacy
@@ -204,11 +196,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@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
- 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@ae4e34835e566bbcc12bec8f2191b069f307ece2
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@ae4e34835e566bbcc12bec8f2191b069f307ece2
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@ae4e34835e566bbcc12bec8f2191b069f307ece2
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@ae4e34835e566bbcc12bec8f2191b069f307ece2
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@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Saucelabs Variables
uses: angular/dev-infra/github-actions/saucelabs@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/saucelabs@ae4e34835e566bbcc12bec8f2191b069f307ece2
- 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@ae4e34835e566bbcc12bec8f2191b069f307ece2
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@ae4e34835e566bbcc12bec8f2191b069f307ece2
- 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@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
- 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
+24 -32
View File
@@ -19,9 +19,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
with:
cache-node-modules: true
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Check code lint
@@ -39,7 +37,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@ae4e34835e566bbcc12bec8f2191b069f307ece2
with:
allow-dependencies-licenses: 'pkg:npm/google-protobuf@'
@@ -47,13 +45,18 @@ 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@ae4e34835e566bbcc12bec8f2191b069f307ece2
with:
cache-node-modules: true
disable-package-manager-cache: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Cache downloaded Cypress binary
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: '~/.cache/Cypress'
key: cypress-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Run unit tests
@@ -67,18 +70,17 @@ jobs:
start: pnpm bazel run //devtools/src:devserver
wait-on: 'http://localhost:4200'
wait-on-timeout: 300
install: false
test:
runs-on: ubuntu-latest-8core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
with:
cache-node-modules: true
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Run CI tests for framework
@@ -98,13 +100,11 @@ jobs:
runs-on: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
with:
cache-node-modules: true
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
- 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@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Run tests
@@ -132,17 +132,11 @@ jobs:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
with:
cache-node-modules: true
node-module-directories: |
./node_modules
./packages/zone.js/node_modules
./packages/zone.js/test/typings/node_modules
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
- name: Install node modules
run: pnpm install --frozen-lockfile
- run: |
@@ -180,8 +174,6 @@ jobs:
# steps:
# - name: Initialize environment
# uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b5a3609f89c06eb4037dce22a93641213a5d1508
# with:
# cache-node-modules: true
# - name: Install node modules
# run: pnpm install --frozen-lockfile
# - uses: ./.github/actions/saucelabs-legacy
+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@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.11
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
@@ -37,7 +37,7 @@ jobs:
env:
ANGULAR_CDK_BUILDS_READONLY_GITHUB_TOKEN: ${{ secrets.ANGULAR_CDK_BUILDS_READONLY_GITHUB_TOKEN }}
- name: Create a PR CDK apis (if necessary)
uses: peter-evans/create-pull-request@v7.0.8 # v7.0.8
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
token: ${{ secrets.ANGULAR_ROBOT_ACCESS_TOKEN }}
push-to-fork: 'angular-robot/angular'
@@ -66,7 +66,7 @@ jobs:
env:
ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN: ${{ secrets.ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN }}
- name: Create a PR CLI help (if necessary)
uses: peter-evans/create-pull-request@v7.0.8 # v7.0.8
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
token: ${{ secrets.ANGULAR_ROBOT_ACCESS_TOKEN }}
push-to-fork: 'angular-robot/angular'
-1
View File
@@ -2,7 +2,6 @@ import {ReleaseConfig} from '@angular/ng-dev';
/** Configuration for the `ng-dev release` command. */
export const release: ReleaseConfig = {
rulesJsInteropMode: true,
publishRegistry: 'https://wombat-dressing-room.appspot.com',
representativeNpmPackage: '@angular/core',
npmPackages: [
+4 -3
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.
@@ -177,6 +177,7 @@ groups:
- thePunderWoman
- ~pkozlowski-opensource
- mmalerba
- JeanMeche
# =========================================================
# Framework: Security-sensitive files which require extra review
@@ -273,7 +274,7 @@ groups:
- bencodezen
- crisbeto
- kirjs
- ~JeanMeche
- JeanMeche
- jelbourn
- thePunderWoman
- devversion
+8 -3
View File
@@ -1,7 +1,8 @@
load("@aspect_rules_js//js:defs.bzl", "js_library")
load("@npm2//:defs.bzl", "npm_link_all_packages")
load("@devinfra//bazel/validation:defs.bzl", "validate_ts_version_matching")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//:yarn.bzl", "YARN_PATH")
load("//tools:defaults2.bzl", "copy_to_bin", "js_binary")
load("//tools:defaults.bzl", "copy_to_bin", "js_binary")
package(default_visibility = ["//visibility:public"])
@@ -11,7 +12,6 @@ exports_files([
"browser-providers.conf.js",
YARN_PATH,
"package.json",
"angular.json",
])
npm_link_all_packages(
@@ -25,6 +25,11 @@ filegroup(
srcs = ["package.json"],
)
validate_ts_version_matching(
module_lock_file = "MODULE.bazel.lock",
package_json = "package.json",
)
alias(
name = "tsconfig.json",
actual = "//packages:tsconfig-build.json",
+93 -155
View File
@@ -1,52 +1,87 @@
<a name="20.2.0-next.6"></a>
# 20.2.0-next.6 (2025-08-07)
### compiler-cli
<a name="20.2.3"></a>
# 20.2.3 (2025-08-29)
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [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)) |
| [479a919f42](https://github.com/angular/angular/commit/479a919f42517193653384220adab5b89dd74e3d) | fix | fixes regression with event parsing and animate prefix ([#63470](https://github.com/angular/angular/pull/63470)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [f87fad3fff](https://github.com/angular/angular/commit/f87fad3fff62cebf2868e06cba48e0f27b719d24) | fix | avoid injecting internal error handler from a destroyed injector ([#62275](https://github.com/angular/angular/pull/62275)) |
| [114906d2d6](https://github.com/angular/angular/commit/114906d2d68d98c98961d858abd3ae714d4809a3) | fix | Fix cancellation of animation enter classes ([#63442](https://github.com/angular/angular/pull/63442)) |
| [596b545130](https://github.com/angular/angular/commit/596b5451309b8ce4f08a1cd36e6b3610507d52f9) | fix | Prevent an error on cleanup when an `rxResource` `stream` threw before returning an `Observable` ([#63342](https://github.com/angular/angular/pull/63342)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="20.2.2"></a>
# 20.2.2 (2025-08-27)
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [d7b6045d61](https://github.com/angular/angular/commit/d7b6045d61582d20a17802e769dc1441984988f0) | fix | fixes animations on elements with structural directives ([#63390](https://github.com/angular/angular/pull/63390)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [6c421ed65d](https://github.com/angular/angular/commit/6c421ed65d050765a18eafc51fe7257abc5682ce) | fix | Ensures `@for` loop animations never get cancelled ([#63328](https://github.com/angular/angular/pull/63328)) |
| [9093e0e132](https://github.com/angular/angular/commit/9093e0e132f99c2b590c31b299871bcd493b7de0) | fix | fix memory leak with leaving nodes tracking ([#63328](https://github.com/angular/angular/pull/63328)) |
| [c8f07daf8f](https://github.com/angular/angular/commit/c8f07daf8f2c7e8c6641eb4368379a3f5f1d1f52) | fix | Fixes `animate.leave` binding to a string with spaces ([#63366](https://github.com/angular/angular/pull/63366)) |
<!-- CHANGELOG SPLIT MARKER -->
<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)) |
### 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 +89,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 +107,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 +147,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 +165,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 +187,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 +214,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.5.0")
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.1")
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 = "ae4e34835e566bbcc12bec8f2191b069f307ece2",
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 = "5.9.2",
)
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",
)
+4329
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.1",
"@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.1",
"@angular/cdk": "20.2.1",
"@angular/cli": "20.2.1",
"@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.1",
"@angular/platform-browser": "workspace:*",
"@angular/platform-server": "workspace:*",
"@angular/router": "workspace:*",
"@angular/ssr": "20.2.0-next.2",
"@angular/ssr": "20.2.1",
"@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",
@@ -11,7 +11,7 @@ import {LOCAL_STORAGE} from '../../providers/index';
import {setCookieConsent} from '../../utils';
/**
* Decelare gtag as part of the window in this file as gtag is expected to already be loaded.
* Declare gtag as part of the window in this file as gtag is expected to already be loaded.
*/
declare const window: Window & typeof globalThis & {gtag?: Function};
@@ -11,7 +11,7 @@ import {NavigationItem} from '../../interfaces/index';
import {NavigationState} from '../../services/index';
import {RouterLink, RouterLinkActive} from '@angular/router';
import {IconComponent} from '../icon/icon.component';
import {IsActiveNavigationItem} from '../../pipes/is-active-navigation-item.pipe';
import {IsActiveNavigationItem} from '../../pipes';
import {NgTemplateOutlet} from '@angular/common';
import {MatTooltipModule} from '@angular/material/tooltip';
@@ -27,6 +27,7 @@ ng_project(
"//adev/shared-docs/directives",
"//adev/shared-docs/interfaces",
"//adev/shared-docs/pipes",
"//adev/shared-docs/providers",
"//adev/shared-docs/services",
],
)
@@ -20,19 +20,18 @@ import {
viewChildren,
} from '@angular/core';
import {WINDOW} from '../../providers/index';
import {ClickOutside} from '../../directives/index';
import {Search, SearchHistory} from '../../services/index';
import {WINDOW} from '../../providers';
import {ClickOutside, SearchItem} from '../../directives';
import {Search, SearchHistory} from '../../services';
import {TextField} from '../text-field/text-field.component';
import {FormControl, ReactiveFormsModule} from '@angular/forms';
import {ActiveDescendantKeyManager} from '@angular/cdk/a11y';
import {SearchItem} from '../../directives/search-item/search-item.directive';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {Router, RouterLink} from '@angular/router';
import {fromEvent} from 'rxjs';
import {AlgoliaIcon} from '../algolia-icon/algolia-icon.component';
import {RelativeLink} from '../../pipes/relative-link.pipe';
import {RelativeLink} from '../../pipes';
import {SearchHistoryComponent} from '../search-history/search-history.component';
@Component({
@@ -52,10 +51,10 @@ import {SearchHistoryComponent} from '../search-history/search-history.component
styleUrls: ['./search-dialog.component.scss'],
})
export class SearchDialog {
onClose = output();
dialog = viewChild.required<ElementRef<HTMLDialogElement>>('searchDialog');
items = viewChildren(SearchItem);
textField = viewChild(TextField);
readonly onClose = output();
readonly dialog = viewChild.required<ElementRef<HTMLDialogElement>>('searchDialog');
readonly items = viewChildren(SearchItem);
readonly textField = viewChild(TextField);
readonly history = inject(SearchHistory);
private readonly search = inject(Search);
@@ -68,9 +67,9 @@ export class SearchDialog {
this.injector,
).withWrap();
searchQuery = this.search.searchQuery;
resultsResource = this.search.resultsResource;
searchResults = this.search.searchResults;
readonly searchQuery = this.search.searchQuery;
readonly resultsResource = this.search.resultsResource;
readonly searchResults = this.search.searchResults;
// We use a FormControl instead of relying on NgModel+signal to avoid
// the issue https://github.com/angular/angular/issues/13568
@@ -38,6 +38,8 @@ ts_project(
":search-history",
"//adev:node_modules/@angular/core",
"//adev:node_modules/@angular/platform-browser",
"//adev:node_modules/@angular/router",
"//adev/shared-docs/providers",
"//adev/shared-docs/services",
"//adev/shared-docs/testing",
],
@@ -21,7 +21,7 @@ import {ActiveDescendantKeyManager} from '@angular/cdk/a11y';
import {SearchHistory} from '../../services';
import {RelativeLink} from '../../pipes';
import {SearchItem} from '../../directives/search-item/search-item.directive';
import {SearchItem} from '../../directives';
@Component({
selector: 'docs-search-history',
@@ -17,7 +17,7 @@ import {
} from '@angular/core';
import {Location, ViewportScroller} from '@angular/common';
import {TableOfContentsLevel} from '../../interfaces/index';
import {TableOfContentsLoader} from '../../services/table-of-contents-loader.service';
import {TableOfContentsLoader} from '../../services';
import {IconComponent} from '../icon/icon.component';
@Component({
@@ -29,16 +29,16 @@ export class TopLevelBannerComponent {
* separately for different events or instances. Without a unique ID,
* closing one banner could inadvertently hide other banners for different events.
*/
id = input.required<string>();
readonly id = input.required<string>();
// Optional URL link that the banner should navigate to when clicked.
link = input<string>();
readonly link = input<string>();
// Text content to be displayed in the banner.
text = input.required<string>();
readonly text = input.required<string>();
// Optional expiry date. Setting the default expiry as a future date so we
// don't have to deal with undefined signal values.
expiry = input(new Date('3000-01-01'), {transform: parseDate});
readonly expiry = input(new Date('3000-01-01'), {transform: parseDate});
// Whether the user has closed the banner or the survey has expired.
hasClosed = linkedSignal(() => {
readonly hasClosed = linkedSignal(() => {
const expired = Date.now() > this.expiry().getTime();
// Needs to be in a try/catch, because some browsers will
@@ -21,13 +21,17 @@ 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",
"//adev/shared-docs/components/copy-source-code-button",
"//adev/shared-docs/components/icon",
"//adev/shared-docs/components/table-of-contents",
"//adev/shared-docs/interfaces",
"//adev/shared-docs/providers",
"//adev/shared-docs/services",
"//adev/shared-docs/utils",
],
)
@@ -28,21 +28,22 @@ import {
effect,
} from '@angular/core';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {TOC_SKIP_CONTENT_MARKER, NavigationState} from '../../../services/index';
import {TOC_SKIP_CONTENT_MARKER, NavigationState} from '../../../services';
import {TableOfContents} from '../../table-of-contents/table-of-contents.component';
import {IconComponent} from '../../icon/icon.component';
import {handleHrefClickEventWithRouter} from '../../../utils/index';
import {Snippet} from '../../../interfaces/index';
import {handleHrefClickEventWithRouter} from '../../../utils';
import {Snippet} from '../../../interfaces';
import {Router} from '@angular/router';
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
@@ -60,8 +61,8 @@ export const GITHUB_CONTENT_URL = 'https://github.com/angular/angular/blob/main/
},
})
export class DocViewer {
docContent = input<string | undefined>();
hasToc = input(false);
readonly docContent = input<string | undefined>();
readonly hasToc = input(false);
readonly contentLoaded = output<void>();
private readonly destroyRef = inject(DestroyRef);
@@ -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>
}
@@ -22,6 +18,8 @@
class="docs-example-copy-link"
[attr.aria-label]="'Copy link to ' + exampleMetadata()?.title + ' example to the clipboard'"
(click)="copyLink()"
matTooltip="Copy link to example"
matTooltipPosition="above"
>
<i aria-hidden="true">
<svg
@@ -45,8 +43,9 @@
<button
type="button"
(click)="toggleExampleVisibility()"
[attr.title]="(expanded() ? 'Collapse' : 'Expand') + ' example'"
[attr.aria-label]="(expanded() ? 'Collapse' : 'Expand') + ' code example'"
matTooltip="{{ expanded() ? 'Collapse' : 'Expand' }} example"
matTooltipPosition="above"
>
<i aria-hidden="true">
@if (!expanded()) {
@@ -87,7 +86,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,13 +99,14 @@
<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"
aria-label="Open example on GitHub"
matTooltip="Open example on GitHub"
matTooltipPosition="above"
>
<i aria-hidden="true">
<svg
@@ -125,13 +127,14 @@
</i>
</a>
}
@if (stackblitzUrl) {
@if (stackblitzUrl()) {
<a
[href]="stackblitzUrl"
[href]="stackblitzUrl()"
target="_blank"
class="docs-example-stackblitz-link"
title="Edit this example in StackBlitz"
aria-label="Edit this example in StackBlitz"
aria-label="Edit example in StackBlitz"
matTooltip="Edit example in StackBlitz"
matTooltipPosition="above"
>
<i aria-hidden="true">
<svg
@@ -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);
@@ -35,7 +35,6 @@ describe('ExampleViewer', () => {
await TestBed.configureTestingModule({
imports: [ExampleViewer],
providers: [
// TODO: Find why tests warn that zone.js is still loaded
provideZonelessChangeDetection(),
{provide: EXAMPLE_VIEWER_CONTENT_LOADER, useValue: exampleContentSpy},
{provide: ActivatedRoute, useValue: {snapshot: {fragment: 'fragment'}}},
@@ -53,9 +52,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 +72,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 +92,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 +123,7 @@ describe('ExampleViewer', () => {
files: [
{
name: 'example.ts',
content: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
sanitizedContent: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
visibleLinesRange: '[1]',
},
],
@@ -148,7 +147,7 @@ describe('ExampleViewer', () => {
files: [
{
name: 'example.ts',
content: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
sanitizedContent: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
visibleLinesRange: '[1]',
},
],
@@ -198,7 +197,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,15 +209,16 @@ describe('ExampleViewer', () => {
preview: true,
}),
);
component.stackblitzUrl = 'https://stackblitz.com/';
componentRef.setInput('stackblitzUrl', 'https://stackblitz.com/');
await component.renderExample();
fixture.detectChanges();
const stackblitzButton = fixture.debugElement.query(
By.css('a[aria-label="Edit this example in StackBlitz"]'),
By.css('a[aria-label="Edit 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 +242,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 +278,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,7 @@ 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';
import {MatTooltipModule} from '@angular/material/tooltip';
export enum CodeExampleViewMode {
SNIPPET = 'snippet',
@@ -44,16 +42,15 @@ export const HIDDEN_CLASS_NAME = 'hidden';
@Component({
selector: 'docs-example-viewer',
imports: [CommonModule, forwardRef(() => DocViewer), CopySourceCodeButton, MatTabsModule],
imports: [CommonModule, CopySourceCodeButton, MatTabsModule, MatTooltipModule],
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 +79,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 -1
View File
@@ -3,7 +3,7 @@ load("@aspect_bazel_lib//lib:copy_to_directory.bzl", _copy_to_directory = "copy_
load("@aspect_rules_esbuild//esbuild:defs.bzl", _esbuild = "esbuild")
load("@devinfra//bazel/private:path_relative_to_label.bzl", _path_relative_to_label = "path_relative_to_label")
load(
"//tools:defaults2.bzl",
"//tools:defaults.bzl",
_jasmine_test = "jasmine_test",
_js_binary = "js_binary",
_js_library = "js_library",
+1
View File
@@ -8,3 +8,4 @@
export * from './click-outside/click-outside.directive';
export * from './external-link/external-link.directive';
export * from './search-item/search-item.directive';
+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"],
)
+16 -2
View File
@@ -16,6 +16,12 @@ def _generate_guides(ctx):
# Pass the the output directory path (which is the bazel-bin directory).
args.add(ctx.bin_dir.path)
# Add the api_manifest file if provided
if ctx.attr.api_manifest:
args.add(ctx.file.api_manifest.path)
else:
args.add("")
# Determine the set of html output files. For each input markdown file, produce an html
# file with the same name (replacing the markdown extension with `.html`).
html_outputs = []
@@ -30,9 +36,13 @@ def _generate_guides(ctx):
html_outputs += [ctx.actions.declare_file("%s.html" % relative_basepath)]
# Define an action that runs the executable.
inputs = ctx.files.srcs + ctx.files.data
if ctx.attr.api_manifest:
inputs.append(ctx.file.api_manifest)
if (ctx.attr.mermaid_blocks):
ctx.actions.run(
inputs = depset(ctx.files.srcs + ctx.files.data),
inputs = depset(inputs),
executable = ctx.executable._generate_guides,
outputs = html_outputs,
arguments = [args],
@@ -42,7 +52,7 @@ def _generate_guides(ctx):
)
else:
ctx.actions.run(
inputs = depset(ctx.files.srcs + ctx.files.data),
inputs = depset(inputs),
executable = ctx.executable._generate_guides_no_mermaid,
outputs = html_outputs,
arguments = [args],
@@ -71,6 +81,10 @@ generate_guides = rule(
doc = """Source referenced from within the markdown.""",
allow_files = True,
),
"api_manifest": attr.label(
doc = """A file containing API entries to be used in the markdown.""",
allow_single_file = True,
),
"mermaid_blocks": attr.bool(
doc = """Whether to transform mermaid blocks.""",
default = False,
@@ -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({
@@ -20,7 +20,6 @@ ts_project(
[
"**/*.mts",
"**/*.tsx",
"shiki.d.ts",
],
exclude = [
"entities.mts",
@@ -28,13 +27,15 @@ ts_project(
),
deps = [
":entities",
"//adev:node_modules/@types/node",
"//adev:node_modules/html-entities",
"//adev:node_modules/marked",
"//adev:node_modules/preact",
"//adev:node_modules/preact-render-to-string",
"//adev:node_modules/prettier",
"//adev:node_modules/shiki",
"//adev/shared-docs/pipeline/shared:linking",
"//adev/shared-docs/pipeline/shared:shiki",
"//adev/shared-docs/pipeline/shared/marked",
"//adev/shared-docs/pipeline/shared/regions",
],
)
@@ -11,12 +11,12 @@ import path from 'path';
import {CliCommand} from './cli-entities.mjs';
import {DocEntry} from './entities.mjs';
import {isCliEntry, isHiddenEntry} from './entities/categorization.mjs';
import {configureMarkedGlobally} from './marked/configuration.mjs';
import {getRenderable} from './processing.mjs';
import {renderEntry} from './rendering.mjs';
import {initHighlighter} from './shiki/shiki.mjs';
import {setCurrentSymbol, setSymbols} from './symbol-context.mjs';
import {CliCommandRenderable, DocEntryRenderable} from './entities/renderables.mjs';
import {initHighlighter} from '../../shared/shiki.mjs';
import {setHighlighterInstance} from './shiki/shiki.mjs';
/** The JSON data file format for extracted API reference info. */
interface EntryCollection {
@@ -25,7 +25,7 @@ interface EntryCollection {
moduleLabel?: string;
normalizedModuleName: string;
entries: DocEntry[] | CliCommand[];
symbols: Map<string, string>;
symbols: Record<string, string>;
}
/** Parse all JSON data source files into an array of collections. */
@@ -34,10 +34,15 @@ function parseEntryData(srcs: string[]): EntryCollection[] {
const fileContent = readFileSync(jsonDataFilePath, {encoding: 'utf8'});
const fileContentJson = JSON.parse(fileContent) as unknown;
if ((fileContentJson as EntryCollection).entries) {
return {
...(fileContentJson as EntryCollection),
symbols: new Map((fileContentJson as any).symbols ?? []),
};
const symbols = Object.fromEntries(
// TODO: refactor that, it's dirty and we can probably do better than this.
// We're removing the leading `@angular/` from module names.
(((fileContentJson as any).symbols ?? []) as [string, string][]).map(
([symbol, moduleName]) => [symbol, moduleName.slice(9)],
),
);
return {...(fileContentJson as EntryCollection), symbols};
}
// CLI subcommands should generate a separate file for each subcommand.
@@ -50,7 +55,7 @@ function parseEntryData(srcs: string[]): EntryCollection[] {
moduleName: 'unknown',
normalizedModuleName: 'unknown',
entries: [fileContentJson as DocEntry],
symbols: new Map(),
symbols: {},
},
...command.subcommands!.map((subCommand) => {
return {
@@ -58,7 +63,7 @@ function parseEntryData(srcs: string[]): EntryCollection[] {
moduleName: 'unknown',
normalizedModuleName: 'unknown',
entries: [{...subCommand, parentCommand: command} as any],
symbols: new Map(),
symbols: {},
};
}),
];
@@ -69,7 +74,7 @@ function parseEntryData(srcs: string[]): EntryCollection[] {
moduleName: 'unknown',
normalizedModuleName: 'unknown',
entries: [fileContentJson as DocEntry], // TODO: fix the typing cli entries aren't DocEntry
symbols: new Map(),
symbols: {},
};
});
}
@@ -90,23 +95,14 @@ function getNormalizedFilename(normalizedModuleName: string, entry: DocEntry | C
}
async function main() {
configureMarkedGlobally();
// Shiki highlighter needs to be setup in an async context
await initHighlighter();
setHighlighterInstance(await initHighlighter());
const [paramFilePath] = process.argv.slice(2);
const rawParamLines = readFileSync(paramFilePath, {encoding: 'utf8'}).split('\n');
const [srcs, outputFilenameExecRootRelativePath] = rawParamLines;
// TODO: Remove when we are using Bazel v6+
// On RBE, the output directory is not created properly due to a bug.
// https://github.com/bazelbuild/bazel/commit/4310aeb36c134e5fc61ed5cdfdf683f3e95f19b7.
if (!existsSync(outputFilenameExecRootRelativePath)) {
mkdirSync(outputFilenameExecRootRelativePath, {recursive: true});
}
// Docs rendering happens in three phases that occur here:
// 1) Aggregate all the raw extracted doc info.
// 2) Transform the raw data to a renderable state.
@@ -1,17 +0,0 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {marked} from 'marked';
import {renderer} from './renderer.mjs';
/** Globally configures marked for rendering JsDoc content to HTML. */
export function configureMarkedGlobally() {
marked.use({
renderer,
});
}
@@ -1,92 +0,0 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {Renderer, Tokens} from 'marked';
import {codeToHtml} from '../shiki/shiki.mjs';
import {SECTION_HEADING, SECTION_SUB_HEADING} from '../styling/css-classes.mjs';
/**
* Custom renderer for marked that will be used to transform markdown files to HTML
* files that can be used in the Angular docs.
*/
export const renderer: Partial<Renderer> = {
code({lang, text}): string {
const highlightResult = codeToHtml(text, lang)
// remove spaces/line-breaks between elements to not mess-up `pre` style
.replace(/>\s+</g, '><');
return `
<div class="docs-code" role="group">
${highlightResult}
</div>
`;
},
image({href, title, text}): string {
return `
<img src="${href}" alt="${text}" title="${title}" class="docs-image">
`;
},
link(this: Renderer, {href, tokens}): string {
return `<a href="${href}">${this.parser.parseInline(tokens)}</a>`;
},
list(this: Renderer, {items, ordered, start}) {
if (ordered) {
return `
<ol class="docs-ordered-list">
${items.map((item) => this.listitem(item)).join('')}
</ol>
`;
}
return `
<ul class="docs-list">
${items.map((item) => this.listitem(item)).join('')}
</ul>
`;
},
table(this: Renderer, {header, rows}: Tokens.Table) {
return `
<div class="docs-table docs-scroll-track-transparent">
<table>
<thead>
${this.tablerow({text: header.map((cell) => this.tablecell(cell)).join('')})}
</thead>
<tbody>
${rows
.map((row) => this.tablerow({text: row.map((cell) => this.tablecell(cell)).join('')}))
.join('')}
</tbody>
</table>
</div>
`;
},
heading(this: Renderer, {text, depth, tokens}: Tokens.Heading) {
const id = text
.toLowerCase()
.replaceAll(' ', '-')
.replace(/[^a-z0-9-]/g, '');
// Since we have a code transformer `addApiLinksToHtml` which adds anchors
// to code blocks of known symbols, we add an additional `data-skip-anchor`
// attribute that prevents the transformation. This is needed since nested
// anchor tags are illegal and break the HTML.
const textRenderer = new Renderer();
textRenderer.codespan = ({text}) => `<code data-skip-anchor>${text}</code>`;
const parsedText = this.parser.parseInline(tokens, textRenderer);
// The template matches templates/section-heading.tsx
return `
<h${depth} id="${id}" class="${SECTION_HEADING} ${SECTION_SUB_HEADING}">
<a href="#${id}" aria-label="Link to ${text} section" tabIndex="-1">
${parsedText}
</a>
</h${depth}>
`;
},
};
@@ -1,196 +0,0 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import * as blockC from './region-matchers/block-c.mjs';
import * as html from './region-matchers/html.mjs';
import * as inlineC from './region-matchers/inline-c.mjs';
import * as inlineCOnly from './region-matchers/inline-c-only.mjs';
import * as inlineHash from './region-matchers/inline-hash.mjs';
import {FileType, removeEslintComments} from './remove-eslint-comments.mjs';
const WHOLE_FILE_REGION_NAME = '';
const DEFAULT_PLASTER = '. . .';
const REGION_MATCHERS = {
ts: inlineC,
js: inlineC,
mjs: inlineCOnly,
es6: inlineC,
html: html,
svg: html,
css: blockC,
conf: inlineHash,
yaml: inlineHash,
yml: inlineHash,
sh: inlineHash,
jade: inlineCOnly,
pug: inlineCOnly,
json: inlineCOnly,
'json.annotated': inlineCOnly,
};
interface Region {
lines: string[];
open?: boolean;
ranges: {from: number; to?: number}[];
}
/**
* NOTE: We assume that the tag defining the beginning and end of the region will be in different lines in each case.
* For example, in HTML, we don't expect to have the following code on one line: <!-- docregion name -->content<!--enddocregion name-->
*/
export const regionParser = (contents: string, filePath: string) => {
const fileType: FileType | undefined = filePath?.split('.').pop() as FileType;
if (!fileType) {
throw new Error(`Incorrect file type for region parser: ${filePath}!`);
}
const regionMatcher = REGION_MATCHERS[fileType];
const openRegions: string[] = [];
const regionMap: Record<string, Region> = {};
let countOfRegionLines = 0;
if (regionMatcher) {
let plaster = regionMatcher.createPlasterComment(DEFAULT_PLASTER);
const lines = removeEslintComments(contents, fileType)
.split(/\r?\n/)
.filter((line, index) => {
const startRegion = line.match(regionMatcher.regionStartMatcher);
const endRegion = line.match(regionMatcher.regionEndMatcher);
const updatePlaster = line.match(regionMatcher.plasterMatcher);
// start region processing
if (startRegion) {
// open up the specified region
handleStartRegion(
startRegion,
regionMap,
index,
countOfRegionLines,
plaster,
openRegions,
);
} else if (endRegion) {
// end region processing
handleEndRegion(openRegions, endRegion, regionMap, index, countOfRegionLines);
} else if (updatePlaster) {
// doc plaster processing
const plasterString = updatePlaster[1].trim();
plaster = plasterString ? regionMatcher.createPlasterComment(plasterString) : '';
} else {
// simple line of content processing
openRegions.forEach((regionName) => regionMap[regionName].lines.push(line));
// do not filter out this line from the content
return true;
}
// this line contained an annotation so let's filter it out
countOfRegionLines++;
return false;
});
if (!regionMap[WHOLE_FILE_REGION_NAME]) {
regionMap[WHOLE_FILE_REGION_NAME] = {lines, ranges: [{from: 1, to: lines.length + 1}]};
}
return {
contents: lines.join('\n'),
regionMap,
totalLinesCount: lines.length,
};
} else {
return {contents, regionMap, totalLinesCount: 0};
}
};
function handleStartRegion(
startRegion: RegExpMatchArray,
regionMap: Record<string, Region>,
index: number,
countOfRegionLines: number,
plaster: string,
openRegions: string[],
) {
const regionNames = getRegionNames(startRegion[1]);
if (regionNames.length === 0) {
regionNames.push(WHOLE_FILE_REGION_NAME);
}
for (const regionName of regionNames) {
const region = regionMap[regionName];
if (region) {
if (region.open) {
throw new Error(`Tried to open a region, named "${regionName}", that is already open`);
}
// Region is opened, set from range value.
region.open = true;
region.ranges.push({from: getFromRangeValue(index, countOfRegionLines)});
if (plaster) {
// Use the same indent as the docregion marker
const indent = startRegion[0].split(/[^ ]/, 1);
region.lines.push(indent + plaster);
}
} else {
regionMap[regionName] = {
lines: [],
open: true,
ranges: [
{
from: getFromRangeValue(index, countOfRegionLines),
},
],
};
}
openRegions.push(regionName);
}
}
function handleEndRegion(
openRegions: string[],
endRegion: RegExpMatchArray,
regionMap: Record<string, Region>,
index: number,
countOfRegionLines: number,
) {
if (openRegions.length === 0) {
throw new Error('Tried to close a region when none are open');
}
// close down the specified region (or most recent if no name is given)
const regionNames = getRegionNames(endRegion[1]);
if (regionNames.length === 0) {
regionNames.push(openRegions[openRegions.length - 1]);
}
for (const regionName of regionNames) {
const region = regionMap[regionName];
if (!region || !region.open) {
throw new Error(`Tried to close a region, named "${regionName}", that is not open`);
}
// Region is closed, we can define the last line number of the region
region.open = false;
region.ranges[region.ranges.length - 1].to = index - countOfRegionLines;
removeLast(openRegions, regionName);
}
}
function getFromRangeValue(index: number, countOfRegionLines: number): number {
return index - countOfRegionLines + 1;
}
function getRegionNames(input: string): string[] {
return input.trim() === '' ? [] : input.split(',').map((name) => name.trim());
}
function removeLast(array: string[], item: string): void {
const index = array.lastIndexOf(item);
array.splice(index, 1);
}
-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;
}
@@ -6,41 +6,24 @@
* found in the LICENSE file at https://angular.dev/license
*/
let highlighter: any;
import {HighlighterGeneric} from 'shiki';
export async function initHighlighter() {
const {createHighlighter} = await import('shiki');
highlighter = await createHighlighter({
themes: ['github-light', 'github-dark'],
langs: [
'javascript',
'typescript',
'angular-html',
'angular-ts',
'shell',
'html',
'http',
'json',
'jsonc',
'nginx',
'markdown',
'apache',
],
});
/**
* Singleton instance of the Shiki highlighter used during API page generation.
*
* TODO: Consider removing this singleton pattern if we find a better alternative.
*/
let highlighter: HighlighterGeneric<any, any>;
export function setHighlighterInstance(instance: HighlighterGeneric<any, any>) {
highlighter = instance;
}
export function codeToHtml(code: string, language: string | undefined): string {
const html = highlighter.codeToHtml(code, {
lang: language ?? 'text',
themes: {
light: 'github-light',
dark: 'github-dark',
},
cssVariablePrefix: '--shiki-',
defaultColor: false,
});
return html;
export function getHighlighterInstance(): HighlighterGeneric<any, any> {
if (!highlighter) {
throw new Error(
'Shiki highlighter has not been initialized. Make sure to call `setHighlighterInstance`.',
);
}
return highlighter;
}
/**
@@ -6,30 +6,17 @@
* found in the LICENSE file at https://angular.dev/license
*/
import {getSymbolUrl as sharedGetSymbolUrl} from '../../shared/linking.mjs';
/**
* API pages are generated each package at a time.
* This allows to use a global context to store the symbols and their corresponding module names.
* This allows us to use a global context to store the symbols and their corresponding module names.
*/
let symbols = new Map<string, string>();
let symbols: Record<string, string> = {};
// This is used to store the currently processed symbol (usually a class or an interface)
let currentSymbol: string | undefined;
export function setSymbols(newSymbols: Map<string, string>): void {
symbols = newSymbols;
}
/**
* Returns the module name of a symbol.
* eg: 'ApplicationRef' => 'core', 'FormControl' => 'forms'
* Also supports class.member, 'NgZone.runOutsideAngular => 'core'
*/
export function getModuleName(symbol: string): string | undefined {
const moduleName = symbols.get(symbol);
return moduleName?.replace('@angular/', '');
}
export function setCurrentSymbol(symbol: string): void {
currentSymbol = symbol;
}
@@ -38,6 +25,14 @@ export function getCurrentSymbol(): string | undefined {
return currentSymbol;
}
export function setSymbols(newSymbols: Record<string, string>): void {
symbols = newSymbols;
}
export function getSymbolUrl(symbol: string): string | undefined {
return sharedGetSymbolUrl(symbol, symbols);
}
export function unknownSymbolMessage(link: string, symbol: string): string {
return `WARNING: {@link ${link}} is invalid, ${symbol} or ${currentSymbol}.${symbol} is unknown in this context`;
}
@@ -20,9 +20,10 @@ import {SectionDescription} from './section-description';
import {SectionUsageNotes} from './section-usage-notes';
import {SectionApi} from './section-api';
import {SectionHeading} from './section-heading';
import {codeToHtml} from '../shiki/shiki.mjs';
import {RawHtml} from './raw-html';
import {DeprecationWarning} from './deprecation-warning';
import {codeToHtml} from '../../../shared/shiki.mjs';
import {getHighlighterInstance} from '../shiki/shiki.mjs';
/** Component to render a class API reference document. */
export function ClassReference(entry: ClassEntryRenderable | PipeEntryRenderable) {
@@ -33,7 +34,13 @@ export function ClassReference(entry: ClassEntryRenderable | PipeEntryRenderable
<>
<div className={SECTION_CONTAINER + ' docs-reference-api-section'}>
<SectionHeading name="Pipe usage" />
<RawHtml value={codeToHtml((entry as PipeEntry).usage, 'angular-html')} />
<RawHtml
value={codeToHtml(
getHighlighterInstance(),
(entry as PipeEntry).usage,
'angular-html',
)}
/>
</div>
</>
) : (
@@ -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> : <></>}
@@ -7,8 +7,7 @@
*/
import {h} from 'preact';
import {getModuleName} from '../symbol-context.mjs';
import {getLinkToModule} from '../transforms/url-transforms.mjs';
import {getSymbolUrl} from '../symbol-context.mjs';
const symbolRegex = /([a-zA-Z_$][a-zA-Z_$0-9\.]*)/;
@@ -23,11 +22,8 @@ export function CodeSymbol(props: {code: string}) {
// Every even index is a non-match when the regex has 1 capturing group
if (index % 2 === 0) return rawSymbol;
let [symbol, subSymbol] = rawSymbol.split('.'); // Also takes care of methods, enum value etc.
const moduleName = getModuleName(symbol);
if (moduleName) {
const url = getLinkToModule(moduleName, symbol, subSymbol);
const url = getSymbolUrl(rawSymbol);
if (url) {
return <a href={url}>{rawSymbol}</a>;
}
@@ -8,11 +8,13 @@
import {h} from 'preact';
import {RawHtml} from './raw-html';
import {codeToHtml} from '../shiki/shiki.mjs';
import {codeToHtml} from '../../../shared/shiki.mjs';
import {get} from 'http';
import {getHighlighterInstance} from '../shiki/shiki.mjs';
/** Component to render a header of the CLI page. */
export function HighlightTypeScript(props: {code: string}) {
const result = codeToHtml(props.code, 'typescript');
const result = codeToHtml(getHighlighterInstance(), props.code, 'typescript');
const withScrollTrack = result.replace(/^(<pre class="shiki)/, '$1 docs-mini-scroll-track');
return <RawHtml value={withScrollTrack} className="docs-code" />;
@@ -21,6 +21,7 @@ ts_project(
"//adev:node_modules/@types/jsdom",
"//adev:node_modules/jsdom",
"//adev/shared-docs/pipeline/api-gen/rendering:render_api_to_html_lib",
"//adev/shared-docs/pipeline/shared:shiki",
],
)
@@ -9,18 +9,17 @@
import {resolve} from 'path';
import {readFile} from 'fs/promises';
import {JSDOM} from 'jsdom';
import {configureMarkedGlobally} from '../marked/configuration.mjs';
import {getRenderable} from '../processing.mjs';
import {renderEntry} from '../rendering.mjs';
import {initHighlighter} from '../shiki/shiki.mjs';
import {initHighlighter} from '../../../shared/shiki.mjs';
import {setHighlighterInstance} from '../shiki/shiki.mjs';
describe('CLI docs to html', () => {
let fragment: DocumentFragment;
let entryJson: any;
beforeAll(async () => {
await initHighlighter();
await configureMarkedGlobally();
setHighlighterInstance(await initHighlighter());
const entryContent = await readFile(resolve('./fake-cli-entries.json'), {
encoding: 'utf-8',
@@ -1276,14 +1276,14 @@
}
],
"symbols": [
["AfterRenderPhase", "core"],
["afterRender", "core"],
["EmbeddedViewRef", "core"],
["ChangeDetectionStrategy", "core"],
["ChangeDetectorRef", "core"],
["withNoHttpTransferCache", "platform-browser"],
["withHttpTransferCacheOptions", "platform-browser"],
["withI18nSupport", "platform-browser"],
["withEventReplay", "platform-browser"]
["AfterRenderPhase", "@angular/core"],
["afterRender", "@angular/core"],
["EmbeddedViewRef", "@angular/core"],
["ChangeDetectionStrategy", "@angular/core"],
["ChangeDetectorRef", "@angular/core"],
["withNoHttpTransferCache", "@angular/platform-browser"],
["withHttpTransferCacheOptions", "@angular/platform-browser"],
["withI18nSupport", "@angular/platform-browser"],
["withEventReplay", "@angular/platform-browser"]
]
}
@@ -8,12 +8,12 @@
import {readFile} from 'fs/promises';
import {JSDOM} from 'jsdom';
import {configureMarkedGlobally} from '../marked/configuration.mjs';
import {getRenderable} from '../processing.mjs';
import {renderEntry} from '../rendering.mjs';
import {initHighlighter} from '../shiki/shiki.mjs';
import {setSymbols} from '../symbol-context.mjs';
import {resolve} from 'path';
import {initHighlighter} from '../../../shared/shiki.mjs';
import {setHighlighterInstance} from '../shiki/shiki.mjs';
// Note: The tests will probably break if the schema of the api extraction changes.
// All entries in the fake-entries are extracted from Angular's api.
@@ -24,14 +24,13 @@ describe('markdown to html', () => {
const entries2 = new Map<string, string>();
beforeAll(async () => {
await initHighlighter();
await configureMarkedGlobally();
setHighlighterInstance(await initHighlighter());
const entryContent = await readFile(resolve('./fake-entries.json'), {
encoding: 'utf-8',
});
const entryJson = JSON.parse(entryContent) as any;
const symbols = new Map<string, string>([
const symbols = Object.fromEntries([
['AfterRenderPhase', 'core'],
['afterRender', 'core'],
['EmbeddedViewRef', 'core'],
@@ -8,11 +8,11 @@
import {readFile} from 'fs/promises';
import {DocEntryRenderable} from '../entities/renderables.mjs';
import {configureMarkedGlobally} from '../marked/configuration.mjs';
import {getRenderable} from '../processing.mjs';
import {initHighlighter} from '../shiki/shiki.mjs';
import {setSymbols} from '../symbol-context.mjs';
import {resolve} from 'path';
import {initHighlighter} from '../../../shared/shiki.mjs';
import {setHighlighterInstance} from '../shiki/shiki.mjs';
// Note: The tests will probably break if the schema of the api extraction changes.
// All entries in the fake-entries are extracted from Angular's api.
@@ -22,14 +22,13 @@ describe('renderable', () => {
const entries = new Map<string, DocEntryRenderable>();
beforeAll(async () => {
await initHighlighter();
await configureMarkedGlobally();
setHighlighterInstance(await initHighlighter());
const entryContent = await readFile(resolve('./fake-entries.json'), {
encoding: 'utf-8',
});
const entryJson = JSON.parse(entryContent) as any;
const symbols = new Map<string, string>([
const symbols = Object.fromEntries([
['AfterRenderPhase', 'core'],
['afterRender', 'core'],
['EmbeddedViewRef', 'core'],
@@ -14,7 +14,7 @@ describe('jsdoc transforms', () => {
it('should transform links', () => {
setCurrentSymbol('Router');
setSymbols(
new Map([
Object.fromEntries([
['Route', 'test'],
['Router', 'test'],
['Router.someMethod', 'test'],
@@ -34,16 +34,16 @@ import {
} from '../entities/categorization.mjs';
import {CodeLineRenderable} from '../entities/renderables.mjs';
import {HasModuleName, HasRenderableToc} from '../entities/traits.mjs';
import {getModuleName} from '../symbol-context.mjs';
import {getSymbolUrl} from '../symbol-context.mjs';
import {
codeToHtml,
getHighlighterInstance,
insertParenthesesForDecoratorInShikiHtml,
replaceKeywordFromShikiHtml,
} from '../shiki/shiki.mjs';
import {filterLifecycleMethods, mergeGettersAndSetters} from './member-transforms.mjs';
import {getLinkToModule} from './url-transforms.mjs';
import {formatJs} from './format-code.mjs';
import {codeToHtml} from '../../../shared/shiki.mjs';
const INDENT = ' ';
const SPACE = ' ';
@@ -85,7 +85,11 @@ export async function addRenderableCodeToc<T extends DocEntry & HasModuleName>(
formattedCode = await formatJs(metadata.contents);
}
let codeWithSyntaxHighlighting = codeToHtml(formattedCode ?? metadata?.contents, 'typescript');
let codeWithSyntaxHighlighting = codeToHtml(
getHighlighterInstance(),
formattedCode ?? metadata?.contents,
'typescript',
);
if (isDecoratorEntry(entry)) {
// Shiki requires a keyword for correct formating of Decorators
@@ -525,14 +529,9 @@ export function addApiLinksToHtml(htmlString: string): string {
// The captured content ==> vvvvvvvv
/(?<!<a[^>]*>)(<(?:(?:span)|(?:code))(?!\sdata-skip-anchor)[^>]*>\s*)([^<]*?)(\s*<\/(?:span|code)>)/g,
(type: string, span1: string, potentialSymbolName: string, span2: string) => {
const [symbol, subSymbol] = potentialSymbolName.split(/(?:#|\.)/) as [string, string?];
// mySymbol() => mySymbol
const symbolWithoutInvocation = symbol.replace(/\([^)]*\);?/g, '');
const moduleName = getModuleName(symbolWithoutInvocation);
if (moduleName) {
return `${span1}<a href="${getLinkToModule(moduleName, symbol, subSymbol)}">${potentialSymbolName}</a>${span2}`;
const url = getSymbolUrl(potentialSymbolName);
if (url) {
return `${span1}<a href="${url}">${potentialSymbolName}</a>${span2}`;
}
return type;
@@ -25,9 +25,8 @@ import {
HasStableFlag,
} from '../entities/traits.mjs';
import {getLinkToModule} from './url-transforms.mjs';
import {addApiLinksToHtml} from './code-transforms.mjs';
import {getCurrentSymbol, getModuleName, unknownSymbolMessage} from '../symbol-context.mjs';
import {getCurrentSymbol, getSymbolUrl, unknownSymbolMessage} from '../symbol-context.mjs';
const JS_DOC_USAGE_NOTE_TAGS: Set<string> = new Set(['remarks', 'usageNotes', 'example']);
export const JS_DOC_SEE_TAG = 'see';
@@ -141,7 +140,11 @@ function getHtmlAdditionalLinks<T extends HasJsDocTags>(entry: T): LinkEntryRend
if (linkMatch) {
const link = linkMatch[1];
const {url, label} = parseAtLink(link);
const parsed = parseAtLink(link);
if (!parsed) {
return undefined;
}
const {url, label} = parsed;
return {label, url};
}
@@ -168,13 +171,17 @@ function wrapExampleHtmlElementsWithCode(text: string) {
*/
function convertLinks(text: string) {
return text.replace(jsDoclinkRegexGlobal, (_, link) => {
const {label, url} = parseAtLink(link);
const parsed = parseAtLink(link);
if (!parsed) {
return `<code>${link}</code>`; // leave the link as-is if we can't parse it
}
const {label, url} = parsed;
return `<a href="${url}"><code>${label}</code></a>`;
});
}
function parseAtLink(link: string): {label: string; url: string} {
function parseAtLink(link: string): {label: string; url: string} | undefined {
// Because of microsoft/TypeScript/issues/59679
// getTextOfJSDocComment introduces an extra space between the symbol and a trailing ()
link = link.replace(/ \(\)$/, '');
@@ -195,24 +202,18 @@ function parseAtLink(link: string): {label: string; url: string} {
};
}
let [symbol, subSymbol] = rawSymbol.replace(/\(\)$/, '').split(/(?:#|\.)/);
let moduleName = getModuleName(symbol);
let url = getSymbolUrl(rawSymbol);
const label = description ?? rawSymbol;
const currentSymbol = getCurrentSymbol();
if (!url) {
const currentSymbol = getCurrentSymbol();
// 2nd attempt, try to get the module name in the context of the current symbol
url = getSymbolUrl(`${currentSymbol}.${rawSymbol}`);
if (!moduleName) {
// 2nd attemp, try to get the module name in the context of the current symbol
moduleName = getModuleName(`${currentSymbol}.${symbol}`);
if (!moduleName || !currentSymbol) {
throw unknownSymbolMessage(link, symbol);
if (!url || !currentSymbol) {
throw unknownSymbolMessage(link, rawSymbol);
}
subSymbol = symbol;
symbol = currentSymbol;
}
return {label, url: getLinkToModule(moduleName, symbol, subSymbol)};
return {label, url};
}
@@ -7,7 +7,6 @@
*/
export const API_PREFIX = 'api';
export const MODULE_NAME_PREFIX = '@angular/';
export function getLinkToModule(moduleName: string, symbol: string, subSymbol?: string) {
return `/${API_PREFIX}/${moduleName}/${symbol}${subSymbol ? `#${subSymbol}` : ''}`;
@@ -18,7 +18,7 @@ ts_project(
"//adev:node_modules/jsdom",
"//adev:node_modules/tinyglobby",
"//adev/shared-docs/pipeline/examples/shared",
"//adev/shared-docs/pipeline/guides:guides_lib",
"//adev/shared-docs/pipeline/shared/regions",
],
)
@@ -11,10 +11,10 @@ import {readFile} from 'fs/promises';
import {copyFolder, createFolder, removeFolder} from '../shared/file-system.mjs';
import jsdom from 'jsdom';
import {glob} from 'tinyglobby';
import {regionParser} from '../../guides/extensions/docs-code/regions/region-parser.mjs';
import {appendCopyrightToFile} from '../shared/copyright.mjs';
import {FileType} from '../../guides/extensions/docs-code/sanitizers/eslint.mjs';
import {EXCLUDE_FILES_FOR_STACKBLITZ, STACKBLITZ_CONFIG_FILENAME} from './defaults.mjs';
import {regionParser} from '../../shared/regions/region-parser.mjs';
import {FileType} from '../../shared/regions/remove-eslint-comments.mjs';
interface StackblitzConfig {
title: string;
@@ -18,7 +18,7 @@ ts_project(
"//adev:node_modules/tinyglobby",
"//adev/shared-docs/interfaces",
"//adev/shared-docs/pipeline/examples/shared",
"//adev/shared-docs/pipeline/guides:guides_lib",
"//adev/shared-docs/pipeline/shared/regions",
],
)
@@ -10,13 +10,13 @@ import {join} from 'path';
import {readFile} from 'fs/promises';
import {copyFolder, createFolder} from '../shared/file-system.mjs';
import {glob} from 'tinyglobby';
import {regionParser} from '../../guides/extensions/docs-code/regions/region-parser.mjs';
import {appendCopyrightToFile} from '../shared/copyright.mjs';
import {FileType} from '../../guides/extensions/docs-code/sanitizers/eslint.mjs';
import {EXCLUDE_FILES, CONFIG_FILENAME} from './defaults.mjs';
import {zip, strToU8} from 'fflate';
import {FileAndContent} from '../../../interfaces';
import {FileType} from '../../shared/regions/remove-eslint-comments.mjs';
import {regionParser} from '../../shared/regions/region-parser.mjs';
interface ZipConfig {
ignore: string[];
+4 -11
View File
@@ -53,7 +53,6 @@ ts_project(
srcs = glob(
[
"**/*.mts",
"shiki.d.ts",
],
exclude = ["index.mts"],
),
@@ -61,16 +60,8 @@ ts_project(
"//adev/shared-docs:__subpackages__",
],
deps = [
"//adev:node_modules/@types/jsdom",
"//adev:node_modules/@types/node",
"//adev:node_modules/diff",
"//adev:node_modules/emoji-regex",
"//adev:node_modules/html-entities",
"//adev:node_modules/jsdom",
"//adev:node_modules/marked",
"//adev:node_modules/mermaid",
"//adev:node_modules/playwright-core",
"//adev:node_modules/shiki",
"//adev/shared-docs/pipeline/shared:shiki",
"//adev/shared-docs/pipeline/shared/marked",
],
)
@@ -85,5 +76,7 @@ ts_project(
deps = [
":guides_lib",
"//adev:node_modules/@types/node",
"//adev/shared-docs/pipeline/shared:shiki",
"//adev/shared-docs/pipeline/shared/marked",
],
)
@@ -1,13 +0,0 @@
/*!
* @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
*/
// These kind of comments are used CSS and other languages that do not support inline comments
export const regionStartMatcher = /^\s*\/\*\s*#docregion\s*(.*)\s*\*\/\s*$/;
export const regionEndMatcher = /^\s*\/\*\s*#enddocregion\s*(.*)\s*\*\/\s*$/;
export const plasterMatcher = /^\s*\/\*\s*#docplaster\s*(.*)\s*\*\/\s*$/;
export const createPlasterComment = (plaster: string) => `/* ${plaster} */`;
@@ -1,14 +0,0 @@
/*!
* @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
*/
// These kind of comments are used in HTML
export const regionStartMatcher = /^\s*<!--\s*#docregion\s*(.*?)\s*(?:-->)?\s*$/;
export const regionEndMatcher = /^\s*<!--\s*#enddocregion\s*(.*?)\s*-->\s*$/;
export const plasterMatcher = /^\s*<!--\s*#docplaster\s*(.*?)\s*-->\s*$/;
export const createPlasterComment = (plaster: string) => `<!-- ${plaster} -->`;
@@ -1,13 +0,0 @@
/*!
* @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
*/
// These kind of comments are used in languages that do not support block comments, such as Jade
export const regionStartMatcher = /^\s*\/\/\s*#docregion\s*(.*)\s*$/;
export const regionEndMatcher = /^\s*\/\/\s*#enddocregion\s*(.*)\s*$/;
export const plasterMatcher = /^\s*\/\/\s*#docplaster\s*(.*)\s*$/;
export const createPlasterComment = (plaster: string) => `// ${plaster}`;
@@ -1,13 +0,0 @@
/*!
* @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
*/
// This comment type is used in C like languages such as JS, TS, etc
export const regionStartMatcher = /^\s*\/\/\s*#docregion\s*(.*)\s*$/;
export const regionEndMatcher = /^\s*\/\/\s*#enddocregion\s*(.*)\s*$/;
export const plasterMatcher = /^\s*\/\/\s*#docplaster\s*(.*)\s*$/;
export const createPlasterComment = (plaster: string) => `/* ${plaster} */`;
@@ -1,13 +0,0 @@
/*!
* @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
*/
// These type of comments are used in hash comment based languages such as bash and Yaml
export const regionStartMatcher = /^\s*#\s*#docregion\s*(.*)\s*$/;
export const regionEndMatcher = /^\s*#\s*#enddocregion\s*(.*)\s*$/;
export const plasterMatcher = /^\s*#\s*#docplaster\s*(.*)\s*$/;
export const createPlasterComment = (plaster: string) => `# ${plaster}`;
@@ -1,61 +0,0 @@
/*!
* @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 type FileType =
| 'ts'
| 'js'
| 'mjs'
| 'es6'
| 'html'
| 'svg'
| 'css'
| 'conf'
| 'yaml'
| 'yml'
| 'sh'
| 'jade'
| 'pug'
| 'json'
| 'json.annotated';
/**
* Remove any ESLint comments from the provided code string. This is particularly useful as we may
* want to store code formatted for an example that would not be allowed in our repo. For instance,
* we can disable ESLint to allow for a `console` usage, despite not allowing it typically, so that
* it can be used in an example in documenation.
*/
export function removeEslintComments(input: string, fileType: FileType) {
if (!input || (fileType !== 'ts' && fileType !== 'js' && fileType !== 'html')) {
return input;
}
return input.replace(regexesForFileTypes[fileType], '');
}
const jsRegexes = [
/\/\/ *eslint-disable(?:-next-line)?(?: .*)?(?:\n *|$)/,
/\n? *\/\/ *eslint-(?:disable-line|enable)(?: .*)?(?=\n|$)/,
/\/\*\s*eslint-disable(?:-next-line)?(?: [\s\S]*?)?\*\/ *(?:\n *)?/,
/\n? *\/\*\s*eslint-(?:disable-line|enable)(?: [\s\S]*?)?\*\//,
];
const htmlRegexes = [
/<!--\s*eslint-disable(?:-next-line)?(?: [\s\S]*?)?--> *(?:\n *)?/,
/\n? *<!--\s*eslint-(?:disable-line|enable)(?: [\s\S]*?)?-->/,
];
const joinRegexes = (regexes: any) =>
new RegExp(regexes.map((regex: any) => `(?:${regex.source})`).join('|'), 'g');
const htmlRegex = joinRegexes(htmlRegexes);
// Note: the js regex needs to also include the html ones to account for inline templates in @Components
const jsRegex = joinRegexes([...jsRegexes, ...htmlRegexes]);
const regexesForFileTypes = {
js: jsRegex,
ts: jsRegex,
html: htmlRegex,
};
+44 -5
View File
@@ -8,25 +8,45 @@
import {readFileSync, writeFileSync} from 'fs';
import path from 'path';
import {parseMarkdown} from './parse.mjs';
import {initHighlighter} from './extensions/docs-code/format/highlight.mjs';
import {initHighlighter} from '../shared/shiki.mjs';
import {parseMarkdownAsync} from '../shared/marked/parse.mjs';
type ApiManifest = ApiManifestPackage[];
interface ApiManifestPackage {
moduleName: string;
entries: {name: string}[];
}
async function main() {
const [paramFilePath] = process.argv.slice(2);
const rawParamLines = readFileSync(paramFilePath, {encoding: 'utf8'}).split('\n');
const [srcs, outputFilenameExecRootRelativePath] = rawParamLines;
const [srcs, outputFilenameExecRootRelativePath, apiManifestPath] = rawParamLines;
// The highlighter needs to be setup asynchronously
// so we're doing it at the start of the pipeline
await initHighlighter();
const highlighter = await initHighlighter();
for (const filePath of srcs.split(',')) {
if (!filePath.endsWith('.md')) {
throw new Error(`Input file "${filePath}" does not end in a ".md" file extension.`);
}
let apiManifest: ApiManifest = [];
if (apiManifestPath) {
try {
const apiManifestStr = readFileSync(apiManifestPath, {encoding: 'utf8'});
apiManifest = JSON.parse(apiManifestStr);
} catch (error) {
console.warn('Failed to load API entries:', error);
}
}
const markdownContent = readFileSync(filePath, {encoding: 'utf8'});
const htmlOutputContent = await parseMarkdown(markdownContent, {markdownFilePath: filePath});
const htmlOutputContent = await parseMarkdownAsync(markdownContent, {
markdownFilePath: filePath,
apiEntries: mapManifestToEntries(apiManifest),
highlighter,
});
// The expected file name structure is the [name of the file].md.html.
const htmlFileName = filePath + '.html';
@@ -37,3 +57,22 @@ async function main() {
}
main();
function mapManifestToEntries(apiManifest: ApiManifest): Record<string, string> {
const duplicateEntries = new Set<string>();
const entryToModuleMap: Record<string, string> = {};
for (const pkg of apiManifest) {
for (const entry of pkg.entries) {
if (duplicateEntries.has(entry.name)) {
continue;
} else if (entryToModuleMap[entry.name]) {
delete entryToModuleMap[entry.name];
duplicateEntries.add(entry.name);
} else {
entryToModuleMap[entry.name] = pkg.moduleName.replace(/^@angular\//, '');
}
}
}
return entryToModuleMap;
}
@@ -1,58 +0,0 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {marked} from 'marked';
import {hooks} from './hooks.mjs';
import {Renderer} from './renderer.mjs';
import {docsAlertExtension} from './extensions/docs-alert.mjs';
import {docsCalloutExtension} from './extensions/docs-callout.mjs';
import {docsPillExtension} from './extensions/docs-pill/docs-pill.mjs';
import {docsPillRowExtension} from './extensions/docs-pill/docs-pill-row.mjs';
import {docsVideoExtension} from './extensions/docs-video.mjs';
import {docsWorkflowExtension} from './extensions/docs-workflow/docs-workflow.mjs';
import {docsStepExtension} from './extensions/docs-workflow/docs-step.mjs';
import {docsCardExtension} from './extensions/docs-card/docs-card.mjs';
import {docsCardContainerExtension} from './extensions/docs-card/docs-card-container.mjs';
import {docsDecorativeHeaderExtension} from './extensions/docs-decorative-header.mjs';
import {docsCodeBlockExtension} from './extensions/docs-code/docs-code-block.mjs';
import {docsCodeExtension} from './extensions/docs-code/docs-code.mjs';
import {docsCodeMultifileExtension} from './extensions/docs-code/docs-code-multifile.mjs';
import {ParserContext, setContext} from './utils.mjs';
import {walkTokens} from './walk-tokens.mjs';
export async function parseMarkdown(
markdownContent: string,
context: ParserContext,
): Promise<string> {
setContext(context);
marked.use({
hooks,
extensions: [
docsAlertExtension,
docsCalloutExtension,
docsPillExtension,
docsPillRowExtension,
docsVideoExtension,
docsWorkflowExtension,
docsStepExtension,
docsCardExtension,
docsCardContainerExtension,
docsDecorativeHeaderExtension,
docsCodeBlockExtension,
docsCodeExtension,
docsCodeMultifileExtension,
],
walkTokens,
// The async option causes marked to await walkTokens functions before parsing the tokens and returning an HTML string.
// We leverage this to allow us to use async libraries like mermaid and building stackblitz examples.
async: true,
});
return marked.parse(markdownContent, {renderer: new Renderer()});
}
@@ -1,28 +0,0 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {Renderer as _Renderer} from 'marked';
import {linkRender} from './tranformations/link.mjs';
import {tableRender} from './tranformations/table.mjs';
import {listRender} from './tranformations/list.mjs';
import {imageRender} from './tranformations/image.mjs';
import {textRender} from './tranformations/text.mjs';
import {headingRender} from './tranformations/heading.mjs';
/**
* Custom renderer for marked that will be used to transform markdown files to HTML
* files that can be used in the Angular docs.
*/
export class Renderer extends _Renderer {
override link = linkRender;
override table = tableRender;
override list = listRender;
override image = imageRender;
override text = textRender;
override heading = headingRender;
}
-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;
}
@@ -1,50 +0,0 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {existsSync, readFileSync} from 'fs';
import {join} from 'path';
import {cwd} from 'process';
// TODO(josephperrott): Set edit content url based on the owner, repo and branch.
/** The base url for edting the a file in the repository. */
const GITHUB_EDIT_CONTENT_URL = 'https://github.com/angular/angular/edit/main';
/** Get the page title with edit button to modify the page source. */
export function getPageTitle(text: string): string {
return `
<!-- Page title -->
<div class="docs-page-title">
<h1 tabindex="-1">${text}</h1>
<a class="docs-github-links" target="_blank" href="${GITHUB_EDIT_CONTENT_URL}/${context?.markdownFilePath}" title="Edit this page" aria-label="Edit this page">
<!-- Pencil -->
<docs-icon role="presentation">edit</docs-icon>
</a>
</div>`;
}
/** Configuration using environment for parser, providing context. */
export interface ParserContext {
markdownFilePath?: string;
}
let context: ParserContext = {};
export function setContext(envContext: Partial<ParserContext>) {
context = envContext;
}
/** The base directory of the workspace the script is running in. */
const WORKSPACE_DIR = cwd();
export function loadWorkspaceRelativeFile(filePath: string): string {
const fullFilePath = join(WORKSPACE_DIR, filePath);
if (!existsSync(fullFilePath)) {
throw Error(`Cannot find: ${filePath}`);
}
return readFileSync(fullFilePath, {encoding: 'utf-8'});
}
@@ -1,38 +0,0 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {Token} from 'marked';
import {DocsCodeToken} from './extensions/docs-code/docs-code.mjs';
/**
* Describe a HANDLE_MERMAID value which esbuild will use at build time to determine if the mermaid
* related code should be included in the bundle.
* THIS VALUE IS NOT AVAILABLE AT RUNTIME.
*/
export declare const HANDLE_MERMAID: boolean;
/** Type guard for if a provided token is the DocsCodeToken. */
function isDocsCodeToken(token: Token): token is DocsCodeToken {
return !!(token as DocsCodeToken).language;
}
/**
* Handle the provided token based on the token itself replacing its content/data in place
* as appropriate.
*/
let mermaid: typeof import('./mermaid/index.mjs');
export async function walkTokens(token: Token): Promise<void> {
if (!isDocsCodeToken(token) || token.language !== 'mermaid') {
return;
}
if (HANDLE_MERMAID) {
mermaid ??= await import('./mermaid/index.mjs');
return mermaid.processMermaidCodeBlock(token);
}
}
@@ -0,0 +1,22 @@
load("//adev/shared-docs:defaults.bzl", "ts_project")
package(default_visibility = ["//visibility:public"])
ts_project(
name = "linking",
srcs = ["linking.mts"],
visibility = [
"//adev/shared-docs/pipeline:__subpackages__",
],
)
ts_project(
name = "shiki",
srcs = ["shiki.mts"],
visibility = [
"//adev/shared-docs/pipeline:__subpackages__",
],
deps = [
"//adev:node_modules/shiki",
],
)
@@ -0,0 +1,62 @@
/*!
* @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
*/
// In some case we know that we don't want to link a symbol
// Example when there is a conflict between API entries and compiler features.
// eg: "animate" is both an Animation API entry and an template instruction "animation.enter"
const LINK_EXEMPT = new Set(['animate', 'animate.enter', 'animate.leave']);
export function shouldLinkSymbol(symbol: string): boolean {
return !LINK_EXEMPT.has(symbol);
}
export type ApiEntries = Record<string, string>; // symbolName -> moduleName (without @angular/ prefix)
/**
* Extracts the symbol name and property name from a symbol string.
* eg:
* foobar() => {symbolName: 'foobar', propName: null}
* ApplicationRef.tick = > {symbolName: 'ApplicationRef', propName: 'tick'}
* ApplicationRef.tick() = > {symbolName: 'ApplicationRef', propName: 'tick'}
* @Component => {symbolName: 'Component', propName: null}
*/
export function extractFromSymbol(symbol: string): {propName: string | null; symbolName: string} {
let propName: string | undefined;
let symbolName = symbol;
// we want to match functions when they have parentheses
if (symbolName.endsWith('()')) {
symbolName = symbolName.slice(0, -2);
}
if (symbolName.startsWith('@')) {
symbolName = symbolName.slice(1);
}
if (symbolName.includes('#')) {
[symbolName, propName] = symbolName.split('#');
} else if (symbolName.includes('.')) {
[symbolName, propName] = symbolName.split('.');
}
return {propName: propName ?? null, symbolName: symbolName};
}
export function getSymbolUrl(symbol: string, apiEntries: ApiEntries): string | undefined {
if (hasMoreThanOneDot(symbol) || !shouldLinkSymbol(symbol)) {
return undefined;
}
const {symbolName, propName} = extractFromSymbol(symbol);
// We don't want to match entries like "constructor"
const apiEntry = Object.hasOwn(apiEntries, symbolName) && apiEntries[symbolName];
return apiEntry ? `/api/${apiEntry}/${symbolName}${propName ? `#${propName}` : ''}` : undefined;
}
function hasMoreThanOneDot(str: string) {
return str.split('.').length - 1 > 1;
}
@@ -0,0 +1,26 @@
load("//adev/shared-docs:defaults.bzl", "ts_project")
package(default_visibility = ["//visibility:public"])
ts_project(
name = "marked",
srcs = glob(["**/*.mts"]),
visibility = [
"//adev/shared-docs/pipeline:__subpackages__",
],
deps = [
"//adev:node_modules/@types/jsdom",
"//adev:node_modules/@types/node",
"//adev:node_modules/diff",
"//adev:node_modules/emoji-regex",
"//adev:node_modules/html-entities",
"//adev:node_modules/jsdom",
"//adev:node_modules/marked",
"//adev:node_modules/mermaid",
"//adev:node_modules/playwright-core",
"//adev:node_modules/shiki",
"//adev/shared-docs/pipeline/shared:linking",
"//adev/shared-docs/pipeline/shared:shiki",
"//adev/shared-docs/pipeline/shared/regions",
],
)
@@ -7,8 +7,8 @@
*/
import {Tokens, Token, RendererThis, TokenizerThis} from 'marked';
import {anchorTarget} from '../../helpers.mjs';
import {loadWorkspaceRelativeFile} from '../../utils.mjs';
import {loadWorkspaceRelativeFile, anchorTarget} from '../../helpers.mjs';
import {setInsideLink} from '../../transformations/link.mjs';
interface DocsCardToken extends Tokens.Generic {
type: 'docs-card';
@@ -73,7 +73,7 @@ function getStandardCard(renderer: RendererThis, token: DocsCardToken) {
<a href="${token.href}" ${anchorTarget(token.href)} class="docs-card">
<div>
<h3>${token.title}</h3>
${renderer.parser.parse(token.tokens)}
${parseWithoutCreatingLinks(renderer, token)}
</div>
<span>${token.link ? token.link : 'Learn more'}</span>
</a>
@@ -90,6 +90,15 @@ function getStandardCard(renderer: RendererThis, token: DocsCardToken) {
`;
}
function parseWithoutCreatingLinks(renderer: RendererThis, token: DocsCardToken) {
setInsideLink(true);
try {
return renderer.parser.parse(token.tokens);
} finally {
setInsideLink(false);
}
}
function getCardWithSvgIllustration(renderer: RendererThis, token: DocsCardToken) {
// We can assume that all illustrations are svg files
// We need to read svg content, instead of renering svg with `img`,
@@ -8,6 +8,7 @@
import {TokenizerThis, RendererThis} from 'marked';
import {CodeToken, formatCode} from './format/index.mjs';
import {AdevDocsRenderer} from '../../renderer.mjs';
export interface DocsCodeBlock extends CodeToken {
type: 'docs-code-block';
@@ -48,6 +49,6 @@ export const docsCodeBlockExtension = {
if (token.language === 'mermaid') {
return token.code;
}
return formatCode(token);
return formatCode(token, (this.parser.renderer as AdevDocsRenderer).context);
},
};
@@ -8,8 +8,9 @@
import {TokenizerThis, RendererThis} from 'marked';
import {CodeToken, formatCode} from './format/index.mjs';
import {FileType, removeEslintComments} from './sanitizers/eslint.mjs';
import {loadWorkspaceRelativeFile} from '../../utils.mjs';
import {loadWorkspaceRelativeFile} from '../../helpers.mjs';
import {AdevDocsRenderer} from '../../renderer.mjs';
import {FileType, removeEslintComments} from '../../../regions/remove-eslint-comments.mjs';
/** Marked token for a custom docs element. */
export interface DocsCodeToken extends CodeToken {
@@ -82,6 +83,6 @@ export const docsCodeExtension = {
return undefined;
},
renderer(this: RendererThis, token: DocsCodeToken) {
return formatCode(token);
return formatCode(token, (this.parser.renderer as AdevDocsRenderer).context);
},
};
@@ -8,7 +8,7 @@
import {diffLines, Change as DiffChange} from 'diff';
import {CodeToken} from './index.mjs';
import {loadWorkspaceRelativeFile} from '../../../utils.mjs';
import {loadWorkspaceRelativeFile} from '../../../helpers.mjs';
export interface DiffMetadata {
code: string;

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