Compare commits

...

382 Commits

Author SHA1 Message Date
Pawel Kozlowski 4d7eb054b6 release: cut the v19.2.8 release 2025-04-23 17:11:57 +02:00
Pawel Kozlowski 11b90319f7 Revert "release: cut the v19.2.8 release" (#60983)
This reverts commit 94b2a8cee0.

Reverting due to release process aborting in the middle

PR Close #60983
2025-04-23 16:51:01 +02:00
Pawel Kozlowski 94b2a8cee0 release: cut the v19.2.8 release 2025-04-23 16:29:07 +02:00
arturovt b55761829e refactor(router): remove Compiler injectee from RouterPreloader (#60945)
This commit removes the `Compiler` injectee from the `RouterPreloader` constructor. It's unused but was still being referenced in the factory definition: `static ɵfac = ɵɵngDeclareFactory(...)`.

PR Close #60945
2025-04-23 15:18:23 +02:00
Matthieu Riegler beba3c7c93 refactor(compiler-cli): Extract type predicates from type guards. (#60934)
Previously they were extracted as `boolean`.

PR Close #60934
2025-04-23 09:56:45 +02:00
Matthieu Riegler 7d2980982c docs(docs-infra): Improve doc support for pipes. (#60926)
This commits adds the pipe usage and the impure pipe mention.

PR Close #60926
2025-04-23 08:46:12 +02:00
Doug Parker b9c15af651 release: bump Angular DevTools version to 1.0.29 (#60963)
PR Close #60963
2025-04-23 08:44:18 +02:00
Jeevan Mahesha 3824519a27 docs: replace EventEmitter with output and self-closing tags in templates (#60910)
Replaced all instances of EventEmitter with the new output() utility.
Updated templates to use self-closing tags for cleaner markup.

PR Close #60910
2025-04-22 21:42:19 +02:00
Matthieu Riegler adac95c7f9 refactor(core): mark makeEnvironmentProviders as public. (#60956)
`makeEnvironmentProviders` was already exported but didn't have the `@publicApi` tag.

PR Close #60956
2025-04-22 16:27:24 +02:00
Gabriel Bergoc ea4a211216 fix(forms): make NgForm emit FormSubmittedEvent and FormResetEvent (#60887)
Currently, only forms created with `FormGroupDirective` emit events on
form submission and resetting. This commit extends this behavior to
Template-driven forms also.

Related to #58894

PR Close #60887
2025-04-22 13:04:41 +02:00
Matthieu Riegler 9d08525567 docs: format RouterUpgradeInitializer usage notes (#60930)
This commit also adds a standalone example

PR Close #60930
2025-04-22 12:01:00 +02:00
Matthieu Riegler 5f0e0abbb8 refactor(compiler-cli): Don't extract constructors with no parameters (#60928)
This will prevent usesless paramters in the docs, ex: https://angular.dev/api/core/ApplicationInitStatus#constructor

This improves #60302

PR Close #60928
2025-04-22 11:59:45 +02:00
Matthieu Riegler 455809858f docs: Update creating libraries to the current recommendations (#60931)
PR Close #60931
2025-04-22 11:57:53 +02:00
Matthieu Riegler 2f9c7041fd docs: fix NG2800 rendering (#60932)
PR Close #60932
2025-04-22 11:57:01 +02:00
Matthieu Riegler 5555e9f7dc docs: update docs centered on NgModules (#60933)
PR Close #60933
2025-04-22 11:08:56 +02:00
Doug Parker 763e3ca8ab release: bump Angular DevTools version to 1.0.28 (#60893)
PR Close #60893
2025-04-17 11:25:00 +02:00
kirjs 2c1f348478 release: cut the v19.2.7 release 2025-04-16 16:41:50 -04:00
Alan Agius c90eea2cd1 refactor(common): eliminate redundant iterator-to-array conversion (#60884)
Simplifies code by removing unnecessary `Array.from` usage.

PR Close #60884
2025-04-16 12:44:36 -04:00
Angular Robot d1731687e1 build: update io_bazel_rules_sass digest to cbe5261 (#60882)
See associated pull request for more information.

PR Close #60882
2025-04-16 12:43:46 -04:00
Alan Agius 37ab6814f5 fix(common): issue a warning instead of an error when NgOptimizedImage exceeds the preload limit (#60883)
This should not be treated as a hard error, as it doesn’t break the application but merely degrades performance.

Closes #60871

(cherry picked from commit 8f25d4a033)

PR Close #60883
2025-04-16 12:04:39 -04:00
ryncdr 2a65a12fce docs(docs-infra): first-app tutorial - step-14-http src-final correction (#60738)
Updated housing.service.ts > getHousingLocationById()
 - Added search parameter to fetch URL
 - Returns single object instead of array

PR Close #60738
2025-04-16 10:23:51 -04:00
Andrew Scott 5cd80525e7 refactor(core): Update Transition finished promise to not throw unhandled rejection (#60816)
As with `InternalNavigationResult`, this commit adds the `catch` to the
`finished` promise on `InternalNavigationTransition` to avoid unhandled
promise rejections.

PR Close #60816
2025-04-15 18:40:43 -04:00
Andrew Scott aaf07d8e4c docs: Add error handling documentation (#60848)
This adds a page to document the error handling practices, APIs, and features _in the framework_.
It does not contain any application-specific recommendations or
patterns as this information is subjective and domain-specific.

PR Close #60848
2025-04-15 17:35:02 -04:00
Jessica Janiuk 070c09f2b3 fix(docs-infra): prevent processing node_modules .md files (#60872)
If you happen to have node_modules installed for adev tutorials, there would be problems with trying to run adev tests. This excludes those node_modules folders.

PR Close #60872
2025-04-15 17:28:01 -04:00
Doug Parker 9171401b88 refactor(devtools): update release process to commit before publishing (#60646)
This moves the commit step to the start of the process and releases after merging it. This has two key benefits:
1. The commit history now reflects the actual release (ex. any DevTools commits before the release commit are actually included in that release). Previously the changes in a release were dictated by the release PR branch, which is an ephemeral target. Other PRs may be merged to `main` before the release PR, and those changes would not be included in that DevTools release.
2. We can now compute a changelog based on this more accurate history.

The downside to this change is that release PRs are now blocking releases in a way they weren't before (which is likely desirable in the grand scheme of things), meaning we need to be more diligent about merging them in a timely manner.

I added a short script for listing DevTools commits since the last release, taking advantage of the more accurate commit history. This should make changelog generation a lot easier, even if there's still a manual process of rewriting the commit message into a line item in release notes.

Also made a few minor cleanup changes such as escaping the markdown in the suggested reviewer note so it can be more easily copy-pasted from the rendered format of this doc.

PR Close #60646
2025-04-15 09:19:40 -04:00
Angular Robot 9ebe59fa1c build: update all non-major dependencies (#60869)
See associated pull request for more information.

PR Close #60869
2025-04-15 09:10:51 -04:00
Logan Dupont c80f24d658 docs: fix missing card-title tag in example of fallback-content section (#60855)
PR Close #60855
2025-04-14 11:01:07 -04:00
Matthieu Riegler c0e4ff140d refactor(compiler): add support for the new search element (#54945)
See #whatwg/html#5811
Spec: https://html.spec.whatwg.org/multipage/grouping-content.html#the-search-element

breaking change: You cannot have self-closing `search` component anymore as they are recognized as a native non-void element.

fixes #54944

PR Close #54945
2025-04-14 09:34:36 -04:00
JoostK 79ff75fcc3 test(core): type tests for linkedSignal (#60857)
This commit adds type inference tests for `linkedSignal` usages, to capture their behavior w.r.t.
type inference. Note that there's some situations where type inference doesn't work as you might
expect/hope; these have been included to capture their behavior but may be revisited in the future
if the inference capabilities are expanded for this scenario.

Closes #60423

PR Close #60857
2025-04-14 09:30:37 -04:00
JoostK f6e52f26c7 docs: document that linkedSignal with previous should include type arguments (#60857)
Due to the cyclic nature of `previous`'s type and the computation's return type,
TypeScript isn't able to infer generic type arguments.

Closes #60423

PR Close #60857
2025-04-14 09:30:36 -04:00
hawkgs b210d3ccd5 refactor(devtools): switch to components tab whenever the inspector is used (#60694)
Switch to the components tab, if not there, when a component is selected via the inspector.

PR Close #60694
2025-04-14 09:22:05 -04:00
hawkgs 0e8e867b85 refactor(devtools): create highlight overlay on node selection (#60744)
Currently, highlighting works only when a directive explorer node is hovered. The change enables this feature on node selection as well.

PR Close #60744
2025-04-14 09:20:25 -04:00
Jessica Janiuk 6545eff815 docs: remove unused imports in examples (#60867)
PR Close #60867
2025-04-14 09:16:29 -04:00
Miles Malerba 4fec563f7f docs: Restructure example build rules (#60778)
Restructures the examples build rules so that all examples are exposed
through a single file group in adev/src/content/examples.

Also adds a separate filegroup in the same location for just the
embeddable examples and adds it to the APPLICATION_FILES for the docs
app.

This uncovered the fact that some of our examples have broken
non-compiling code. I've excluded these ones from being embeddable for
now, until the breakages can be addressed

PR Close #60778
2025-04-11 17:19:35 -04:00
Miles Malerba 1c6a209c7a docs: Add back script to generate example previews map (#60778)
Restores the ability to have example components rendered alongside the
code. This functionality was broken a while back by #53511.

To enable the embedded preview for an example, add `preview` and
`path=adev/src/content/expamples/component/to/render.ts` attributes to
the `<docs-code>` or `<docs-code-multifile>` tag.

Tested with one of the accessibility examples and it seems to work now.

PR Close #60778
2025-04-11 17:19:34 -04:00
Ryan Russell b144126612 fix(core): inject migration: replace param with this. (#60713)
The inject tool inserts `const foo = this.foo` if code
in the constructor referenced the constructor parameter `foo`.
If `foo` is a readonly property, we can instead replace `foo` with
`this.foo`. This allows more properties to be moved out of the
constructor with combineMemberInitializers.
For now, it only touches initializers, not all of the code in the
constructor.

PR Close #60713
2025-04-10 13:31:31 -04:00
Alan Agius 77c60414a2 fix(docs-infra): update docs-alert and tests (#60829)
Before this commit, the docs-alert tests were failing. This also ensures that `NOTE:`, `TIP:` and others are always capitalized.

(cherry picked from commit ab5986dd5685d36e209972916cddb9dca8e0a557)

PR Close #60829
2025-04-10 11:19:53 -04:00
Vincent d39e09da41 fix(http): Include HTTP status code and headers when HTTP requests errored in httpResource (#60802)
Currently the HTTP status code and headers are only included if the request succeeded. Given status codes convey more information in case of a request error vs. success, this makes it more useful than inspecting what is contained in `.error()`.

PR Close #60802
2025-04-09 14:25:03 -07:00
Andrew Scott 54f9269fad release: cut the v19.2.6 release 2025-04-09 12:25:57 -07:00
Kristiyan Kostadinov fc946c5f72 fix(compiler-cli): ensure HMR works with different output module type (#60797)
Currently when we transpile the HMR update module, we use the project's compiler options verbatim. This appears to break down with some module types, whereas we have to use a native export.

These changes override the compiler options to ensure that the user's options don't end up breaking HMR.

Fixes #60795.

PR Close #60797
2025-04-09 11:42:56 -07:00
Jermaine Jatau d99935a7ac docs: update guide on referencing component children (#60787)
PR Close #60787
2025-04-09 11:08:32 -07:00
Matthieu Riegler 880ebf4a71 Revert "refactor(core): use stream in rxResource instead of loader (#59910)" (#60803)
This reverts commit 98a584c1e8.

PR Close #60803
2025-04-09 09:33:27 -07:00
Angular Robot ae8a4c4905 build: update github/codeql-action action to v3.28.15 (#60780)
See associated pull request for more information.

PR Close #60780
2025-04-08 16:26:15 -07:00
JoostK 9241615ad0 fix(core): reduce total memory usage of various migration schematics (#60776)
This commit changes Tsurge's operation within angular-devkit (i.e. the CLI) to
no longer retain all programs across all migrations. This isn't necessary for
so-called "funnel" migrations so not retaining the programs for those migrations
is a pure performance win. The "complex" migrations may see increased execution time
given that the program is now being recreated for the actual migration phase to run,
although reduced memory pressure may help alleviate this overhead. Since this new
approach should help prevent Node from running out of memory and failing entirely
this is preferred over a potentially increased execution time.

Fixes #59813

PR Close #60776
2025-04-08 16:12:57 -07:00
Kristiyan Kostadinov a382066165 refactor(migrations): simplify integration of tsurge migrations into the CLI (#60386) (#60776)
Currently when we reuse a Tsurge migration is reused externally, there's some glue code that needs to be executed in a specific order. The code gets copied between the different migrations which is error-prone and means that bugs may have to be fixed several times.

These changes move the common steps out into a separate function so that only the migration-specific logic (mostly instantiation and logging) is left in the schematic.

PR Close #60386

PR Close #60776
2025-04-08 16:12:56 -07:00
aparziale f2bfa3151e fix(core): fix ng generate @angular/core:output-migration. Fixes angular#58650 (#60763)
Fixes #58650 - Insert a TODO comment for empty emit (without parameter).

PR Close #60763
2025-04-08 16:10:04 -07:00
arturovt 6a55970373 refactor(router): replace APP_INITIALIZER (#60719)
The `APP_INITIALIZER` is deprecated. Replaced with `provideAppInitializer`.

PR Close #60719
2025-04-08 16:06:05 -07:00
Andrew Scott dc193a7e3a refactor(router): use performance API for router view transitions (#60790)
Adds feature tracking for view transitions.

PR Close #60790
2025-04-08 14:02:29 -07:00
cexbrayat 56db79a973 refactor(core): use stream in rxResource instead of loader (#59910)
With the changes in #59573, `resource` can now define a `stream` rather than a `loader`.
In the same PR, `rxResource` was updated to leverage this new functionality to handle multiple responses from the underlying observable,
rather than just the first one as it was previously.
This commit renames the `loader` option of `rxResource` into `stream` to be better aligned with its new behavior.

The previous version is temporarily kept and marked as deprecated to help migrating the current usage.

Before
```
usersResource = rxResource({
  request: () => ...,
  loader: ({ request }) => ...
});
```

After
```
usersResource = rxResource({
  request: () => ...,
  stream: ({ request }) => ...
});
```

PR Close #59910
2025-04-08 10:19:15 -07:00
Kristiyan Kostadinov 4c09fae588 refactor(platform-browser): remove GenericBrowserDomAdapter (#60760)
The `GenericBrowserDomAdapter` wasn't don't anything so we can drop it and have the `BrowserDomAdapter` extend `DomAdapter` directly.

PR Close #60760
2025-04-08 10:14:55 -07:00
Angular Robot cf12993383 build: update dependency @types/babel__generator to v7.27.0 (#60781)
See associated pull request for more information.

PR Close #60781
2025-04-08 10:13:58 -07:00
Kirill Cherkashin 8b9df449c7 docs: Update guide link in http package md file (#59955)
PR Close #59955
2025-04-08 09:20:20 -07:00
Angular Robot 35de6f68f3 build: update io_bazel_rules_sass digest to b4800f3 (#60737)
See associated pull request for more information.

PR Close #60737
2025-04-07 13:33:15 -07:00
Kristiyan Kostadinov 3441f7b914 fix(compiler): error if rawText isn't estimated correctly (#60529) (#60753)
The `TemplateLiteralElementExpr` has some logic where it tries to estimate the `rawText` if one isn't provided by looking at the node's source span. The problem with this approach is that we have some long-standing issues with our expression AST parser (see https://github.com/angular/angular/pull/60267#discussion_r1986402524) where it might not produce accurate spans if escape sequences are involved. This in turn can lead to unrecoverable errors, because TypeScript will throw an error if the raw string doesn't match the cooked one when constructing a TypeScript AST node.

These changes remove the logic that depends on the source span and relies purely on the secondary fallback that inserts escaped characters manually.

It's also worth noting that the `rawText` doesn't seem to matter much at this point, because the main usage of it is when downlevelling template literals to ES5 which we no longer support.

Fixes #60528.

PR Close #60529

PR Close #60753
2025-04-07 13:15:02 -07:00
Jamie Couperwhite ae2fc18855 docs: fix typo in documentation for pendingUntilEvent (#60756)
PR Close #60756
2025-04-07 10:29:36 -07:00
aparzi 00bbd9b382 fix(core): fix docs for output migration (#60764)
missing EventEmitter import

PR Close #60764
2025-04-07 09:23:35 -07:00
Alan Agius e9a719ef2b build: avoid export internal renames (#60739)
There is no need to minify internal names as these are minified by the consuming app

PR Close #60739
2025-04-04 09:49:15 -07:00
hawkgs de51b9a48d docs(docs-infra): fix home animation text width on small devices; fix snackbar colors (#60745)
The text used to exceed the viewport width.

PR Close #60745
2025-04-04 09:44:45 -07:00
Andrew Scott 1b36f6e1e0 refactor(common): Add hashchange event for traversals (#60682)
This commit adds the logic to emit the `hashchange` event for
traversals.

PR Close #60682
2025-04-03 16:54:57 -07:00
Andrew Scott 8880ed67f1 refactor(common): Update FakeNavigation deferred commit to use precommitHandler (#60652)
This commit updates the FakeNavigation implementation to match the
spec's new `precommitHandler` which replaces the old `commit: 'after-transition'`.

PR Close #60652
2025-04-03 16:53:07 -07:00
Angular Robot d7089d29ef build: update io_bazel_rules_sass digest to 3548d6b (#60721)
See associated pull request for more information.

PR Close #60721
2025-04-03 13:08:02 -07:00
Doug Parker 12320347cc refactor(core): add ApplicationRef.prototype.bootstrapImpl with an injector parameter (#60622)
This is a roll forward of commit d5a8a1c524. Nothing is meaningfully different, as we're trying again to see if the CI failure is reproducible.

PR Close #60622
2025-04-03 10:48:02 -07:00
Andrew Scott fcdef1019f fix(language-service): Ensure dollar signs are escaped in completions (#60597)
Dollar signs need to be escaped so they are not replaced during snippet
expansion: https://code.visualstudio.com/docs/editing/userdefinedsnippets#_how-do-i-have-a-snippet-place-a-variable-in-the-pasted-script

fixes https://github.com/angular/vscode-ng-language-service/issues/2139

PR Close #60597
2025-04-03 10:45:57 -07:00
Andrew Scott 0e82d42774 fix(language-service): Do not provide element completions in end tag (#60616)
Element completions should not be provided when the position is in the
end tag or between the start and end tags.

fixes https://github.com/angular/vscode-ng-language-service/issues/2157

PR Close #60616
2025-04-03 10:36:33 -07:00
LC 8d183aebbb docs: Fix Property Binding (#60725)
PR Close #60725
2025-04-03 10:09:37 -07:00
Jessica Janiuk 5b76da59c6 release: cut the v19.2.5 release 2025-04-02 14:53:11 -04:00
hawkgs 8ce68289e6 docs(docs-infra): fix algolia icon in the search dialog on safari (#60702)
The icon used to have zero height due to its display property.

PR Close #60702
2025-04-02 16:19:47 +00:00
aparziale 006ac7f22f fix(core): fixes #592882 ng generate @angular/core:signal-queries-migration (#60688)
fixes #592882 - retain accessibility modifier if it's already present for signal migrations

PR Close #60688
2025-04-02 15:14:43 +00:00
arturovt 635fb00969 refactor(service-worker): pull less RxJS symbols (#60657)
In this commit, we reduce the number of imported RxJS symbols since they are redundant.

- We replace `merge` with a manual observable because `merge` internally pulls in `from()`.
- We remove `defer` and `throwError`, replacing them with `new Observable(s => s.error(..))`.
- We replace `toPromise()` with `new Promise`, as `toPromise()` is deprecated.
- We convert `readyToRegister` to a promise to avoid using RxJS operators like `delay`.

PR Close #60657
2025-04-02 15:00:34 +00:00
aparziale 8f68d1bec3 fix(core): fix ng generate @angular/core:output-migration (#60626)
output-migration command not keep type if @output declaring without initializer

PR Close #60626
2025-04-02 14:26:05 +00:00
Tomasz Domański 7cd89ad2c6 fix(service-worker): assign initializing client's app version, when a request is for worker script (#58131)
When a new version of app is available in a service worker, and a client with old version exists, web workers initialized from a client with old version will now be properly assigned with the same version.

Before this change, a web worker was assigned with the newest version.

Fixes #57971

PR Close #58131
2025-04-02 14:23:52 +00:00
Ahmed Hakeem 0c5b697afe docs: add a note about styles collision resolution (#59266)
PR Close #59266
2025-04-02 13:57:28 +00:00
Dany Marques 792954ba2c docs(core): give types to signal API (#58965)
PR Close #58965
2025-04-02 13:56:55 +00:00
Dany Marques 27a678a093 docs(core): improve computation example (#58965)
PR Close #58965
2025-04-02 13:56:55 +00:00
Matthieu Riegler f90dc69548 docs: Use inject for DI (#59835)
PR Close #59835
2025-04-02 13:37:31 +00:00
Matthieu Riegler 670dc2af89 docs(docs-infra): fix adev (#60695)
PR Close #60695
2025-04-02 12:37:04 +00:00
Matthieu Riegler 9604ec6e16 refactor(compiler): prevent object methods being recognised as entities (#58100)
With this commit object methods (like `valueOf`, `toString` are not considered as valid entities anymore.

PR Close #58100
2025-04-02 11:35:54 +00:00
Jake Spievak 88a2c92f87 docs: update the first app tutorial to include a note about importing NgFor directive (#60627)
PR Close #60627
2025-04-02 11:34:25 +00:00
Matthieu Riegler 2d8943122b docs: add targets for the bundling debug (#60693)
PR Close #60693
2025-04-02 11:33:52 +00:00
Matthieu Riegler 440b1ada9b docs(docs-infra): Search results as HTML (#60394)
fixes #60384

PR Close #60394
2025-04-02 11:32:58 +00:00
Andrew Kushnir da9f509adf build: exclude relative imports commits via .git-blame-ignore-revs (#60685)
This commit adds a list of commits that refactored the code to use relative imports to the .git-blame-ignore-revs.

PR Close #60685
2025-04-01 22:23:16 +00:00
Andrew Kushnir d0c979e0f0 test(bazel): update common package contents test to skip chunks (#60676)
This commit updates the `common` package contents test to skip JS chunks, while still making sure that the main entrypoint files are present.

PR Close #60676
2025-04-01 18:16:49 +00:00
Andrew Kushnir f8ca1d57af build(common): updating golden files for the @angular/common package (#60676)
This commit updates golden files that got changed after swtiching to relative paths. There are no actual change to the APIs, the golden file updates capture the change in imports.

PR Close #60676
2025-04-01 18:16:49 +00:00
Andrew Kushnir d725c6ed0f refactor(common): convert scripts within packages/common to relative imports (#60676)
This commit updates scripts within `packages/common` to relative imports as a prep work to the upcoming infra updates.

PR Close #60676
2025-04-01 18:16:49 +00:00
Andrew Kushnir 7edca03989 refactor(router): re-export the RouterTestingModule symbols (#60674)
This commit re-exports the symbols that are exposed by the `RouterTestingModule` (which re-exports
the symbols from the `RouterModule`. These re-exports are needed for the Angular compiler
to overcome its limitation (on the consumer side) of not knowing where to import import
symbols when relative imports are used within the package.

PR Close #60674
2025-04-01 18:16:05 +00:00
Andrew Kushnir 1fa95e5c2e refactor(router): switching to relative imports within the router package (#60674)
This commit updates scripts within `packages/router` to relative imports as a prep work to the upcoming infra updates.

PR Close #60674
2025-04-01 18:16:05 +00:00
Joey Perrott 1f02cb74e2 ci: update to latest dev-infra action versions (#60677)
Update to the latest actions

PR Close #60677
2025-04-01 18:14:47 +00:00
Andrew Scott bd1a755ab4 refactor(router): Update StateManager base class with common concrete implementations (#60617)
This commit updates the `StateManager` base class to contain common
concrete implementations that would be the same regardless of whether
the state manager is backed by the browser history API or the Navigation
API.

PR Close #60617
2025-04-01 14:05:44 +00:00
Angular Robot 95037222fb build: update all non-major dependencies (#60668)
See associated pull request for more information.

PR Close #60668
2025-04-01 12:34:37 +00:00
Jessica Janiuk b3c7282121 Revert "refactor(core): add ApplicationRef.prototype.bootstrapImpl with an injector parameter (#60622)" (#60669)
This reverts commit 7cb8639da9.

PR Close #60669
2025-04-01 12:18:52 +00:00
Doug Parker e816d2d694 refactor(core): add ApplicationRef.prototype.bootstrapImpl with an injector parameter (#60622)
This allows any components individually bootstrapped to inherit from a unique `Injector`. This is useful when bootstrapping multiple root components with different providers.

For now, the function is private while we explore potential designs to consolidate it with the existing `ApplicationRef.prototype.bootstrap` method.

PR Close #60622
2025-04-01 12:01:00 +00:00
Paul Gschwendtner fa48f98d9f fix(animations): add missing peer dependency on @angular/common (#60660)
As of
https://github.com/angular/angular/commit/1c4a3677eb4140435d27c0c873f719b7d8cdce58#diff-64131f78c9ae21421dc277debf9c8a16705a90fa649ddf580da3db434c295b11R7-R8,
the animations package has a dependency on `@angular/common`. This
commit adds this dependency to the `package.json`— as otherwise pnpm
strict builds will fail.

PR Close #60660
2025-04-01 11:59:50 +00:00
Andrew Kushnir 9eaeffd398 refactor(compiler): convert scripts within packages/compiler to relative imports (#60655)
This commit updates scripts within `packages/compiler` to relative imports as a prep work to the upcoming infra updates.

PR Close #60655
2025-04-01 11:59:14 +00:00
Andrew Kushnir f94f3a6acf refactor(compiler-cli): convert scripts within packages/compiler-cli to relative imports (#60655)
This commit updates scripts within `packages/compiler-cli` to relative imports as a prep work to the upcoming infra updates.

PR Close #60655
2025-04-01 11:59:14 +00:00
Andrew Kushnir 0b7fc584d4 refactor(forms): convert scripts within packages/forms to relative imports (#60624) (#60654)
This commit updates scripts within `packages/forms` to relative imports as a prep work to the upcoming infra updates.

PR Close #60624

PR Close #60654
2025-04-01 11:58:28 +00:00
Andrew Scott 0e9e0348dd fix(language-service): Update adapter to log instead of throw errors (#60651)
This prevents errors from being thrown from the adapters. Throwing errors
in the language service causes the extension to crash. Repeated errors
will permanently break the extension.

fixes https://github.com/angular/vscode-ng-language-service/issues/2166

PR Close #60651
2025-03-31 21:36:35 +00:00
Vincent 74cd7be6b3 refactor(core): Make unsupported styling type error message clearer (#59563)
The previous message would sound like a full sentence when using a signal without `()` (Example: Unsupported styling type function: [Input Signal: neutral]). The new formatting makes it a bit more obvious that the type itself is the problem.

PR Close #59563
2025-03-31 21:31:43 +00:00
Angular Robot 3bc113d514 build: update io_bazel_rules_sass digest to b80aeb7 (#60653)
See associated pull request for more information.

PR Close #60653
2025-03-31 21:24:50 +00:00
Andrew Kushnir 4387b37eb9 refactor(router): drop special handling of the OutletInjector (#58351)
This commit updates the OutletInjector and related code to avoid special handling of that injector. The main code that had special handling was refactored to no longer require is in https://github.com/angular/angular/pull/56763, this commit completes the cleanup.

PR Close #58351
2025-03-31 20:46:01 +00:00
Jessica Janiuk c1a1b1c3f8 docs: fix missing file header (#60649)
PR Close #60649
2025-03-31 20:42:23 +00:00
Matthieu Riegler 38557304e3 refactor(core): remove TODOs referencing #24571 (#60648)
Fixing those todos are now mostly breaking changes.
The situation is "good" as is.

PR Close #60648
2025-03-31 20:24:30 +00:00
Michael van der Luit 8d41c5bff3 docs(docs-infra): add search via queryparam all adev routes (#57567)
add search via a queryparam (?search=query) on all adev routes

PR Close #57567
2025-03-31 20:17:19 +00:00
Sheik Althaf f15f41111b refactor(docs-infra): migrate adev to signal-based queries (#58646)
Used migration schametic to migrate to signal based queries and little manual migration where setter is used

PR Close #58646
2025-03-31 20:16:39 +00:00
Ngnintedem3004 b972249145 docs: Update code snippet visible lines (#60419)
Updates the relevant code snippet visible lines to be accurate.

PR Close #60419
2025-03-31 20:16:03 +00:00
Vlad Boisa b2222889c8 docs: remove todo comment (#59928)
Removes outdated todo comment

PR Close #59928
2025-03-31 19:57:57 +00:00
arturovt f3361fbf3e refactor(platform-browser): remove empty deps lists (#60312)
Removes empty `deps` lists in Platform-Browser providers.

PR Close #60312
2025-03-31 18:09:08 +00:00
Andrew Kushnir a689415d00 build: update lock files for integration test apps (#60594) (#60643)
This commit updates yarn.lock files for integration test apps.

PR Close #60594

PR Close #60643
2025-03-31 17:55:39 +00:00
Andrew Kushnir d119cd32b1 refactor(core): drop unused deps for integration apps (#60594) (#60643)
This commit drops unused deps from the `packages.json` files of various integration test apps.

PR Close #60594

PR Close #60643
2025-03-31 17:55:39 +00:00
Andrew Kushnir 51d7696b50 ci: moving integration tests into a separate GH action (#60594) (#60643)
This commit extracts integration tests from the `test` CI job into a separate GH job (to run in parallel).

PR Close #60594

PR Close #60643
2025-03-31 17:55:39 +00:00
Andrew Kushnir db08558c3b test(core): remove obsolete integration tests (#60594) (#60643)
This commit removes a number of obsolete integration tests and also removes some e2e tests for a few remianing apps, since they are not adding value, but cause extra time to spend on CI.

PR Close #60594

PR Close #60643
2025-03-31 17:55:39 +00:00
Doug Parker ad72be1059 release: bump Angular DevTools version to 1.0.27 (#60642)
PR Close #60642
2025-03-31 17:50:20 +00:00
AleksanderBodurri 139fead7d3 fix(devtools): catch firefox non-top level frame error case when using utilities APIs (#60430)
Previously the `frameUrl` option in `chrome.devtools.inspectedWindow.eval` would throw errors when used in Firefox, preventing inspect source functionality for firefox users even if they don't need to target a particular frame on the page (they are on the top level frame with Angular DevTools).

Now this behaviour is as follows:

Firefox user that has the top level frame selected -> DevTools inspect functionality works as expected.

Firefox user that has a non-top level frame selected -> DevTools now renders a snackbar message informing the user of the limitation.

PR Close #60430
2025-03-31 17:09:57 +00:00
EriksonBahr e61d06afb5 fix: step 6 tutorial docs (#60630)
PR Close #60630
2025-03-31 17:04:35 +00:00
hawkgs 086b4a986e refactor(devtools): fix firefox breadcrumbs (#60552)
Expand the breadcrumbs container to fit the directive explorer width and remove the scrollbar.

PR Close #60552
2025-03-31 16:56:55 +00:00
Angular Robot 84f3ba0d90 build: lock file maintenance (#60635)
See associated pull request for more information.

PR Close #60635
2025-03-31 14:43:03 +00:00
Elderov, Ali fdde642985 docs: fix private modifier for the injected service (#60619)
PR Close #60619
2025-03-31 13:13:37 +00:00
Colum Ferry 11ed7e01e2 docs: update links for angular rspack to correct locations (#60634)
PR Close #60634
2025-03-31 13:12:13 +00:00
Jessica Janiuk dbbddd1617 fix(core): prevent omission of deferred pipes in full compilation (#60571)
This prevents a bug where pipes would be excluded from defer dependency generation.

PR Close #60571
2025-03-31 13:11:13 +00:00
Andrew Kushnir 0252da985a build: remove obsolete bundling test apps (#60591) (#60615)
This commit removes a few bundling test apps that do not provide any value, but require time on CI and during local development to update golden files.

The functionality that was tested in those apps is covered by various other tests that we have in a repository (either in the same `packages/core/test/bundling` folder or in other unit/integration tests).

PR Close #60591

PR Close #60615
2025-03-28 19:57:06 +00:00
Jessica Janiuk 43d03f840e ci: fix over extraction of init symbols in symbol tests (#60493) (#60614)
This omits including any init_ symbols in the symbol tests that were unnecessary and causing friction.

PR Close #60493

PR Close #60614
2025-03-28 19:48:36 +00:00
Andrew Kushnir 882f96fead refactor(core): produce a message about @defer behavior when HMR is enabled (#60533)
When the HMR is enabled in Angular, all `@defer` block dependencies are loaded
eagerly, instead of waiting for configured trigger conditions. From the DX perspective,
it might be seen as an issue when all dependencies are being loaded eagerly. This commit
adds a logic to produce a message into the console to provide more info for developers.

PR Close #60533
2025-03-28 15:00:32 +00:00
Matthieu Riegler b18215d1c8 refactor(core): retrieve the jsActionMap only once. (#60587)
Before the change, the map was pull on every loop execution.

PR Close #60587
2025-03-28 13:35:29 +00:00
Kristiyan Kostadinov 15f53f035b fix(migrations): handle shorthand assignments in super call (#60602)
Fixes that the logic which checks whether a parameter is used inside a `super` call wasn't accounting for shorthand assignments.

PR Close #60602
2025-03-28 13:34:37 +00:00
Kristiyan Kostadinov 4b161e6234 fix(migrations): inject migration not handling super parameter referenced via this (#60602)
The inject migration has some logic that treats parameters referenced directly inside of `super` differently. This logic didn't account for the fact that the parameters could be inside of inline functions which have less strict access requirements.

PR Close #60602
2025-03-28 13:34:37 +00:00
arturovt 8931fca34c refactor(core): calculate hasHttpTransferCacheOptions later (#60605)
Prior to this commit, `hasHttpTransferCacheOptions` was calculated immediately after the `featuresKind` set was declared, which was always defaulted to `false`.

PR Close #60605
2025-03-28 13:33:58 +00:00
Andrew Scott 958e98e4f7 fix(router): Add missing types to transition (#60307)
The 'types' property was added recently and is available in all browsers that support view transitions

fixes #60285

PR Close #60307
2025-03-28 11:51:07 +00:00
Matthieu Riegler 90cef52107 docs(docs-infra): fix the deferable views tutorials (#60604)
patch backport of #60509

fixes #60595

PR Close #60604
2025-03-28 11:47:50 +00:00
Andrew Scott f4c4b10ea8 fix(compiler-cli): Produce fatal diagnostic on duplicate decorated properties (#60376)
This prevents the compilation and language service from crashing.

fixes https://github.com/angular/vscode-ng-language-service/issues/2091

PR Close #60376
2025-03-27 20:26:42 +00:00
Benjamin Pabst 64da69f7b6 fix(core): check ngDevMode for undefined (#60565)
This adds a check to "toSignal" whether ngDevMode is not undefined as this can happen for some MFE applications.

PR Close #60565
2025-03-27 20:25:41 +00:00
Kristiyan Kostadinov ca5aa4d55b fix(compiler): throw for invalid "as" expression in if block (#60580)
Adds some validation that the "as" expression in an `@if` block is valid.

Fixes #59939.

PR Close #60580
2025-03-27 20:24:59 +00:00
Ryan Russell da6e93f434 fix(core): preserve comments in internal inject migration (#60588)
The internal-only combineMemberInitializers option
for the inject migration sometimes dropped the
doc comments from the members.

PR Close #60588
2025-03-27 20:24:23 +00:00
Shashwat Pathak b53220a9bf docs: update description for AfterRenderPhase.EarlyRead (#60527)
PR Close #60527
2025-03-27 18:33:24 +00:00
Andrew Kushnir 96b4f8abde refactor(platform-browser): switching to relative imports within the platform-browser package (#60559)
This commit updates scripts within `packages/platform-browser` to relative imports as a prep work to the upcoming infra updates.

PR Close #60559
2025-03-27 18:31:53 +00:00
Andrew Kushnir 8e7a6a32fa refactor(platform-browser-dynamic): switching to relative imports within the platform-browser-dynamic package (#60559)
This commit updates scripts within `packages/platform-browser-dynamic` to relative imports as a prep work to the upcoming infra updates.

PR Close #60559
2025-03-27 18:31:52 +00:00
Andrew Kushnir f4b59770e1 refactor(platform-server): switching to relative imports within the platform-server package (#60559)
This commit updates scripts within `packages/platform-server` to relative imports as a prep work to the upcoming infra updates.

PR Close #60559
2025-03-27 18:31:52 +00:00
Andrew Kushnir c2ef28062a refactor(animations): convert scripts within packages/animations to relative imports (#60230)
This commit updates scripts within `packages/animations` to relative imports as a prep work to the upcoming infra updates.

PR Close #60230
2025-03-27 18:28:01 +00:00
Andrew Kushnir c64956c411 refactor(benchpress): convert scripts within packages/benchpress to relative imports (#60230)
This commit updates scripts within `packages/benchpress` to relative imports as a prep work to the upcoming infra updates.

PR Close #60230
2025-03-27 18:28:01 +00:00
Jessica Janiuk bc79985c65 fix(core): fix regexp for event types (#60592)
This regexp accidentally worked. It was splitting by individual character and putting a pipe in rather than splitting by set of event types

PR Close #60592
2025-03-27 18:27:04 +00:00
arturovt 3bc8fe40e4 refactor(service-worker): drop fromEvent (#60424)
In this commit, we remove `fromEvent` and replace it with a manually created observable to import fewer symbols from RxJS. Some codebases may not use `fromEvent` at all, but using it in a single place would still include it in the initial bundle.

PR Close #60424
2025-03-27 18:17:22 +00:00
Joey Perrott d9420fedcb ci: update bazel RBE setup on CI and use trusted build configuration for upstream CI runs (#60590)
Update to use the latest bazel/configure-remote action from dev-infra and set up trusted builds
for CI runs from upstream branches.

PR Close #60590
2025-03-27 18:16:38 +00:00
Andrew Kushnir 1ada286279 build: add build step to the public API extractor script (#60578)
This commit adds a step where we build all found targets in parallel, which speeds up the process of completing public API extractor test/update.

PR Close #60578
2025-03-27 18:13:40 +00:00
Andrew Kushnir 60492810fd build: add build step to the symbol extractor script (#60573)
This commit adds a step where we build all found targets in parallel, which speeds up the process of completing symbol extractor test/update.

PR Close #60573
2025-03-27 18:13:04 +00:00
Alan Agius 2f96ba96a0 refactor(docs-infra): minor clean up in testing helpers (#60581)
Modernize code of testing-helper

PR Close #60581
2025-03-27 18:12:32 +00:00
Alan Agius 08fc82e13f refactor(docs-infra): remove redundant overrides in FakeWebContainer (#60581)
This is required to fix
```
adev/shared-docs/testing/testing-helper.ts:100:12 - error TS2416: Property 'on' in type 'FakeWebContainer' is not assignable to the same property in base type 'WebContainer'.
  Type '{ (event: "port", listener: PortListener): Unsubscribe; (event: "server-ready", listener: ServerReadyListener): Unsubscribe; (event: "error", listener: ErrorListener): Unsubscribe; (event: "preview-message", listener: PreviewMessageListener): Unsubscribe; }' is not assignable to type '{ (event: "port", listener: PortListener): Unsubscribe; (event: "server-ready", listener: ServerReadyListener): Unsubscribe; (event: "preview-message", listener: PreviewMessageListener): Unsubscribe; (event: "error", listener: ErrorListener): Unsubscribe; (event: "xdg-open", listener: OpenListener): Unsubscribe; (ev...'.
    Types of parameters 'event' and 'event' are incompatible.
      Type '"xdg-open"' is not assignable to type '"port"'.

100   override on(event: 'server-ready', listener: ServerReadyListener): Unsubscribe;
               ~~
```

See: https://github.com/angular/angular/actions/runs/14098789522/job/39491059550?pr=60526

PR Close #60581
2025-03-27 18:12:32 +00:00
hawkgs 0e156f7461 docs(docs-infra): fix navigation component UI bugs (#60583)
- Detachment of the navigation from the left window border
- Odd horizontal scroll when there is a URL fragment and the viewport width <900px

PR Close #60583
2025-03-27 18:11:39 +00:00
Manimaran T 1b77d52dd7 docs(docs-infra): fix correct HTML tag typo in welcome message (#60569)
PR Close #60569
2025-03-27 18:11:03 +00:00
Gerome Grignon e2dca56aaf docs: lint code examples (#59979)
PR Close #59979
2025-03-27 18:09:46 +00:00
Gerome Grignon 0ecdbdaafd docs: migrate reactive forms to standalone (#59979)
PR Close #59979
2025-03-27 18:09:45 +00:00
Gerome Grignon b982331dd3 docs: migrate reactive forms to standalone (#59979)
PR Close #59979
2025-03-27 18:09:45 +00:00
Joey Perrott d9fc010b18 build: disable remote upload of local action results to RBE cache (#60568)
disable remote upload for local actions

PR Close #60568
2025-03-26 20:48:17 -07:00
hawkgs 135ffc25b0 docs(docs-infra): fix CSS media queries boundaries (#60564)
Make lower boundaries exclusive, so we avoid conflicts with the upper boundaries.

PR Close #60564
2025-03-26 20:47:33 -07:00
Paul Gschwendtner 22a0e54ac4 fix(compiler-cli): support relative imports to symbols outside rootDir (#60555)
By default, the compiler-cli uses the relative import strategy when
there is no `rootDir` or `rootDirs`. This is expected as everything is
assumed to be somehow reachable through relative imports.

With `rootDirs` that allow for a "virtual file system"-like environment,
the compiler is not necessarily able to always construct proper relative
imports. The compiler includes the `LogicalProjectStrategy` for this
reason. This strategy is able to respect `rootDirs` to construct
relative paths when possible.

This logic currently accidentally triggers when there is a `rootDir`
set. This option is not to be confused with the virtual directory
option called `rootDirs`. The compiler currently confuses this and
accidentally enters this mode when there is just a `rootDir`— breaking
in monorepos that imports can point outside the `rootDir` to e.g. other
compilation unit's `.d.ts` (which is valid; just not `.ts` sources can
live outside the root dir).

This is necessary for our Bazel toolchain migration.

PR Close #60555
2025-03-26 20:45:56 -07:00
Jessica Janiuk 7ff4235b42 docs: add more details about event replay (#60554)
PR Close #60554
2025-03-26 20:45:04 -07:00
Pawel Kozlowski 5a59af0ef8 refactor(core): simplify signature of listenToDirectiveOutput (#60514) (#60547)
We can simplify signature of listenToDirectiveOutput by passing less
arguments (some of them can be derived from already passed arguments).

PR Close #60547
2025-03-26 20:43:13 -07:00
Angular Robot 88d7b7c965 build: update scorecard action dependencies (#60543)
See associated pull request for more information.

PR Close #60543
2025-03-26 20:40:59 -07:00
Andrew Kushnir ee46567475 refactor(language-service): convert scripts within packages/language-service to relative imports (#60540)
This commit updates scripts within `packages/language-service` to relative imports as a prep work to the upcoming infra updates.

PR Close #60540
2025-03-26 20:40:02 -07:00
Andrew Kushnir c9562ac2cc refactor(localize): convert scripts within packages/localize to relative imports (#60540)
This commit updates scripts within `packages/localize` to relative imports as a prep work to the upcoming infra updates.

PR Close #60540
2025-03-26 20:40:02 -07:00
hawkgs 07565928ad ci: add hawkgs to pullapprove (#60536)
Add hawkgs to pullaprove for angular-dev.

PR Close #60536
2025-03-26 20:39:32 -07:00
Andrew Kushnir 650c179371 refactor(upgrade): convert scripts within packages/upgrade to relative imports (#60238)
This commit updates scripts within `packages/upgrade` to relative imports as a prep work to the upcoming infra updates.

PR Close #60238
2025-03-26 20:35:12 -07:00
Andrew Kushnir 1b576ee5f5 refactor(service-worker): convert scripts within packages/service-worker to relative imports (#60238)
This commit updates scripts within `packages/service-worker` to relative imports as a prep work to the upcoming infra updates.

PR Close #60238
2025-03-26 20:35:11 -07:00
Alex Rickabaugh 4c16eae925 release: cut the v19.2.4 release 2025-03-26 20:26:39 -07:00
Andrew Kushnir 7a65b06665 refactor(core): updates to golden files (#60227) (#60556)
This commit updates golden files to include the changes that appeared after changing imports to relative paths.

PR Close #60227

PR Close #60556
2025-03-26 07:05:23 -07:00
Andrew Kushnir d6d3a87c72 refactor(core): convert scripts within packages/core/test to relative imports (#60227) (#60556)
This commit updates scripts within `packages/core/test` to relative imports as a prep work to the
upcoming infra updates.

PR Close #60227

PR Close #60556
2025-03-26 07:05:23 -07:00
Andrew Kushnir 854a66d8ee refactor(core): convert scripts within packages/core/src to relative imports (#60227) (#60556)
This commit updates scripts within `packages/core/src` to relative imports as a prep work to the upcoming infra updates.

PR Close #60227

PR Close #60556
2025-03-26 07:05:23 -07:00
Hryhorii (Greg) Avcharov 00a9331fe8 docs: fix templates bindings link (#60521)
PR Close #60521
2025-03-24 09:07:30 -07:00
aparzi 081f5f5a83 fix(core): fix used templates are not deleted (#60459)
After running the control flow migration, used templates are not deleted.

PR Close #60459
2025-03-24 09:04:06 -07:00
Milo 5e109c8ded fix(devtools): show preview content even after expanding node (#60360)
this aligns with Chrome devtools behavior

PR Close #60360
2025-03-24 09:03:22 -07:00
Pawel Kozlowski 9ac4057db8 refactor(core): specify reactive node kind for linked signal (#60451)
This commit adds reactive node kind for linked signal.

PR Close #60451
2025-03-24 07:06:47 -07:00
Matthieu Riegler d6a1a3a5de Revert "fix(localize): handle @angular/build:karma in ng add (#60513)" (#60523)
This reverts commit a2f622d82d.

PR Close #60523
2025-03-24 06:58:49 +00:00
cexbrayat a2f622d82d fix(localize): handle @angular/build:karma in ng add (#60513)
`ng add @angular/localize` now also adds the localize polyfill to the configuration of Karma if the `@angular/build:karma` builder is used
(which is the default in Angular CLI v20)

PR Close #60513
2025-03-21 14:37:24 -07:00
Paul Gschwendtner a4f144a366 test: ng-modules-importability test should import every module in isolation (#60503)
This will make the test even more useful, as it ensures that we aren't
accidentally relying on the compiler potentially discovering best
guessed modules from other imports that previously were part of the same
file (importing all modules as part of the test).

PR Close #60503
2025-03-21 14:36:27 -07:00
Andrew Temple c5f28cd02e docs: remove link to lazy loading documentation (#60501)
Removes a link that no longer directs users to the expected documentation. Deleting the line is the recommended solution for issue #60500.
PR Close #60501
2025-03-21 14:35:58 -07:00
Pawel Kozlowski 877456e729 refactor(core): share code between ComponentRef and targeted instructions (#60463)
This refactor reorganizes code such that the dynamic bindings logic and
targeted listener instruction can share most of the code.

PR Close #60463
2025-03-21 13:12:00 +01:00
Paul Gschwendtner c667d54bc9 build: add missing tinyglobby dependency in patch branch (#60510)
This dependency is not availale in the patch brach, while it is
available in the `main` branch. A recent PR relied on this dependency,
with passing tests because we don't run tests against the patch branch.

PR Close #60510
2025-03-21 12:25:03 +01:00
Alan Agius 8e8ccc7927 fix(platform-browser): ensure platformBrowserTesting includes platformBrowser providers (#60480)
Previously, `platformBrowserTesting` did not include any `platformBrowser` providers, causing an inconsistency with `platformBrowserDynamicTesting`.

This update resolves the issue by restructuring platform inheritance to ensure proper provider inclusion:

- `platformCore → platformBrowser → platformBrowserTesting`
- `platformBrowser → platformBrowserDynamic → platformBrowserDynamicTesting`

Now, `platformBrowserTesting` correctly inherits from `platformBrowser`, aligning with the expected behavior.

PR Close #60480
2025-03-20 12:33:13 -07:00
Paul Gschwendtner 867ea1c88a test: add integration test to ensure all exported modules can be imported (#60489)
This commit adds a new integration test which will help ensure that all
exported `@NgModule`'s of framework packages can be imported by users
without any errors.

This test is generally useful, but with our upcoming changes with
relative imports, this is a good safety-net. Relative imports could
break re-exported NgModules inside NgModule's. For more details, see:
https://github.com/angular/components/pull/30667

Notably we don't expect any issues for framework package as re-exporting
`@NgModule`'s inside `@NgModule`'s is seemingly a rather rare pattern for
APF libraries (confirmed by Material only having like 4-5 instances).

PR Close #60489
2025-03-20 12:32:37 -07:00
Paul Gschwendtner bf899ef0f4 build: prepare testing infrastructure for code splitting of core package (#60487)
When we switch to relative imports, shared `.d.ts` chunks can be
generated.

We need to also pull these into our mock virtual FS testing
environments. Notably this does not cause a test slow-down because we
are talking about very few extra `.d.ts` chunk files. In our experiments
before, with no dts bundling, we saw test time increase from e.g.
20seconds to 100seconds. The 20s are still the same locally!

In addition, since code for definitions can now reside in shared `.d.ts`
chunks, the language service tests need to be adjusted in cases where
they assert for code definition locations in `@angular/core`. A new
helper prepares for more code to be moved into arbitrary `.d.ts` files;
we should simply assert the definition comes out of
`node_modules/@angular/core`.

PR Close #60487
2025-03-20 12:30:58 -07:00
Angular Robot c13c53fc65 build: update actions/upload-artifact digest to ea165f8 (#60466)
See associated pull request for more information.

PR Close #60466
2025-03-20 11:54:43 -07:00
Paul Gschwendtner 9426e83988 build: disable RBE for compliance partial goldens (#60473)
We've seen these tests regularly, but somewhat rarely to be
stuck/hanging in the remote execution workers. Since the issue was
reproducable locally (via local RBE environment), we can improve
stability for the team until we resolve this with the RBE team.

PR Close #60473
2025-03-20 07:40:22 +00:00
khalilou88 6df6aa1ce2 docs: add missing word to inheritance docs (#60467)
PR Close #60467
2025-03-19 20:41:53 +01:00
Angular Robot c422fb600a build: update actions/cache digest to 5a3ec84 (#60468)
See associated pull request for more information.

PR Close #60468
2025-03-19 20:35:34 +01:00
Pawel Kozlowski 2be008986a release: cut the v19.2.3 release 2025-03-19 20:23:56 +01:00
Alan Agius 2466fc9b42 refactor(platform-browser-dynamic): relocate DOMTestComponentRenderer to @angular/platform-browser (#60453)
This commit moves `DOMTestComponentRenderer` to `@angular/platform-browser/testing`, allowing the Angular CLI to eliminate its dependency on `@angular/platform-browser-dynamic`, which would no longer be required for new projects.

PR Close #60453
2025-03-19 19:08:09 +01:00
Kristiyan Kostadinov aa8ea7a5b2 fix(compiler-cli): report more accurate diagnostic for invalid import (#60455)
Currently when an incorrect value is in the `imports` array, we highlight the entire array which can be very noisy for large arrays. This comes up semi-regularly (at least for me) when an import is missing.

These changes add some logic that reports a more accurate diagnostic location for the most common case where the `imports` array is static. Non-static arrays will fall back to the current behavior.

PR Close #60455
2025-03-19 19:06:38 +01:00
Jessica Janiuk d306e31ee4 ci: fix flakey defer test (#60461)
This uses a fake timer scheduler implementation to ensure timer tests do not cause flakiness, similar to the incremental hydration tests.

PR Close #60461
2025-03-19 18:39:38 +01:00
Matthieu Riegler c007dd5c77 docs: fix component metadata inheritance (#60464)
fixes #60422

PR Close #60464
2025-03-19 17:59:48 +01:00
Paul Gschwendtner 1e06c8e8b6 fix(platform-browser-dynamic): ensure compiler is loaded before @angular/common (#60458)
With the recent changes to the APF bundling rules, we turned on
tree-shaking in rollup to support proper code splitting for FESM bundles.

This resulted in Rollup re-ordering imports in the FESM bundles of
`@angular/platform-browser-dynamic`— highlighting that over the past
years, this package "accidentally" resulted in the side-effects of the
compiler registering itself globally.

This continues to be the case, and our changes generally didn't cause
any issues in CLI applications because the CLI explicitly wires up the
compiler (as expected) before `-dynamic` is even loaded. For custom
setup, like Analog, this order change surfaced a breakage because e.g.
`@angular/common` with its JIT decorators of e.g. directives/services
are triggered before the compiler is actually loaded/made available.

This commit fixes this. The explicit imports in practice are a noop
because our FESM bundling doesn't recognize compiler as side-effects
true; but marking the whole -dynamic package as having side-effects;
prevents rollup from swapping the import order. Long-term, we should
look into improving this by teaching `ng_package` that e.g. the compiler
has side-effects; so that the `import @angular/compiler` statement is
not dropped when constructing FESM bundles.

PR Close #60458
2025-03-19 16:54:49 +01:00
Jan Martin 13a8709b2b fix(core): catch hydration marker with implicit body tag (#60429)
When the browser parses a valid html5 response like this:

```html
<!-- ... -->
<title>My page</title>
</head>
<!--nghm-->
<app-root></app-root>
<!-- ... -->
```

The resulting DOM will only start adding nodes to the body when it
runs into the first non-header tag. E.g.:

```yml
- head
  - title "My page"
- comment "nghm"
- body
  - app-root
```

This isn't a sign that comments are modified, so it seems worth to
handle it gracefully.

PR Close #60429
2025-03-19 15:51:37 +01:00
Matthieu Riegler 4a1ae82a6c ci: prevent renovate to update typescript automatically (#60341)
This is something we usually want to do manually.

PR Close #60341
2025-03-19 15:48:21 +01:00
Jessica Janiuk 9fea601a93 ci: update shared primitives reviewers list (#60447)
This tightens up the list of reviewers for any shared primitives code changes.

PR Close #60447
2025-03-19 08:37:40 +01:00
Matthieu Riegler dc2af3d54d refactor(dev-infra): disable progressBar test (#60448)
This test often (but inconsitantly) timeouts with
```
Error: Timeout - Async function did not complete within 5000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL)
```

We suspect a racing condition within the RouterTestingHarness.
Until this has been investigated, we'll disable this test.

PR Close #60448
2025-03-19 08:36:52 +01:00
Paul Gschwendtner 7d476782dd refactor: remove peer dependency on core from compiler (#60437)
Note that this is not a public-facing change because the compiler is not
supposed to be used directly. See `public-api-surface.md`

We are changing this because in the current state, for advanced setups
like our Bazel infrastructure in Material, this peer dependency can
result in a cycle. That is because we may decide to link the
`@angular/core` package using the compiler-cli/compiler; while
transitively the compiler has a dependency on core. That's a cycle
(surfacing in Bazel w/ `rules_js`).

Dropping this optional peer dependency is acceptable because `core`,
since recently, also has an optional peer dependency on the compiler.
This one makes more sense and is also more user-facing (people generally
never install the compiler directly).

Notably the compiler does not have any runtime dependency on `core` and
this was purely added for some safety checking. See:
https://github.com/angular/angular/commit/8c171da29f499648273e61cfb5bffaa4278097e5

PR Close #60437
2025-03-18 18:15:08 +01:00
Alan Agius a0327bb596 docs(docs-infra): add support for @example (#60443)
In TSDoc, we currently handle the `@usageNotes` annotation, but this is not a standard TSDoc tag. Instead, the `@example` annotation is the correct standard, which is used in the Angular CLI repo and on the SSR package.

This change ensures that `@example` is treated the same as `@usageNotes` during the transform process and also handle multiple instances of `@example` on the same tag.

PR Close #60443
2025-03-18 18:14:11 +01:00
Alan Agius 5c19ab5511 docs: update provideClientHydration parameter description (#60432)
PR Close #60432
2025-03-18 18:11:48 +01:00
Vlad Boisa a38319ca39 docs: change the broked link (#60436)
Change the wrong path of the link to a working one.
PR Close #60436
2025-03-18 18:09:32 +01:00
Alan Agius 9291d52856 refactor(platform-server): expose internal render method for extensibility (#60416)
The `renderApplication` and `renderModule` methods currently encapsulate the entire rendering process, making it difficult to intercept key phases from a non-Angular context. This change exports the internal `render` method, allowing us to perform operations such as:

- Flushing headers before hydration preparation
- Handling non static redirects (e.g., 302 responses)
- Intercepting router events for additional processing

This refactor serves as an experimental step toward improving the API for better customization and integration in the future.

PR Close #60416
2025-03-18 10:31:44 +01:00
Doug Parker 9dffdd744d refactor(devtools): fix reading resolutionPath (#60403)
Sometimes `forest` can be empty if the provided roots are empty, and was leading to a "Cannot read `resolutionPath` of `undefined`" error. Now we check the forest has a tree in it before looking up `resolutionPath`.

There might be a separate issue with the fact that the backend script likely shouldn't be emitting an empty forest in the first place. However we already check that a resolution path exists at all, so I think it's fair to also check that a tree was provided. We can separately look into making sure the backend is emitting valid data.

PR Close #60403
2025-03-18 10:19:51 +01:00
Angular Robot 82fb14e600 build: update io_bazel_rules_sass digest to ebdb141 (#60428)
See associated pull request for more information.

PR Close #60428
2025-03-18 10:18:16 +01:00
William Mba b4f3352232 docs: fix typo (#60431)
PR Close #60431
2025-03-18 10:11:59 +01:00
Paul Gschwendtner 2364be9ee2 build: improve partial compliance golden generation and add debug logging (#60427)
Improves the partial compliance golden generation to not rely on large
files being transmitted via `stdout`. Instead the files are written
directly as it's done in idiomatic Bazel generation actions.

In addition, we add extra stdout logging for the Bazel action, to see if
the process is actually invoked in RBE workers. Right now those are
occassionally stuck, but neither us, nor the RBE team can see anything
running, and they're occasionally stuck for 1hr.

PR Close #60427
2025-03-18 07:10:43 +00:00
Kristiyan Kostadinov 0615ffb4f7 fix(core): include input name in error message (#60404)
Includes either the `debugName` or alias of an input in the error message about a value not being available.

Fixes #60199.

PR Close #60404
2025-03-17 12:15:03 +01:00
Angular Robot acaadca289 build: pin actions/upload-artifact action to 4cec3d8 (#60401)
See associated pull request for more information.

PR Close #60401
2025-03-17 10:26:01 +01:00
Paul Gschwendtner 9b8781a523 build: upload grpc remote logs for debugging (#60393)
This should be helpful in figuring out why RBE is currently unstable.

PR Close #60393
2025-03-14 19:51:27 +01:00
Jessica Janiuk 296aded9da fix(core): execute timer trigger outside zone (#60392)
This should prevent defer timers from impacting app stability by executing them outside of the zone, similar to other defer triggers.

fixes: #60373

PR Close #60392
2025-03-14 17:01:03 +01:00
Rahat Ahmed 24c5398f7d refactor(core): Support and document manually provided internal injections (#60347)
For internal framework values stored in injectors, they are manually
managed and inserted into injectors as needed. Therefore their tokens
don't provide a value or factory. This updates the type to reflect that
and updates the jsdocs a bit.

PR Close #60347
2025-03-14 13:40:41 +01:00
Andrew Scott f030409c88 refactor(router): Clean up the transition subject (#60357)
This commit cleans up the transition subject a bit so it doesn't use a dummy
initial value. It also avoids copying over data from the previous
request when a new one is created.

PR Close #60357
2025-03-14 11:16:15 +01:00
Andrew Scott ca32602393 refactor(router): Update to use early return to reduce nesting (#60377)
Updates a switchTap body to use early return to reduce nesting

PR Close #60377
2025-03-14 11:15:28 +01:00
Denis Bendrikov 8551cabe23 fix(devtools): eliminate unnecessary scrollbars on injector tree (#59966)
Modify CSS to eliminate unnecessary scrollbars on injector tree

PR Close #59966
2025-03-14 08:38:02 +01:00
Kristiyan Kostadinov 9e1a1030c8 fix(upgrade): handle output emitters when downgrading a component (#60369)
The `DowngradeComponentAdapter` adapter was assuming that all outputs are observables, but they can also be `OutputEmitterRef`.

Fixes #60366.

PR Close #60369
2025-03-13 17:36:56 +01:00
Pawel Kozlowski 38566293a4 refactor(core): pass signal equal function to primitives (#60364)
The signals primitives package understands the equals option now
so we can pass it to the signal / computed creation methods instead
of manually assigning the equality function on a reactive node.

PR Close #60364
2025-03-13 17:24:18 +01:00
Hyron48 8caf9d7f77 docs: added short explanation about event reply (#60349)
a short explanation about event reply has been added, briefly explaining the phases that compose it

PR Close #60349
2025-03-13 17:03:41 +01:00
Nico Muszalczyk 8b888b2e52 docs: note that CSS is also taken into account in the max bundle size (#60362)
Closes #60356

PR Close #60362
2025-03-13 15:50:40 +01:00
Angular Robot fc192fdba1 docs: update Angular CLI help [19.2.x] (#60371)
Updated Angular CLI help contents.

PR Close #60371
2025-03-13 15:49:36 +01:00
Matthieu Riegler 4a30a4e26b refactor(http): replace overriden method with a ts declare (#60278)
This allows us to drop the useless `super.hasValue()`.

PR Close #60278
2025-03-12 12:27:48 -07:00
Pawel Kozlowski 0d2b964d09 refactor(core): add equal option to the signal and computed creation (#60300)
This change moves more logic to the primitives package by pushing
the equal configuration on a reactive node to the signal and
computed creation utilities.

PR Close #60300
2025-03-12 10:38:28 -07:00
Taygan Caldwell 0f19351e2a refactor: cleanup untracked in core (#60150)
Re-export untracked in core from primitives

PR Close #60150
2025-03-12 10:37:52 -07:00
Andrew Kushnir 7ee7eaa754 test(core): reduce test flakiness by increasing time delta (#60338)
This commit updates an expected delta range for a duration of a view transition to reduce flakiness of that test.

PR Close #60338
2025-03-12 10:36:36 -07:00
Hryhorii (Greg) Avcharov 61139f617d docs: remove --all argument from ng update (#60350)
Closes #60340

PR Close #60350
2025-03-12 10:36:03 -07:00
Paul Gschwendtner 9f9b1c7f8b build: enable remote execution keepalive (#60355)
This should help with network issues of spawned RBE actions. It should
also introduce timeouts when actions couldn't be spawned in a timely
manner.

PR Close #60355
2025-03-12 10:35:28 -07:00
Andrew Kushnir 7529512e7b release: cut the v19.2.2 release 2025-03-12 09:42:52 -07:00
Andrew Scott 05729f4116 refactor(router): split remainder of describes in integration test file (#60313)
to more easily navigate and identify different suites of integration tests,
this commit splits them into several different files

PR Close #60313
2025-03-11 17:13:28 -07:00
Matthieu Riegler 41fd77664e docs(docs-infra): Bump tutorial/playground to 19.2 (#60337)
fixes #60335

PR Close #60337
2025-03-11 16:54:32 -07:00
Paul Gschwendtner 044dac98c9 feat(bazel): support bundling .d.ts with code splitting (#60321) (#60332)
Instead of relying on Microsoft's API extractor for `d.ts` bundling,
we are switching to Rollup-based `.d.ts` bundling.

This allows us to support code spliting, even for `.d.ts` files,
allowing for relative imports to be used between entry-points, without
ending up duplicating `.d.ts` definitions in two files. This would otherwise cause
problems with assignability of types.

It also nicely integrates into our existing rollup configuration, and
overall simplifies the `ng_package` rule even further!

Notably `tsup` also uses this rollup plugin, and it seems to work well.
Keep in mind that Microsoft's API extractor is pretty hard to integrate,
caused many problems in the past, and isn't capable of code splitting.
This aligns our d.ts bundling with the .mjs bundling (great alignment).

PR Close #60321

PR Close #60332
2025-03-11 15:33:05 -07:00
Kristiyan Kostadinov 56b551d273 fix(compiler): incorrect spans for template literals (#60323) (#60331)
Fixes that we were producing zero-length spans for template literals and template literal elements.

Fixes #60320.
Fixes #60319.

PR Close #60323

PR Close #60331
2025-03-11 15:02:17 -07:00
Matthieu Riegler 705fb0d236 docs: add mention of GH issue for devPreview feedback (#60010)
fixes #59902

PR Close #60010
2025-03-11 14:26:25 -07:00
arturovt b6f22a7526 refactor(core): inline standalone check to be dropped (#60305)
Inlines `standalone` check into the message to be dropped.

PR Close #60305
2025-03-11 13:01:44 -07:00
Matthieu Riegler 8ed63bc1bb docs: remove mention of #59443 in 19.2 changelog (#60329)
#59443 was reverted for breaking projects in G3.

PR Close #60329
2025-03-11 12:58:16 -07:00
AlirezaEbrahimkhani e98facebac docs: change xss doc url to angular new documentation (#59915)
PR Close #59915
2025-03-11 12:57:48 -07:00
Juhmer-Tena f9b6bf91be docs: fix commit message guideline link (#60296)
Fixes the link for the commit message guideline in CONTRIBUTING.md
pointing to the building and testing angular guide instead of the
commit message guidelines

Fixes #60925

PR Close #60296
2025-03-11 11:08:24 -07:00
Kristiyan Kostadinov c41b3c83ca build: update public-api approvers (#60328)
Adds myself and Paul to the public API reviewers to help with the reviews.

PR Close #60328
2025-03-11 11:07:19 -07:00
Doug Parker e59432cf07 refactor(devtools): refactors property view drag-and-drop behavior (#60286)
The main goal of this change is to remove `categoryOrder` which effectively hard-codes the supported length of `panels`. Adding another item to `panels` is not rendered unless that is added to `categoryOrder`.

My solution to this is to make the set of categories a signal, with each category able to produce the data inside it. This allow `CdkDragDrop` to rearrange categories but then still produce the correct data in the template without needing a separate array to track order.

Also removed `hidden` and inlined it in the template, since the logic was the same for every panel.

`moveItemInArray` is unfortunately an in-place move, so I needed to manually clone the array to ensure `panels` observes an immutable update which works better with signals and change detection.

PR Close #60286
2025-03-11 09:27:04 -07:00
aparzi b144dd946e fix(core): fix removal of a container reference used in the component file (#60210)
During migration a container reference was deleted even though it was used in the component file.

PR Close #60210
2025-03-11 09:26:14 -07:00
Vlad Boisa 64bdffb97a docs: fix one broke link by #57591 (#60237)
Fix 1 link in adev toolchain `{@link forRoot}`
PR Close #60237
2025-03-11 09:24:03 -07:00
Matthieu Riegler 7832be5905 docs: fix event listener key modifier example (#60280)
PR Close #60280
2025-03-11 09:23:02 -07:00
Angular Robot 4e1f28eddf build: update github/codeql-action action to v3.28.11 (#60316)
See associated pull request for more information.

PR Close #60316
2025-03-11 09:21:44 -07:00
Angular Robot 36d740d6ef build: update dependency typescript to ~5.8.0 (#60317)
See associated pull request for more information.

PR Close #60317
2025-03-11 09:21:07 -07:00
Matthieu Riegler 30f6db37a0 refactor(core): log a warning instead of throwing error on OutputRef.emit when the directive is destroyed. (#60293)
This should not be a hard error, as nothing bad happens but the users should be warned that no event will be emitted.

fixes #60110

PR Close #60293
2025-03-10 16:08:53 -07:00
Matthieu Riegler 442ef134b8 docs(docs-infra): Extract class constructors (#60302)
fixes #59180

PR Close #60302
2025-03-10 16:05:03 -07:00
Andrew Scott b1d0d20240 refactor(router): split integration test file (#60311)
to more easily navigate and identify different suites of integration tests,
this commit splits them into several different files

PR Close #60311
2025-03-10 16:03:54 -07:00
Jessica Janiuk 4e87b58fd1 ci: fix timer test flakiness (#60310)
This replaces the TimerScheduler entirely and ensures the callback is called immediately. This should prevent any further flakiness.

PR Close #60310
2025-03-10 15:08:54 -07:00
arturovt ec65169dfb refactor(core): replace PLATFORM_ID in initTransferState (#60299)
Replaces `PLATFORM_ID` check with the `ngServerMode`.

PR Close #60299
2025-03-10 13:49:24 -07:00
Paul Gschwendtner 15c42969fc fix(platform-server): add missing peer dependency for rxjs (#60308)
The server package imports from `rxjs`, but the dependency was not
specified as `peerDependency`, nor `dependency`. This surfaces as an
error in strict dependency environments, like with pnpm's symlinked node
modules structure.

This commit fixes this. It presumably doesn't fail with e.g. Yarn, or
npm because of node modules hoisting.

PR Close #60308
2025-03-10 11:41:06 -07:00
Doug Parker cfdadb562f release: bump Angular DevTools version to 1.0.26 (#60309)
PR Close #60309
2025-03-10 11:40:27 -07:00
Kristiyan Kostadinov 23ca88522b fix(compiler-cli): handle transformed classes when generating HMR code (#60298)
We had several places where we were trying to get the source file of a class for which we're generating HMR-related code. These calls will fail if the class was transformed so we have to get its source file through the original node.

Fixes #60287.

PR Close #60298
2025-03-10 09:58:53 -07:00
Doug Parker ea8008d95e fix(devtools): handle case where directive metadata has undefined dependencies (#60256)
This fixes a bug introduced by [#60206](https://github.com/angular/angular/pull/60206/files#diff-c07b9ecd59f6e0ed636ac9672b9644178d9a999f04bc8b8198b13e86589dfa5b). Previously `DirectiveMetadata.prototype.dependencies` was always set, but in that PR `dependencies` is only set if an `Injector` is found (which only happens when `ng.getInjector` is *not* defined). This causes an error when evaluating `dependencies.length` in the template.

Fix is just to check for existance before calling `length`.

PR Close #60256
2025-03-10 09:57:26 -07:00
Doug Parker cef606aa8e refactor(devtools): remove input/output/property links (#60284)
These links aren't that helpful in the context of Angular DevTools for a few reasons:
1. Users of the extension should already have a general understanding of core Angular concepts, inputs and outputs included.
2. The input and output links go to API documentation which isn't useful for someone who doesn't actually understand the core concepts anyways.
3. These links point to signals documentation even though DevTools shows non-signal inputs and outputs.
4. Properties linked to template binding docs, which doesn't *really* have anything to do with the plain JS properties being shown in DevTools anyways.

PR Close #60284
2025-03-10 09:56:20 -07:00
Joey Perrott 44155c9209 refactor(bazel): remove primary_bundle_name as attr for ng_package (#60306)
Remove primary_bundle_name as an attr for ng_package as it is unused.

PR Close #60306
2025-03-10 09:31:20 -07:00
Joey Perrott 43b89e7bb1 refactor(bazel): hardcode esm as the ouput for rollup (#60306)
Remove the option as an arg for creating a rollup config since it is static.

PR Close #60306
2025-03-10 09:31:20 -07:00
Hryhorii Avcharov 5e2f312321 fix(docs-infra): terminal light mode text color (#60246)
This commit changes the text color in terminal light mode to improve
visibility and user experience. The previous color was too light and
made it difficult to read the text.

PR Close #60246
2025-03-10 09:23:20 -07:00
François bd15db3960 docs: fix typo and link in v16 update guide (#60277)
PR Close #60277
2025-03-10 09:22:34 -07:00
Paul Gschwendtner bde1b37e0b build: properly compile tests in core with Angular compiler (#60268)
Previously we never could use relative imports to import e.g. `Component`
in e.g. the `core/tests/bundling` folder. This was necessary because otherwise the
Angular compiler wouldn't process those files as it wouldn't recognize
the Angular decorator as the one from `@angular/core`.

Notably this still isn't a large issue because relative imports still
work for most core tests, that are JIT compiled!

For bundling tests though, or some smaller targets, our new upcoming
guidelines for using relative imports inside the full package; fall
apart. This commit unblocks this effort and allows us to use relative
imports in all tests of `packages/core`. This is achieved by leveraging
the existing `isCore` functionality of the compiler, and fixing a few
instances that were missing before.

PR Close #60268
2025-03-07 11:00:48 -08:00
Vlad Boisa 5131794cde docs: fix typo in desription (#60261)
Fix typos in description of `styleUrl`

Fixes #60258
PR Close #60261
2025-03-07 10:55:38 -08:00
Paul Gschwendtner 70fb3bba4b refactor: add fast-glob to bazel dependencies (#60253)
This will be necessary for downstream (private) consumers
of the `@angular/bazel` package.

PR Close #60253
2025-03-06 12:50:29 -08:00
Jessica Janiuk 5db2df8aad ci: fix flakey timer tests (#60254)
This adjusts the tests to have a longer await time and removes the click portion of the test. These tests should only pass if the timer has triggered hydration.

PR Close #60254
2025-03-06 12:49:48 -08:00
Jessica Janiuk bb12b30d52 fix(core): ensures immediate trigger fires properly with lazy loaded routes (#60203)
In the case that a route was lazy loaded, some triggers would never properly finish hydrating due to things firing before the route finished resolving.
This will find the topmost parent defer block and ensure the registry knows about it before trying to hydrate.
In the case that the registry does not yet know, just the affected triggers await app stability before initializing.
fixes #59997

PR Close #60203
2025-03-06 12:47:47 -08:00
Angular Robot 0c105476a1 docs: update Angular CLI help [19.2.x] (#60249)
Updated Angular CLI help contents.

PR Close #60249
2025-03-06 11:27:46 -08:00
Kristiyan Kostadinov 48dc0d6dc7 refactor(language-service): rename internal symbols to accommodate type checking outside a template (#60191)
Currently the language service has some template-specific terminology around type checking, because that's the only place where we had TCB support. These changes make it more generic to accommodate future functionality.

PR Close #60191
2025-03-06 10:39:32 -08:00
Kristiyan Kostadinov 9d8e943e62 refactor(compiler-cli): rework resource handling to allow directives (#60191)
Currently only components can have resources, because they're the only symbol kinds being type checked. Since we want to add directives to it, these changes rework the resource handling to accommodate them.

PR Close #60191
2025-03-06 10:39:32 -08:00
Kristiyan Kostadinov 1a71167b5c refactor(compiler-cli): rework source manager to accommodate directives (#60191)
Currently the `TemplateSourceManager` is set up to specifically cater to component templates. These changes make it more generic so we can reuse it for directives.

PR Close #60191
2025-03-06 10:39:32 -08:00
Kristiyan Kostadinov 83218bd0d1 refactor(compiler-cli): rework type checking internals to accommodate more than components (#60191)
Currently a lot of the internal type checking data structures are set up specifically for components, because we only support type checking of templates. Since this will change in future commits, these changes prepare for it by renaming various methods and separating out component-specific data.

PR Close #60191
2025-03-06 10:39:32 -08:00
Kristiyan Kostadinov 5cc80dc72f refactor(compiler-cli): change TemplateId terminology (#60191)
Renames the `TemplateId` and terminology related to it, because we'll be using it for more than just templates.

PR Close #60191
2025-03-06 10:39:32 -08:00
Kristiyan Kostadinov 9cdf950108 refactor(compiler): allow binder to apply to more than one set of nodes (#60191)
Currently `R3TargetBinder.bind` gets a set of data back from `DirectiveBinder.apply` and `TemplateBinder.applyWithScope`. This will be annoying  if we have multiple sources of data, because we'd have to do merge them at the end.

These changes switch to constructing the various data structures ahead of time and passing them into the binders to populate them instead.

I also extracted some of the less trivial types into type aliases so we don't have to repeat them.

PR Close #60191
2025-03-06 10:39:31 -08:00
kw 279e6b846f docs: Correct comments for FormControl (#58352)
PR Close #58352
2025-03-06 10:36:47 -08:00
Doug Parker 07cc97ff9b release: bump Angular DevTools version to 1.0.25 (#60235)
PR Close #60235
2025-03-06 10:32:02 -08:00
Paul Gschwendtner 684e837758 feat(bazel): support shared chunks in ng_package (#60241)
Historically we've had to be VERY cautious about the way we import
things between entry-points. That is because the `ng_package` rule
bundling is subject to silently introducing code duplication, breaking
singletons etc. We've had this surface a couple of times already, and
dev-infra tried to help detect such cases by adding safety analysis into
`ng_package`.

Long-term we want to get to an approach where it's easy to simply share
code between chunks. Precisely, with the upcoming `rules_js` migration,
this will be necessary as we will have different import "guidelines"
that would currently, before this commit, result in code duplication, or
trigger our "safety check/lint".

This commit prepares `ng_package` to support relative imports between
entry-points, so that we only need the safety check for cross-package
imports/exports. The result is that `ng_package`/APF is now smartly able
to generate shared chunks for things that are needed between multiple
entry-points. Yay!

Note that those shared chunks still remain private, and are guarded by
our `package.json` "exports"; so no new public API surface is
exposed.

PR Close #60241
2025-03-06 10:29:05 -08:00
Matthieu Riegler dad02c6535 refactor(http): Make sur to pass context & transferCache from httpResource to the underlying request. (#60228)
Prior to this change, both were accepted as argument but never passed to the client.

PR Close #60228
2025-03-06 07:59:07 -08:00
Matthieu Riegler dfc8c432db docs(docs-infra): fix initial TOC selection (#60240)
PR Close #60240
2025-03-06 07:55:43 -08:00
Andrew Kushnir b967ca6b3b Revert "fix(router): update symbols (#60233)" (#60236)
This reverts commit 7bcdf7c143.
The original change causing CI failures was affecting the main branch only, reverting from the patch branch (since it causes CI failures).

PR Close #60236
2025-03-06 10:22:01 +01:00
Jessica Janiuk 7bcdf7c143 fix(router): update symbols (#60233)
This updates the goldens for the router.

PR Close #60233
2025-03-05 15:34:05 -08:00
arturovt 484e0cf43e refactor(platform-browser): drop unsupported event target error message in production (#60016)
Drops unsupported event target error message in production and replaces it with an existing error code.

PR Close #60016
2025-03-05 14:45:50 -08:00
arturovt 6b019ae958 refactor(core): add token to missing injection context error message (#60009)
In this commit, we add injector token information to the error message to improve debugging and context awareness, because it is hard to capture the `inject()` stack trace in asynchronous contexts.

PR Close #60009
2025-03-05 14:44:44 -08:00
arturovt 6dc41265fd fix(core): check whether application is destroyed before initializing event replay (#59789)
In this commit, we check whether the application is destroyed before initializing event replay. The application may be destroyed before it becomes stable, so when the `whenStable` resolves, the injector might already be in a destroyed state. As a result, calling `injector.get` would throw an error indicating that the injector has already been destroyed.

PR Close #59789
2025-03-05 14:43:48 -08:00
arturovt 3076254567 refactor(common): drop ngIf assert template error in production (#59705)
This commit removes the `assertTemplate` error message in production.

PR Close #59705
2025-03-05 14:42:19 -08:00
cexbrayat 90a16a1088 fix(common): support equality function in httpResource (#60026)
The `equal` option was not passed to the underlying resource.

PR Close #60026
2025-03-05 14:41:15 -08:00
iteriani 8d770eccee refactor(core): Remove the optional flag from Injector and all casts. (#60154)
Note that this does NOT use the retrieve method yet. I believe we need to move the logic for notFoundValue into the inject implementation.

PR Close #60154
2025-03-05 13:44:00 -08:00
Taygan Caldwell 699733fcc3 refactor: add untracked to primitives (#60105)
add untracked to primitives to allow Wiz to use it

PR Close #60105
2025-03-05 12:11:40 -08:00
Vlad Boisa b76af47966 docs: change broke Pipe link (#60226)
Change broke link, swap from /guides  to /guide
PR Close #60226
2025-03-05 12:11:06 -08:00
Matthieu Riegler 6accd1b0f5 docs(docs-infra): Use intersectionObserver for TOC (#60166)
Using IntersectionObservers simplfies the code and doesn't rely on APIs that will trigger a reflow.

PR Close #60166
2025-03-05 12:09:45 -08:00
Andrew Scott f08dbe0970 docs: Add more pending tasks documentation in zoneless readme (#59689)
This commit expands on the pending tasks documentation in the zoneless readme

PR Close #59689
2025-03-05 12:08:58 -08:00
Andrew Scott 6c7493e39d docs(core): Update zoneless test documentation to clarify OnPush requirement (#59689)
This updates the zoneless documentation to mention that components under
test a required to be onpush compatible. This includes any wrapper
components only used in tests.

fixes #59082

PR Close #59689
2025-03-05 12:08:58 -08:00
Andrew Scott cc97128760 docs(core): Clarify what it means to be a host for user components (#59689)
Adds a note to clarify what it means for a component to host a user
component in the context of `OnPush` restrictions.

fixes #58648

PR Close #59689
2025-03-05 12:08:58 -08:00
Doug Parker 39e8bd0f4b refactor(devtools): ignore getInjector when it is not supported (#60206)
Previously Angular DevTools would throw when run on an application which does not support `getInjector`, now it safely ignores it and assumes dependency injection is not supported.

PR Close #60206
2025-03-05 12:05:46 -08:00
AleksanderBodurri ba4b3dbed7 fix(devtools): handle case where router tree does not exist (#60221)
Previously this was throwing errors in applications with no Router token.

Now it skips emitting events for the router tree when it is unable to find the Router token.

Note: If these events don't emit, DevTools treats the RouterTree feature as disabled.

PR Close #60221
2025-03-05 12:05:02 -08:00
Miles Malerba d9e022dae2 release: cut the v19.2.1 release 2025-03-05 11:12:18 -08:00
arturovt 48d899f423 docs(zone.js): update NON-STANDARD-APIS.md (#58098)
This commit makes some grammatical changes to the existing documentation.

PR Close #58098
2025-03-05 17:30:43 +00:00
arturovt 19b6564cb2 docs(zone.js): update STANDARD-APIS.md (#58091)
This commit makes some grammatical changes to the existing documentation and adds additional
information about events.

PR Close #58091
2025-03-05 17:28:41 +00:00
arturovt f24246ef25 refactor(core): inline isFactory within getNodeInjectable (#59824)
This commit inlines the `isFactory` function body directly within `getNodeInjectable` because it is only used once. ESBuild does not inline its body within the function, which can be observed when running the build with `NG_BUILD_MANGLE=0`. The results after inlining are as follows:

```
getNodeInjectable x 70,397,377 ops/sec ±3.88% (52 runs sampled)
getNodeInjectable_inlined x 77,834,432 ops/sec ±3.13% (60 runs sampled)
```

PR Close #59824
2025-03-05 17:24:53 +00:00
Doug Parker 65d2ca9ed3 refactor(devtools): ignore ng.applyChanges if not supported (#60207)
Previously Angular DevTools would throw if `ng.applyChanges` was not defined. Now DevTools silently ignores the issue, assuming `mutateComponentOrDirective` was sufficient to update the application.

PR Close #60207
2025-03-05 16:53:57 +00:00
Matthieu Riegler a2db87ef81 docs(docs-infra): fix secondary menu (#60212)
fixes #58897

PR Close #60212
2025-03-05 11:05:07 +01:00
Matthieu Riegler 94ed3c3630 docs(docs-infra): AppComponent cleanup (#60212)
PR Close #60212
2025-03-05 11:05:07 +01:00
Pawel Kozlowski a64a5755e8 refactor(docs-infra): AppComponent cleanups (#58897)
This change contains multiple cleanups in the AppComponent:
- remove unused code;
- use router input bindings instead of manual read from
  the active route;
- remove isBrowser checks from even handlers (click events
  should not be invoked on the server, right?)

PR Close #58897
2025-03-04 22:20:49 +00:00
Jeevan Mahesha 20add2738c docs: update Angular CLI installation instructions for npm, pnpm, yarn, and bun (#59832)
PR Close #59832
2025-03-04 22:19:47 +00:00
Jeevan Mahesha e27a319261 docs: extend Angular CLI installation instructions for pnpm, yarn, and bun (#59832)
PR Close #59832
2025-03-04 22:19:47 +00:00
Mithilesh Zavar fbbe5d55b1 docs(migrations): Fix indentation in documentation for signal inputs migration (#60204)
PR Close #60204
2025-03-04 22:08:29 +00:00
Matthieu Riegler 507ed58152 refactor(core): extract dirty and markForRefresh from the private ViewRef. (#59122)
This allows better tree shaking from projects without the `element` package.

PR Close #59122
2025-03-04 22:05:41 +00:00
Matthieu Riegler 31bbbe9665 docs(docs-infra): Throw error at build time for invalid links (#59162)
PR Close #59162
2025-03-04 20:07:24 +00:00
Samuel Perez 83abe5f606 docs: fix all brokens links on the API pages (#59162)
This PR fix is for the broken links on the API
pages mentioned in issue #57591.

PR Close #59162
2025-03-04 20:07:24 +00:00
Matthieu Riegler 26b3a8f206 refactor(http): add context property to httpResource (#60188)
This was an oversight, `context` can be supported out of the box.

PR Close #60188
2025-03-04 19:57:22 +00:00
Matthieu Riegler edae26e117 docs(docs-infra): Don't truncate types in symbol extraction (#59909)
PR Close #59909
2025-03-04 19:54:58 +00:00
Alexis 8579ff8352 docs: Remove misleading default value DEFAULT_CURRENCY_CODE (#59977)
PR Close #59977
2025-03-04 19:37:57 +00:00
Matthieu Riegler 2bffacbe5e refactor(core): throw an Cyclic Dependency Error in prod mode (#60118)
Prior to this change, cyclic injection didn't trigger any error in prod mode, resulting into injecting the `CIRCULAR` object.
This could lead to strange errors where no method would be found on the token.

fixes #60074

PR Close #60118
2025-03-04 19:37:19 +00:00
naaajii f24a8c60ad docs: update license year (#59883)
updates the year in footer and placeholder for generated files

PR Close #59883
2025-03-04 19:36:48 +00:00
kirjs 036ee75684 docs: mention that log format makes it analyzable for changelog generation. (#58786)
PR Close #58786
2025-03-04 19:35:55 +00:00
kirjs 33a826b196 docs: sync the scope lists and drop ve (#58786)
PR Close #58786
2025-03-04 19:35:55 +00:00
kirjs 114658cf8c docs: address comments (#58786)
PR Close #58786
2025-03-04 19:35:55 +00:00
kirjs d30ea1b89c docs: move commit message guidelies to a separate file (#58786)
PR Close #58786
2025-03-04 19:35:54 +00:00
michael-small aff6d3d135 docs: update version table for 19.2 (#60173)
PR Close #60173
2025-03-04 17:47:10 +00:00
hawkgs 1c31c0d141 docs(docs-infra): API doc content rendering fixes (#60116)
The PR introduces a few doc content rendering fixes:
- Fix highlighted section heading styles (regression from #59965).
- Convert JSDoc links within 'Usage Notes' sections to HTML and render them.
- Add IDs to doc content headings. This, by itself, makes these headings available in the page ToC.

PR Close #60116
2025-03-04 17:46:31 +00:00
Andrew Scott 3f0116607d fix(language-service): Forward the tags for quick info from the type definition (#59524)
Prior to this commit, the tags from the type definition were dropped.
Tags may include, but are not limited to, deprecation information from
the jsdoc.

PR Close #59524
2025-03-04 17:37:23 +00:00
Lang 080fb08b76 docs: fix the wrong way to get a signal value (#59194)
PR Close #59194
2025-03-04 17:28:09 +00:00
Lang d3dde17693 docs: fix typo (#59194)
Co-authored-by: Enea Jahollari <jahollarienea14@gmail.com>
PR Close #59194
2025-03-04 17:28:09 +00:00
Lang 9ae9d9adde docs: use model API in two-way binding example (#59194)
PR Close #59194
2025-03-04 17:28:08 +00:00
Miles Malerba c615bdcde9 docs(docs-infra): Improve support for @link within the jsdoc. (#60201)
PR Close #60201
2025-03-04 17:13:43 +00:00
hawkgs 79c337448e docs: fix AnimationGroupMetadata description (#59733)
Fix the `animations/group()` link.

PR Close #59733
2025-03-04 17:12:11 +00:00
Jeevan Mahesha c67c551fb8 docs: update template syntax to new control flow (#59760)
PR Close #59760
2025-03-04 17:07:06 +00:00
Matthieu Riegler 1149686da5 docs(docs-infra): hide github link for external repos. (#60114)
fixes #60113

PR Close #60114
2025-03-04 17:02:37 +00:00
Matthieu Riegler 5c3be24712 docs(docs-infra): remove animation package (#60165)
PR Close #60165
2025-03-04 17:01:47 +00:00
Angular Robot 444671ac5b build: update dependency @types/chrome to ^0.0.307 (#60195)
See associated pull request for more information.

PR Close #60195
2025-03-04 17:00:22 +00:00
Matthieu Riegler d1233ebfa8 docs(docs-infra): wait for the DOM to be rendered (#60163)
the code inside `renderExample` is explicitly querying the DOM. We need to wait for it to be rendered for those functions to work.

PR Close #60163
2025-03-04 16:58:14 +00:00
Kristiyan Kostadinov 1c328ac261 build: update to TypeScript 5.8 final (#60176)
Updates the repo to stable version of TypeScript 5.8.

PR Close #60176
2025-03-04 16:57:36 +00:00
vladboisa cd31bfcc3e docs: change broke link (#60189)
Change the broked link to the working one

PR Close #60189
2025-03-03 22:20:53 +00:00
Andrew Scott 27174165a6 refactor(core): Update push/replace navigation to not trigger popstate (#60028)
This matches the spec, though there is a bug in chrome that does trigger these events.

PR Close #60028
2025-03-03 18:40:59 +00:00
Andrew Scott bf89792f8b refactor(core): Update fake navigation to more closely follow the spec (#60028)
This commit updates the implementation of the fake navigation to more
closely follow the spec. This includes links to spec parts as well as
some reorganization to have the flow of the code more exactly follow the
corresponding steps in the spec. This makes it easier to verify that th
behavior is correct.

PR Close #60028
2025-03-03 18:40:59 +00:00
Andrew Scott 49e3ec0dcf refactor(core): Ensure fake navigation is not aborted after it succeeds (#60028)
The navigate event was only ever being cleared when a new navigation
happened. That new navigation would abort the previous one, even if it
had already finished successfully.

PR Close #60028
2025-03-03 18:40:59 +00:00
arturovt c2de5f68b3 fix(common): clean up onUrlChange listener when root scope is destroyed (#60004)
This cleans up the `onUrlChange` listener once the root scope is destroyed.

PR Close #60004
2025-03-03 17:14:33 +00:00
Doug Parker dd70675893 release: bump Angular DevTools version to 1.0.24 (#60148)
PR Close #60148
2025-03-03 17:12:23 +00:00
Andrew Scott 1dd94476b3 fix(compiler-cli): ensure template IDs are not reused if a source file changes (#60152)
This commit fixes a bug where nodes are reused across incremental
compilations. The source file's next template ID is lost because a new
source file is created but nodes may still be retained.

PR Close #60152
2025-02-28 19:53:06 +00:00
Vlad Boisa c288a037b5 docs: fix not working links (#60160)
Remove JSDocs link, and replace the automatic linking with a regular markdown link

Fixes #59983

PR Close #60160
2025-02-28 19:52:33 +00:00
iteriani b81ea4f672 refactor(core): Move getCurrentInjector/setCurrentInjector to primitives package. (#60090)
This change casts the injector back and forth since all instances of
injector currently don't implement the `retrieve` method. Note that
the retrieve method is seen as optional, so that Angular can revert back to
inject if necessary.

PR Close #60090
2025-02-28 18:47:09 +00:00
Kristiyan Kostadinov 1b3b05bf72 fix(core): cache ComponentRef inputs and outputs (#60156)
The set of inputs and outputs of a component is static, but the getter for the `inputs` and `outputs` property was re-computing them every time which the user might not expect. These changes add a couple of lines to cache them instead.

PR Close #60156
2025-02-28 16:31:05 +00:00
Jessica Janiuk cfad089cc3 fix(core): prevents event replay from being called on comment nodes (#60130)
In some rare cases with directives, it is possible that the stash function might be called on a comment node. This actually verifies that the node is an element and exits otherwise.

fixes: #60070

PR Close #60130
2025-02-28 16:30:28 +00:00
Jessica Janiuk 95d227e5ef refactor(core): clean up event replay tests (#60130)
This updates the event replay tests to make them share the structure and utility functions used by hydration tests. This also resolves some soft errors in the event replay tests.

PR Close #60130
2025-02-28 16:30:28 +00:00
Matthieu Riegler ddfaf0cd46 refactor(migrations): Don't migrate twice the same file on the self-closing tag migration (#60065)
This commit fixes an issue when ts files are referenced multiple times (and thus analyzed multiple times) for example from a `tsconfig.json` and `tsconfig.spec.json`.

PR Close #60065
2025-02-28 16:27:40 +00:00
Hakeem b09f4a5c79 docs(docs-infra): add a tooltip to show the full text when nav item text is lengthy (#59038)
PR Close #59038
2025-02-27 18:25:19 +00:00
Hakeem 6c0c012e08 docs(docs-infra): handle long names in the sub nav (#59038)
PR Close #59038
2025-02-27 18:25:19 +00:00
Angular Robot a16dfb1b36 build: update actions/cache digest to d4323d4 (#60145)
See associated pull request for more information.

PR Close #60145
2025-02-27 18:23:42 +00:00
arturovt e549bdec8c refactor(animations): tree-shake regular expressions (#60095)
Adds a pure annotation to regular expressions because if the animations package is indirectly referenced in the code, it would include regular expressions in the bundle, even if they're unused (since `new` is side-effectful).

PR Close #60095
2025-02-27 17:53:25 +00:00
Lang 16ca676db0 docs: replace NgIf with new template syntax @if (#59159)
PR Close #59159
2025-02-27 17:41:54 +00:00
ColinJolivet 187758ccca refactor(docs-infra): remove expand button in example viewer if there is no hidden lines (#59086)
Remove the expand button of an example viewer if there is no hidden lines in it, in order not to confuse people

PR Close #59086
2025-02-27 15:48:02 +00:00
Jessica Janiuk 330c24aed9 fix(core): prevent invoking replay listeners on disconnected nodes (#60103)
This prevents replay from happening on nodes that have been removed from the DOM.

fixes: #59841

PR Close #60103
2025-02-27 15:45:14 +00:00
Matthieu Riegler ada75b605e docs(docs-infra): remove tutorial redirection (#60138)
PR Close #60138
2025-02-27 15:41:19 +00:00
Hryhorii Avcharov b06ed3cbf8 docs: fix mermaid event node text visibility in light mode (#60124)
PR Close #60124
2025-02-27 00:27:12 +00:00
Jessica Janiuk e012cf0acf build: add ignore revs file for git blame (#60117)
This allows for setting git and vscode gitlens to ignore specific commit hashes for bulk changes.

PR Close #60117
2025-02-26 16:19:26 -05:00
kirjs 8e9463bffb release: cut the v19.2.0 release 2025-02-26 16:10:05 -05:00
Matthieu Riegler 9b4727587a docs(docs-infra): remove explicit dectectChanges() (#60098)
PR Close #60098
2025-02-26 12:01:00 -05:00
Matthieu Riegler ee2f07fcff refactor(http): rename map to parse on HttpResourceOptions (#60112)
This reflects more the feature intended for this callback.

PR Close #60112
2025-02-26 11:52:44 -05:00
arturovt f76fd48b4a refactor(core): tree-shake REF_EXTRACTOR_REGEXP (#60081)
The `REF_EXTRACTOR_REGEXP` is a `new` expression that has side effects and is not dropped in production, even if it is unused.

PR Close #60081
2025-02-26 11:17:51 -05:00
arturovt 5de4b0cb70 refactor(core): inline depPath in throwCyclicDependencyError to be dropped (#60084)
Inlines the `depPath` within the `throwCyclicDependencyError`, because it's not being tree-shaken in production.

PR Close #60084
2025-02-26 11:10:38 -05:00
Jens Kuehlers fca21320e6 docs: move release date for v20 by one week (#60111)
PR Close #60111
2025-02-26 11:00:44 -05:00
arturovt c4126c7b9a refactor(forms): tree-shake _checkParentType in production (#60041)
In this commit, we move `_checkParentType` to a separate function to avoid a redundant prototype method in production.

PR Close #60041
2025-02-25 14:12:44 -05:00
Andrew Scott 176475f0fc fix(language-service): provide correct rename info for elements (#60088)
This commit ensures we do not block element rename if it is supported by
other rename providers.

fixes https://github.com/angular/vscode-ng-language-service/issues/2077

PR Close #60088
2025-02-25 14:10:55 -05:00
Kristiyan Kostadinov 7d6636087d fix(common): make types for HttpClient more readable (#59901)
`HttpClient` has a lot of overloads to achieve proper type checking, however each overload is also very long which makes it hard to read on adev. These changes replace the object literal types with `Record` to make them a bit more concise.

PR Close #59901
2025-02-25 13:01:11 -05:00
Pawel Kozlowski ce3a9a24d7 refactor(core): remove performance mark feature for signals (#59991)
Remove the performance mark feature from the Angular signal impl
so more code can be shared between primitives and other frameworks.

PR Close #59991
2025-02-25 11:10:09 -05:00
Kristiyan Kostadinov ef17371ab6 refactor(core): add infrastructure for setting inputs on specific directives (#60075)
Sets up the infrastructure that will allow to write only to a specific directive and its host directives as a base for future functionality.

I've also renamed `setInputsForProperty` to be a bit more explicit that its sets all inputs.

PR Close #60075
2025-02-25 10:58:51 -05:00
Kristiyan Kostadinov 6473214384 refactor(core): avoid memory allocations if there are no host directives (#60075)
Currently the host directive logic disassembles and re-assembles the array of directive matches, in case there are host directives which in most cases produces an identical array.

These changes add some logic so that we only need to allocate the additional memory if we actually need it.

PR Close #60075
2025-02-25 10:58:51 -05:00
Kristiyan Kostadinov f23946abe9 refactor(core): move component logic out of host directives resolution (#60075)
In order to mark a TNode as a component, we need to store the index of the component definition. Currently this happens in the logic that resolves host directives, because the component's host directives can move affect the index.

These changes move the logic out into the directive initialization logic since it doesn't have much to do with host directives.

PR Close #60075
2025-02-25 10:58:51 -05:00
Kristiyan Kostadinov fa6d9c22ac refactor(core): track match index of directives (#60075)
If we want to target an input write to a directive, we have to know the index at which its instance is stored. Technically we can already find this by looking through `TView.data`, but that'll require a linear lookup for each write which can get slow.

These changes introduce the new `TNode.directiveToIndex` map which allows us to quickly find the index of a directive based on its definition, as well as any host directives that its might've brought in.

PR Close #60075
2025-02-25 10:58:51 -05:00
Angular Robot d5f467e601 build: update all non-major dependencies (#60093)
See associated pull request for more information.

PR Close #60093
2025-02-25 10:49:25 -05:00
Angular Robot b5f28006b3 build: update io_bazel_rules_sass digest to 3b3667f (#60092)
See associated pull request for more information.

PR Close #60092
2025-02-25 10:45:36 -05:00
Angular Robot aac3e8acf6 build: update scorecard action dependencies (#60094)
See associated pull request for more information.

PR Close #60094
2025-02-25 10:43:28 -05:00
mgechev 10fb8722fe docs: add a page for custom build pipeline (#60058)
Add a documentation page for creating a custom build pipeline
with community plugins.

PR Close #60058
2025-02-25 10:40:36 -05:00
Aristeidis Bampakos 93c1918ab1 docs: update security guide (#59885)
PR Close #59885
2025-02-25 10:24:27 -05:00
Kristiyan Kostadinov ebfbaeba54 fix(core): capture stack for HMR errors (#60067)
Currently we send the `message` of an error thrown during HMR. That's usually not enough so now we also capture the stack trace.

Relates to https://github.com/angular/angular-cli/issues/29695.

PR Close #60067
2025-02-24 11:56:17 -05:00
hawkgs 9c5a6a6442 refactor(devtools): drop @ from inputs and outputs label (#60053)
Drop '@' from inputs and outputs label to fit in with the new signal-based API.

PR Close #60053
2025-02-24 10:49:13 -05:00
Evgeniy Aksyonov 67366d2f93 docs: fix typo in outputs.md for migrations section (#60055)
PR Close #60055
2025-02-24 10:46:23 -05:00
hawkgs 225e602176 docs(docs-infra): fix the top position of the search dialog (#60012)
Instead of centering the dialog, fix the top position in such way that when the results container is full, the dialog looks centered. This prevents the dialog from "jumping" when you type and the results change.

PR Close #60012
2025-02-24 10:44:19 -05:00
Charles Lyding 02a768e1d2 docs: use @angular/build directly in example/tutorial projects (#60046)
By using the `@angular/build` package directly within projects for each
example and tutorial, the total install size can be reduced. This lowers the amount
of time required to be spent setting up the dependencies in browser
before the example is displayed.

The `@angular/build@19.2.0-next.2` package currently has a total unpacked size of ~115 MB.
The `@angular-devkit/build-angular@19.2.0-next.2` package currently has a total unpacked size of ~291 MB.

This also removes the now unneeded `NG_BUILD_PARALLEL_TS=0` environment variable usage.

PR Close #60046
2025-02-24 10:14:18 -05:00
Kristiyan Kostadinov 35d20cb4b4 refactor(core): do not store input/output public names (#60036)
Reworks the `TNode.inputs` and `TNode.outputs` to not store the public names of bindings. The only reason they were stored was for host directive re-aliasing which is handled through a different data structure now.

PR Close #60036
2025-02-21 14:07:35 -05:00
Kristiyan Kostadinov 352021e1d2 refactor(core): separate host directive inputs from selector-matched ones (#60036)
Currently `TNode.inputs`/`TNode.outputs` store all of the available bindings on that node, no matter if they came from a directive that the user applied directly or from a host directive. This has a couple of drawbacks:
1. We need to store more information that necessary. For example, the only reason we have strings in the arrays is to facilitate host directive aliasing.
2. It doesn't allow us to distinguish which host directives belong to which selector-matched directives.

These changes are a step towards resolving both issues by storing the host directive binding information in separate data structures.

PR Close #60036
2025-02-21 14:07:35 -05:00
Kristiyan Kostadinov 285abbb38f refactor(core): rework how inputs/outputs are initialized (#60036)
Reworks the functions that create the `initialInputs`, `inputs` and `outputs` structures to initilize them within the function, instead of returning them to be initialized later. This will simplify future refactors where they'll produce more than one piece of information.

PR Close #60036
2025-02-21 14:07:35 -05:00
Jessica Janiuk 3fd6551cae docs: remove todo from jsdoc (#60042)
This removes TODO from a JSDoc block that made it show up on adev.

PR Close #60042
2025-02-21 11:16:48 -05:00
Pawel Kozlowski ea8662ab3e refactor(core): remove duplicated checks for ngNonBindable (#60048)
This refactoring consolidates logic around detecting ngNonBindable
mode - previously those checks were done in two separate places.
By doing the check in one place we can simplify the directive resolution
logic.

PR Close #60048
2025-02-21 11:08:50 -05:00
Jessica Janiuk 1d28a42815 refactor(core): clean up when blocks fail to fetch or hydrate (#59740)
There are cases where resources fail to fetch or the DOM has changed due to an if block. This should clean up the remaining promises and any registry references to those blocks in that case.

PR Close #59740
2025-02-21 11:08:04 -05:00
arturovt 21740846b5 refactor(core): drop platform check in ImagePerformanceWarning (#59809)
Replaces `PLATFORM_ID` checks with `ngServerMode`.

PR Close #59809
2025-02-20 12:32:23 -05:00
hawkgs 4fde15438f refactor(devtools): fix component inspector highlighting (#59995)
Use `position: absolute` instead of `position: fixed`. This fixes the odd behavior that can be reproduced when scrolling.

PR Close #59995
2025-02-20 11:56:09 -05:00
Trevor Florence 7a1bf0610e fix(benchpress): Ensure future-proof correct initialization order (#60025)
Future changes to initialization order can cause this previously OK code to start having compiler erroring like: `TS2729: Property 'foo' is used before its initialization.`

PR Close #60025
2025-02-20 11:21:55 -05:00
muhammadali1658 195d0b1ff5 docs: Fix typo ')' in banner-initial.component.spec.ts (#60032)
PR Close #60032
2025-02-20 11:03:11 -05:00
Joey Perrott 053593ef3e ci: update deploy doc site script (#60021)
Update the checked in version of the deploy script

PR Close #60021
2025-02-19 21:01:32 +00:00
Miles Malerba 347c3d5761 build: remove circular deps goldens (#60021)
Removes the circular dependencies golden file and cleans up the
associated pullapprove group. All circular dependencies have been
removed and no new ones may be added.

PR Close #60021
2025-02-19 21:01:32 +00:00
Miles Malerba 8449c071da build: update to latest @angular/ng-dev version (#60021)
Update to the latest version to gain circular deps updates.

PR Close #60021
2025-02-19 21:01:32 +00:00
Andrew Scott f88ed8e470 refactor(core): Add fake navigation to primitives for code sharing (#59857)
This moves the `FakeNavigation` implementation to the primitives folder
so its implementation can be shared with Wiz. This class was initially
copied directly from the Wiz implementation, with some small modifications.
There will still need to be some work done to align the implementations
and fix anything internally that needs adjusting.

PR Close #59857
2025-02-19 20:09:10 +00:00
Jessica Janiuk 11ea0a0f7d release: cut the v19.2.0-rc.0 release 2025-02-19 14:02:38 -05:00
1589 changed files with 65681 additions and 119529 deletions
+10 -1
View File
@@ -113,13 +113,22 @@ build:remote --remote_instance_name=projects/internal-200822/instances/primary_i
build:remote --bes_instance_name=internal-200822
build:remote --remote_cache=remotebuildexecution.googleapis.com
build:remote --remote_executor=remotebuildexecution.googleapis.com
build:remote --remote_upload_local_results=false
build:remote --experimental_remote_grpc_log=/tmp/rbe-grpc.log
# See: https://docs.google.com/document/d/1NgDPsCIwprDdqC1zj0qQrh5KGK2hQTSTux1DAvi4rSc/edit?tab=t.0.
build:remote --experimental_remote_execution_keepalive
# Use HTTP remote cache
build:remote-cache --remote_cache=https://storage.googleapis.com/angular-team-cache
build:remote-cache --remote_accept_cached=true
build:remote-cache --remote_upload_local_results=true
build:remote-cache --remote_upload_local_results=false
build:remote-cache --google_default_credentials
# Additional flags added when running a "trusted build" with additional access
build:trusted-build --remote_upload_local_results=true
# Ensure that tags like "no-remote-exec" get propagated to actions created by rules,
# even if the rule implementation does not explicitly pass them to the execution requirements.
# https://bazel.build/reference/command-line-reference#flag--experimental_allow_tags_propagation
+40
View File
@@ -0,0 +1,40 @@
# all commits that change formatting to prettier
fd544159e300340a25a48e3f40c58795991a4c17
31fdf0fbea6b89c8d3d141b2ef8e79c2737287cb
0d78a92431178be73342aeddda4b62d9e49138ba
f307e95459898b9027d5e13357a809d8952e9017
b1dffa4abe8321a47d79b2ea29ee32a81acfe031
ca517d7f2c38775969a65fde1d88f41ad5f27931
8f69c83b848ad0dc3c7ffce2541fc726693dedcf
a5b5b7d5ef84b9852d2115dd7a764f4ab3299379
894c1c5f100a62866cc7ed3e23d025c8e505c60d
ca39926de2ccaceb11de47a35e5bf9899147a877
b857aafcb9bdb5f1400a4cfedd56657e71ebe8cd
c4b880a025823efadb9d76195c6261f2992c7654
4c2b0d94e22f022969b86b95af516b76322840e0
0460a9dfafe3a7ebbff1b87e52048fb7416bba43
ec03e462f3d4ec90d1267474cc344563c949c2cf
bbbe477f479f20722f0fea7ccc46095aad5d4253
cc34e5fb072e7903e01463953a19d18503a39347
f9781f9804f1e7c84df356d9aeb267730a7fc499
dc62446ef7f2898a20d3be1196ecaf2a92a1077d
711cb416260ca11ff158fc39b372efa2cf022d36
# commits that switch to relative imports
854a66d8eee2f0d0c1f4bafe976d191281004e4b
d6d3a87c724a2b309870b04f1e8157c042642cc1
7a65b06665425411094d8e1d64203d22b999255c
1b576ee5f5be665a3663abd5df741f1ae90107f8
650c179371973f9cfbf433b67f5fbf2722c55cf4
c9562ac2cc28bbc4f78cd705c9437cb0a8057066
ee46567475c2a485ac9abd07633f484a879379cf
c64956c411a993fcac7c8daa57ab027a56d75ff3
c2ef28062a9ae51e9143e5e2cb1ee75473f92696
f4b59770e188071eb8a30eb077ba62c6ff550916
8e7a6a32facc5ea6f375af01787bc13e468654b3
96b4f8abde9c25fad713144a67617036e11dd977
0b7fc584d4456944097ae1c94e7875492c21605a
f94f3a6acf7050651842806db2440ca549309ba2
9eaeffd3982923d1feea8ba7fbe44821dfff18e2
1fa95e5c2e85825e77630ed15fbefbbe29cef6a3
d725c6ed0f4b98b70fac702312b51b5c9cc412b6
f8ca1d57af81b19c21b441c842c50a3c63da18e5
+1 -1
View File
@@ -1,7 +1,7 @@
## PR Checklist
Please check if your PR fulfills the following requirements:
- [ ] The commit message follows our guidelines: https://github.com/angular/angular/blob/main/CONTRIBUTING.md#commit
- [ ] The commit message follows our guidelines: https://github.com/angular/angular/blob/main/contributing-docs/commit-message-guidelines.md
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been added / updated (for bug fixes / features)
+306 -45
View File
@@ -3754,7 +3754,7 @@ var require_dist_node4 = __commonJS({
if (options.request.headers.authorization) {
requestCopy.headers = Object.assign({}, options.request.headers, {
authorization: options.request.headers.authorization.replace(
/ .*$/,
/(?<! ) .*$/,
" [REDACTED]"
)
});
@@ -3814,7 +3814,7 @@ var require_dist_node5 = __commonJS({
module.exports = __toCommonJS(dist_src_exports);
var import_endpoint3 = require_dist_node2();
var import_universal_user_agent7 = require_dist_node();
var VERSION11 = "8.4.0";
var VERSION11 = "8.4.1";
function isPlainObject5(value) {
if (typeof value !== "object" || value === null)
return false;
@@ -3863,7 +3863,7 @@ var require_dist_node5 = __commonJS({
headers[keyAndValue[0]] = keyAndValue[1];
}
if ("deprecation" in headers) {
const matches = headers.link && headers.link.match(/<([^>]+)>; rel="deprecation"/);
const matches = headers.link && headers.link.match(/<([^<>]+)>; rel="deprecation"/);
const deprecationLink = matches && matches.pop();
log.warn(
`[@octokit/request] "${requestOptions.method} ${requestOptions.url}" is deprecated. It is scheduled to be removed on ${headers.sunset}${deprecationLink ? `. See ${deprecationLink}` : ""}`
@@ -4015,16 +4015,16 @@ var require_dist_node6 = __commonJS({
return to;
};
var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
var dist_src_exports = {};
__export(dist_src_exports, {
var index_exports = {};
__export(index_exports, {
GraphqlResponseError: () => GraphqlResponseError2,
graphql: () => graphql22,
withCustomRequest: () => withCustomRequest2
});
module.exports = __toCommonJS(dist_src_exports);
module.exports = __toCommonJS(index_exports);
var import_request3 = require_dist_node5();
var import_universal_user_agent7 = require_dist_node();
var VERSION11 = "7.1.0";
var VERSION11 = "7.1.1";
var import_request22 = require_dist_node5();
var import_request4 = require_dist_node5();
function _buildMessageForResponseErrors2(data) {
@@ -4224,17 +4224,17 @@ var require_dist_node8 = __commonJS({
return to;
};
var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
var dist_src_exports = {};
__export(dist_src_exports, {
var index_exports = {};
__export(index_exports, {
Octokit: () => Octokit3
});
module.exports = __toCommonJS(dist_src_exports);
module.exports = __toCommonJS(index_exports);
var import_universal_user_agent7 = require_dist_node();
var import_before_after_hook2 = require_before_after_hook();
var import_request3 = require_dist_node5();
var import_graphql2 = require_dist_node6();
var import_auth_token2 = require_dist_node7();
var VERSION11 = "5.2.0";
var VERSION11 = "5.2.1";
var noop2 = () => {
};
var consoleWarn2 = console.warn.bind(console);
@@ -6533,7 +6533,7 @@ var require_dist_node10 = __commonJS({
paginatingEndpoints: () => paginatingEndpoints
});
module.exports = __toCommonJS(dist_src_exports);
var VERSION11 = "9.2.1";
var VERSION11 = "9.2.2";
function normalizePaginatedListResponse2(response) {
if (!response.data) {
return {
@@ -6577,7 +6577,7 @@ var require_dist_node10 = __commonJS({
const response = await requestMethod({ method, url, headers });
const normalizedResponse = normalizePaginatedListResponse2(response);
url = ((normalizedResponse.headers.link || "").match(
/<([^>]+)>;\s*rel="next"/
/<([^<>]+)>;\s*rel="next"/
) || [])[1];
return { value: normalizedResponse };
} catch (error) {
@@ -27620,7 +27620,7 @@ function paginateRest(octokit) {
paginateRest.VERSION = VERSION8;
//
var VERSION9 = "13.3.1";
var VERSION9 = "13.5.0";
//
var Endpoints = {
@@ -27649,6 +27649,7 @@ var Endpoints = {
createEnvironmentVariable: [
"POST /repos/{owner}/{repo}/environments/{environment_name}/variables"
],
createHostedRunnerForOrg: ["POST /orgs/{org}/actions/hosted-runners"],
createOrUpdateEnvironmentSecret: [
"PUT /repos/{owner}/{repo}/environments/{environment_name}/secrets/{secret_name}"
],
@@ -27686,6 +27687,9 @@ var Endpoints = {
deleteEnvironmentVariable: [
"DELETE /repos/{owner}/{repo}/environments/{environment_name}/variables/{name}"
],
deleteHostedRunnerForOrg: [
"DELETE /orgs/{org}/actions/hosted-runners/{hosted_runner_id}"
],
deleteOrgSecret: ["DELETE /orgs/{org}/actions/secrets/{secret_name}"],
deleteOrgVariable: ["DELETE /orgs/{org}/actions/variables/{name}"],
deleteRepoSecret: [
@@ -27774,6 +27778,24 @@ var Endpoints = {
getGithubActionsPermissionsRepository: [
"GET /repos/{owner}/{repo}/actions/permissions"
],
getHostedRunnerForOrg: [
"GET /orgs/{org}/actions/hosted-runners/{hosted_runner_id}"
],
getHostedRunnersGithubOwnedImagesForOrg: [
"GET /orgs/{org}/actions/hosted-runners/images/github-owned"
],
getHostedRunnersLimitsForOrg: [
"GET /orgs/{org}/actions/hosted-runners/limits"
],
getHostedRunnersMachineSpecsForOrg: [
"GET /orgs/{org}/actions/hosted-runners/machine-sizes"
],
getHostedRunnersPartnerImagesForOrg: [
"GET /orgs/{org}/actions/hosted-runners/images/partner"
],
getHostedRunnersPlatformsForOrg: [
"GET /orgs/{org}/actions/hosted-runners/platforms"
],
getJobForWorkflowRun: ["GET /repos/{owner}/{repo}/actions/jobs/{job_id}"],
getOrgPublicKey: ["GET /orgs/{org}/actions/secrets/public-key"],
getOrgSecret: ["GET /orgs/{org}/actions/secrets/{secret_name}"],
@@ -27817,6 +27839,10 @@ var Endpoints = {
listEnvironmentVariables: [
"GET /repos/{owner}/{repo}/environments/{environment_name}/variables"
],
listGithubHostedRunnersInGroupForOrg: [
"GET /orgs/{org}/actions/runner-groups/{runner_group_id}/hosted-runners"
],
listHostedRunnersForOrg: ["GET /orgs/{org}/actions/hosted-runners"],
listJobsForWorkflowRun: [
"GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs"
],
@@ -27935,6 +27961,9 @@ var Endpoints = {
updateEnvironmentVariable: [
"PATCH /repos/{owner}/{repo}/environments/{environment_name}/variables/{name}"
],
updateHostedRunnerForOrg: [
"PATCH /orgs/{org}/actions/hosted-runners/{hosted_runner_id}"
],
updateOrgVariable: ["PATCH /orgs/{org}/actions/variables/{name}"],
updateRepoVariable: [
"PATCH /repos/{owner}/{repo}/actions/variables/{name}"
@@ -28452,6 +28481,26 @@ var Endpoints = {
getAllTemplates: ["GET /gitignore/templates"],
getTemplate: ["GET /gitignore/templates/{name}"]
},
hostedCompute: {
createNetworkConfigurationForOrg: [
"POST /orgs/{org}/settings/network-configurations"
],
deleteNetworkConfigurationFromOrg: [
"DELETE /orgs/{org}/settings/network-configurations/{network_configuration_id}"
],
getNetworkConfigurationForOrg: [
"GET /orgs/{org}/settings/network-configurations/{network_configuration_id}"
],
getNetworkSettingsForOrg: [
"GET /orgs/{org}/settings/network-settings/{network_settings_id}"
],
listNetworkConfigurationsForOrg: [
"GET /orgs/{org}/settings/network-configurations"
],
updateNetworkConfigurationForOrg: [
"PATCH /orgs/{org}/settings/network-configurations/{network_configuration_id}"
]
},
interactions: {
getRestrictionsForAuthenticatedUser: ["GET /user/interaction-limits"],
getRestrictionsForOrg: ["GET /orgs/{org}/interaction-limits"],
@@ -28643,6 +28692,7 @@ var Endpoints = {
"PUT /orgs/{org}/outside_collaborators/{username}"
],
createInvitation: ["POST /orgs/{org}/invitations"],
createIssueType: ["POST /orgs/{org}/issue-types"],
createOrUpdateCustomProperties: ["PATCH /orgs/{org}/properties/schema"],
createOrUpdateCustomPropertiesValuesForRepos: [
"PATCH /orgs/{org}/properties/values"
@@ -28652,6 +28702,7 @@ var Endpoints = {
],
createWebhook: ["POST /orgs/{org}/hooks"],
delete: ["DELETE /orgs/{org}"],
deleteIssueType: ["DELETE /orgs/{org}/issue-types/{issue_type_id}"],
deleteWebhook: ["DELETE /orgs/{org}/hooks/{hook_id}"],
enableOrDisableSecurityProductOnAllOrgRepos: [
"POST /orgs/{org}/{security_product}/{enablement}",
@@ -28668,6 +28719,10 @@ var Endpoints = {
getMembershipForAuthenticatedUser: ["GET /user/memberships/orgs/{org}"],
getMembershipForUser: ["GET /orgs/{org}/memberships/{username}"],
getOrgRole: ["GET /orgs/{org}/organization-roles/{role_id}"],
getOrgRulesetHistory: ["GET /orgs/{org}/rulesets/{ruleset_id}/history"],
getOrgRulesetVersion: [
"GET /orgs/{org}/rulesets/{ruleset_id}/history/{version_id}"
],
getWebhook: ["GET /orgs/{org}/hooks/{hook_id}"],
getWebhookConfigForOrg: ["GET /orgs/{org}/hooks/{hook_id}/config"],
getWebhookDelivery: [
@@ -28682,6 +28737,7 @@ var Endpoints = {
listForAuthenticatedUser: ["GET /user/orgs"],
listForUser: ["GET /users/{username}/orgs"],
listInvitationTeams: ["GET /orgs/{org}/invitations/{invitation_id}/teams"],
listIssueTypes: ["GET /orgs/{org}/issue-types"],
listMembers: ["GET /orgs/{org}/members"],
listMembershipsForAuthenticatedUser: ["GET /user/memberships/orgs"],
listOrgRoleTeams: ["GET /orgs/{org}/organization-roles/{role_id}/teams"],
@@ -28756,6 +28812,7 @@ var Endpoints = {
],
unblockUser: ["DELETE /orgs/{org}/blocks/{username}"],
update: ["PATCH /orgs/{org}"],
updateIssueType: ["PUT /orgs/{org}/issue-types/{issue_type_id}"],
updateMembershipForAuthenticatedUser: [
"PATCH /user/memberships/orgs/{org}"
],
@@ -28869,35 +28926,181 @@ var Endpoints = {
]
},
projects: {
addCollaborator: ["PUT /projects/{project_id}/collaborators/{username}"],
createCard: ["POST /projects/columns/{column_id}/cards"],
createColumn: ["POST /projects/{project_id}/columns"],
createForAuthenticatedUser: ["POST /user/projects"],
createForOrg: ["POST /orgs/{org}/projects"],
createForRepo: ["POST /repos/{owner}/{repo}/projects"],
delete: ["DELETE /projects/{project_id}"],
deleteCard: ["DELETE /projects/columns/cards/{card_id}"],
deleteColumn: ["DELETE /projects/columns/{column_id}"],
get: ["GET /projects/{project_id}"],
getCard: ["GET /projects/columns/cards/{card_id}"],
getColumn: ["GET /projects/columns/{column_id}"],
addCollaborator: [
"PUT /projects/{project_id}/collaborators/{username}",
{},
{
deprecated: "octokit.rest.projects.addCollaborator() is deprecated, see https://docs.github.com/rest/projects/collaborators#add-project-collaborator"
}
],
createCard: [
"POST /projects/columns/{column_id}/cards",
{},
{
deprecated: "octokit.rest.projects.createCard() is deprecated, see https://docs.github.com/rest/projects/cards#create-a-project-card"
}
],
createColumn: [
"POST /projects/{project_id}/columns",
{},
{
deprecated: "octokit.rest.projects.createColumn() is deprecated, see https://docs.github.com/rest/projects/columns#create-a-project-column"
}
],
createForAuthenticatedUser: [
"POST /user/projects",
{},
{
deprecated: "octokit.rest.projects.createForAuthenticatedUser() is deprecated, see https://docs.github.com/rest/projects/projects#create-a-user-project"
}
],
createForOrg: [
"POST /orgs/{org}/projects",
{},
{
deprecated: "octokit.rest.projects.createForOrg() is deprecated, see https://docs.github.com/rest/projects/projects#create-an-organization-project"
}
],
createForRepo: [
"POST /repos/{owner}/{repo}/projects",
{},
{
deprecated: "octokit.rest.projects.createForRepo() is deprecated, see https://docs.github.com/rest/projects/projects#create-a-repository-project"
}
],
delete: [
"DELETE /projects/{project_id}",
{},
{
deprecated: "octokit.rest.projects.delete() is deprecated, see https://docs.github.com/rest/projects/projects#delete-a-project"
}
],
deleteCard: [
"DELETE /projects/columns/cards/{card_id}",
{},
{
deprecated: "octokit.rest.projects.deleteCard() is deprecated, see https://docs.github.com/rest/projects/cards#delete-a-project-card"
}
],
deleteColumn: [
"DELETE /projects/columns/{column_id}",
{},
{
deprecated: "octokit.rest.projects.deleteColumn() is deprecated, see https://docs.github.com/rest/projects/columns#delete-a-project-column"
}
],
get: [
"GET /projects/{project_id}",
{},
{
deprecated: "octokit.rest.projects.get() is deprecated, see https://docs.github.com/rest/projects/projects#get-a-project"
}
],
getCard: [
"GET /projects/columns/cards/{card_id}",
{},
{
deprecated: "octokit.rest.projects.getCard() is deprecated, see https://docs.github.com/rest/projects/cards#get-a-project-card"
}
],
getColumn: [
"GET /projects/columns/{column_id}",
{},
{
deprecated: "octokit.rest.projects.getColumn() is deprecated, see https://docs.github.com/rest/projects/columns#get-a-project-column"
}
],
getPermissionForUser: [
"GET /projects/{project_id}/collaborators/{username}/permission"
"GET /projects/{project_id}/collaborators/{username}/permission",
{},
{
deprecated: "octokit.rest.projects.getPermissionForUser() is deprecated, see https://docs.github.com/rest/projects/collaborators#get-project-permission-for-a-user"
}
],
listCards: [
"GET /projects/columns/{column_id}/cards",
{},
{
deprecated: "octokit.rest.projects.listCards() is deprecated, see https://docs.github.com/rest/projects/cards#list-project-cards"
}
],
listCollaborators: [
"GET /projects/{project_id}/collaborators",
{},
{
deprecated: "octokit.rest.projects.listCollaborators() is deprecated, see https://docs.github.com/rest/projects/collaborators#list-project-collaborators"
}
],
listColumns: [
"GET /projects/{project_id}/columns",
{},
{
deprecated: "octokit.rest.projects.listColumns() is deprecated, see https://docs.github.com/rest/projects/columns#list-project-columns"
}
],
listForOrg: [
"GET /orgs/{org}/projects",
{},
{
deprecated: "octokit.rest.projects.listForOrg() is deprecated, see https://docs.github.com/rest/projects/projects#list-organization-projects"
}
],
listForRepo: [
"GET /repos/{owner}/{repo}/projects",
{},
{
deprecated: "octokit.rest.projects.listForRepo() is deprecated, see https://docs.github.com/rest/projects/projects#list-repository-projects"
}
],
listForUser: [
"GET /users/{username}/projects",
{},
{
deprecated: "octokit.rest.projects.listForUser() is deprecated, see https://docs.github.com/rest/projects/projects#list-user-projects"
}
],
moveCard: [
"POST /projects/columns/cards/{card_id}/moves",
{},
{
deprecated: "octokit.rest.projects.moveCard() is deprecated, see https://docs.github.com/rest/projects/cards#move-a-project-card"
}
],
moveColumn: [
"POST /projects/columns/{column_id}/moves",
{},
{
deprecated: "octokit.rest.projects.moveColumn() is deprecated, see https://docs.github.com/rest/projects/columns#move-a-project-column"
}
],
listCards: ["GET /projects/columns/{column_id}/cards"],
listCollaborators: ["GET /projects/{project_id}/collaborators"],
listColumns: ["GET /projects/{project_id}/columns"],
listForOrg: ["GET /orgs/{org}/projects"],
listForRepo: ["GET /repos/{owner}/{repo}/projects"],
listForUser: ["GET /users/{username}/projects"],
moveCard: ["POST /projects/columns/cards/{card_id}/moves"],
moveColumn: ["POST /projects/columns/{column_id}/moves"],
removeCollaborator: [
"DELETE /projects/{project_id}/collaborators/{username}"
"DELETE /projects/{project_id}/collaborators/{username}",
{},
{
deprecated: "octokit.rest.projects.removeCollaborator() is deprecated, see https://docs.github.com/rest/projects/collaborators#remove-user-as-a-collaborator"
}
],
update: ["PATCH /projects/{project_id}"],
updateCard: ["PATCH /projects/columns/cards/{card_id}"],
updateColumn: ["PATCH /projects/columns/{column_id}"]
update: [
"PATCH /projects/{project_id}",
{},
{
deprecated: "octokit.rest.projects.update() is deprecated, see https://docs.github.com/rest/projects/projects#update-a-project"
}
],
updateCard: [
"PATCH /projects/columns/cards/{card_id}",
{},
{
deprecated: "octokit.rest.projects.updateCard() is deprecated, see https://docs.github.com/rest/projects/cards#update-an-existing-project-card"
}
],
updateColumn: [
"PATCH /projects/columns/{column_id}",
{},
{
deprecated: "octokit.rest.projects.updateColumn() is deprecated, see https://docs.github.com/rest/projects/columns#update-an-existing-project-column"
}
]
},
pulls: {
checkIfMerged: ["GET /repos/{owner}/{repo}/pulls/{pull_number}/merge"],
@@ -29270,6 +29473,12 @@ var Endpoints = {
],
getRepoRuleSuites: ["GET /repos/{owner}/{repo}/rulesets/rule-suites"],
getRepoRuleset: ["GET /repos/{owner}/{repo}/rulesets/{ruleset_id}"],
getRepoRulesetHistory: [
"GET /repos/{owner}/{repo}/rulesets/{ruleset_id}/history"
],
getRepoRulesetVersion: [
"GET /repos/{owner}/{repo}/rulesets/{ruleset_id}/history/{version_id}"
],
getRepoRulesets: ["GET /repos/{owner}/{repo}/rulesets"],
getStatusChecksProtection: [
"GET /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks"
@@ -29443,7 +29652,13 @@ var Endpoints = {
search: {
code: ["GET /search/code"],
commits: ["GET /search/commits"],
issuesAndPullRequests: ["GET /search/issues"],
issuesAndPullRequests: [
"GET /search/issues",
{},
{
deprecated: "octokit.rest.search.issuesAndPullRequests() is deprecated, see https://docs.github.com/rest/search/search#search-issues-and-pull-requests"
}
],
labels: ["GET /search/labels"],
repos: ["GET /search/repositories"],
topics: ["GET /search/topics"],
@@ -29498,13 +29713,35 @@ var Endpoints = {
"PUT /orgs/{org}/teams/{team_slug}/memberships/{username}"
],
addOrUpdateProjectPermissionsInOrg: [
"PUT /orgs/{org}/teams/{team_slug}/projects/{project_id}"
"PUT /orgs/{org}/teams/{team_slug}/projects/{project_id}",
{},
{
deprecated: "octokit.rest.teams.addOrUpdateProjectPermissionsInOrg() is deprecated, see https://docs.github.com/rest/teams/teams#add-or-update-team-project-permissions"
}
],
addOrUpdateProjectPermissionsLegacy: [
"PUT /teams/{team_id}/projects/{project_id}",
{},
{
deprecated: "octokit.rest.teams.addOrUpdateProjectPermissionsLegacy() is deprecated, see https://docs.github.com/rest/teams/teams#add-or-update-team-project-permissions-legacy"
}
],
addOrUpdateRepoPermissionsInOrg: [
"PUT /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}"
],
checkPermissionsForProjectInOrg: [
"GET /orgs/{org}/teams/{team_slug}/projects/{project_id}"
"GET /orgs/{org}/teams/{team_slug}/projects/{project_id}",
{},
{
deprecated: "octokit.rest.teams.checkPermissionsForProjectInOrg() is deprecated, see https://docs.github.com/rest/teams/teams#check-team-permissions-for-a-project"
}
],
checkPermissionsForProjectLegacy: [
"GET /teams/{team_id}/projects/{project_id}",
{},
{
deprecated: "octokit.rest.teams.checkPermissionsForProjectLegacy() is deprecated, see https://docs.github.com/rest/teams/teams#check-team-permissions-for-a-project-legacy"
}
],
checkPermissionsForRepoInOrg: [
"GET /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}"
@@ -29542,13 +29779,37 @@ var Endpoints = {
listPendingInvitationsInOrg: [
"GET /orgs/{org}/teams/{team_slug}/invitations"
],
listProjectsInOrg: ["GET /orgs/{org}/teams/{team_slug}/projects"],
listProjectsInOrg: [
"GET /orgs/{org}/teams/{team_slug}/projects",
{},
{
deprecated: "octokit.rest.teams.listProjectsInOrg() is deprecated, see https://docs.github.com/rest/teams/teams#list-team-projects"
}
],
listProjectsLegacy: [
"GET /teams/{team_id}/projects",
{},
{
deprecated: "octokit.rest.teams.listProjectsLegacy() is deprecated, see https://docs.github.com/rest/teams/teams#list-team-projects-legacy"
}
],
listReposInOrg: ["GET /orgs/{org}/teams/{team_slug}/repos"],
removeMembershipForUserInOrg: [
"DELETE /orgs/{org}/teams/{team_slug}/memberships/{username}"
],
removeProjectInOrg: [
"DELETE /orgs/{org}/teams/{team_slug}/projects/{project_id}"
"DELETE /orgs/{org}/teams/{team_slug}/projects/{project_id}",
{},
{
deprecated: "octokit.rest.teams.removeProjectInOrg() is deprecated, see https://docs.github.com/rest/teams/teams#remove-a-project-from-a-team"
}
],
removeProjectLegacy: [
"DELETE /teams/{team_id}/projects/{project_id}",
{},
{
deprecated: "octokit.rest.teams.removeProjectLegacy() is deprecated, see https://docs.github.com/rest/teams/teams#remove-a-project-from-a-team-legacy"
}
],
removeRepoInOrg: [
"DELETE /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}"
@@ -29830,7 +30091,7 @@ function legacyRestEndpointMethods(octokit) {
legacyRestEndpointMethods.VERSION = VERSION9;
//
var VERSION10 = "21.1.0";
var VERSION10 = "21.1.1";
//
var Octokit2 = Octokit.plugin(requestLog, legacyRestEndpointMethods, paginateRest).defaults(
+2 -2
View File
@@ -5,9 +5,9 @@ runs:
using: 'composite'
steps:
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/setup@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Saucelabs Variables
uses: angular/dev-infra/github-actions/saucelabs@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/saucelabs@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Starting Saucelabs tunnel service
shell: bash
run: ./tools/saucelabs/sauce-service.sh run &
+1 -1
View File
@@ -4,7 +4,7 @@ description: 'Installs the dependencies using Yarn'
runs:
using: 'composite'
steps:
- uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4
- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4
with:
path: |
./node_modules/
+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@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/setup@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/configure-remote@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Build adev to ensure it continues to work
run: yarn bazel build //adev:build --full_build_adev --config=release
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@002a34e9875f55bf1850fb57d34261b33b2fd492
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
workflow-artifact-name: 'adev-preview'
pull-number: '${{github.event.pull_request.number}}'
+1 -1
View File
@@ -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@002a34e9875f55bf1850fb57d34261b33b2fd492
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
github-token: '${{secrets.GITHUB_TOKEN}}'
workflow-artifact-name: 'adev-preview'
@@ -16,6 +16,6 @@ jobs:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- uses: angular/dev-infra/github-actions/branch-manager@002a34e9875f55bf1850fb57d34261b33b2fd492
- uses: angular/dev-infra/github-actions/branch-manager@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
+1 -1
View File
@@ -38,7 +38,7 @@ jobs:
- uses: ./.github/actions/yarn-install
- uses: angular/dev-infra/github-actions/bazel/configure-remote@002a34e9875f55bf1850fb57d34261b33b2fd492
- uses: angular/dev-infra/github-actions/bazel/configure-remote@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
bazelrc: ./.bazelrc.user
+48 -20
View File
@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
cache-node-modules: true
- name: Install node modules
@@ -41,13 +41,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/setup@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/configure-remote@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Run unit tests
@@ -59,28 +61,50 @@ jobs:
runs-on: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/setup@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/configure-remote@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
run: yarn install --frozen-lockfile --network-timeout 100000
- name: Run CI tests for framework
run: yarn test:ci
integration-tests:
runs-on: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
run: yarn install --frozen-lockfile --network-timeout 100000
- name: Run integration CI tests for framework
run: yarn integration-tests:ci
adev:
runs-on:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/setup@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/configure-remote@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Build adev in fast mode to ensure it continues to work
@@ -95,13 +119,15 @@ jobs:
labels: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/setup@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/configure-remote@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
run: yarn install --frozen-lockfile
- run: echo "https://${{secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN}}:@github.com" > ${HOME}/.git_credentials
@@ -113,7 +139,7 @@ jobs:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
cache-node-modules: true
node-module-directories: |
@@ -121,9 +147,11 @@ jobs:
./packages/zone.js/node_modules
./packages/zone.js/test/typings/node_modules
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/setup@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/configure-remote@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
run: yarn install --frozen-lockfile
- run: |
@@ -160,7 +188,7 @@ jobs:
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
cache-node-modules: true
- name: Install node modules
@@ -173,11 +201,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/setup@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/configure-remote@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Build adev to ensure it continues to work
+2 -2
View File
@@ -13,13 +13,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: angular/dev-infra/github-actions/commit-message-based-labels@002a34e9875f55bf1850fb57d34261b33b2fd492
- uses: angular/dev-infra/github-actions/commit-message-based-labels@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
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@002a34e9875f55bf1850fb57d34261b33b2fd492
- uses: angular/dev-infra/github-actions/post-approval-changes@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: angular/dev-infra/github-actions/google-internal-tests@002a34e9875f55bf1850fb57d34261b33b2fd492
- uses: angular/dev-infra/github-actions/google-internal-tests@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
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@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
cache-node-modules: true
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/setup@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/configure-remote@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Saucelabs Variables
uses: angular/dev-infra/github-actions/saucelabs@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/saucelabs@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Set up Sauce Tunnel Daemon
run: yarn 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@002a34e9875f55bf1850fb57d34261b33b2fd492
- uses: angular/dev-infra/github-actions/unified-status-check@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
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@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Install node modules
run: yarn -s 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@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/setup@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Install node modules
run: yarn -s install --frozen-lockfile
# We utilize the google-github-actions/auth action to allow us to get an active credential using workflow
+41 -19
View File
@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
cache-node-modules: true
- name: Install node modules
@@ -39,7 +39,7 @@ jobs:
- name: Check code format
run: yarn ng-dev format changed --check ${{ github.event.pull_request.base.sha }}
- name: Check Package Licenses
uses: angular/dev-infra/github-actions/linting/licenses@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/linting/licenses@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
allow-dependencies-licenses: 'pkg:npm/google-protobuf@'
@@ -47,13 +47,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/setup@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/configure-remote@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Run unit tests
@@ -65,17 +65,39 @@ jobs:
runs-on: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/setup@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/configure-remote@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Install node modules
run: yarn install --frozen-lockfile --network-timeout 100000
- name: Run CI tests for framework
run: yarn test:ci
- name: Upload GRPC logs (for debugging of RBE issues)
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
path: /tmp/rbe-grpc.log
retention-days: 1
integration-tests:
runs-on: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Install node modules
run: yarn install --frozen-lockfile --network-timeout 100000
- name: Run integration CI tests for framework
run: yarn integration-tests:ci
artifacts:
needs: [test]
@@ -83,19 +105,19 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/setup@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/configure-remote@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Install node modules
run: yarn install --frozen-lockfile --network-timeout 100000
- name: Run CI tests for framework
run: yarn tsx ./scripts/build/build-packages-dist.mts
- name: Archive build artifacts
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
with:
name: pr-artifacts-${{ github.event.number }}
path: dist/packages-dist/
@@ -105,11 +127,11 @@ jobs:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/setup@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/configure-remote@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Build adev in fast mode to ensure it continues to work
@@ -124,7 +146,7 @@ jobs:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
cache-node-modules: true
node-module-directories: |
@@ -132,9 +154,9 @@ jobs:
./packages/zone.js/node_modules
./packages/zone.js/test/typings/node_modules
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/setup@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/bazel/configure-remote@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
- name: Install node modules
run: yarn install --frozen-lockfile
- run: |
@@ -171,7 +193,7 @@ jobs:
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
cache-node-modules: true
- name: Install node modules
+3 -3
View File
@@ -30,7 +30,7 @@ jobs:
persist-credentials: false
- name: 'Run analysis'
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
with:
results_file: results.sarif
results_format: sarif
@@ -39,7 +39,7 @@ jobs:
# Upload the results as artifacts.
- name: 'Upload artifact'
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: SARIF file
path: results.sarif
@@ -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@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9
uses: github/codeql-action/upload-sarif@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15
with:
sarif_file: results.sarif
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
env:
ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN: ${{ secrets.ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN }}
- name: Create a PR (if necessary)
uses: angular/dev-infra/github-actions/create-pr-for-changes@002a34e9875f55bf1850fb57d34261b33b2fd492
uses: angular/dev-infra/github-actions/create-pr-for-changes@b3b3466509babc50fd7f00b90e8bc607e7fe41aa
with:
branch-prefix: update-cli-help
pr-title: 'docs: update Angular CLI help [${{github.ref_name}}]'
+1 -1
View File
@@ -74,7 +74,7 @@ Fixes #<issue number>
# =============================
#
# The full specification of the Angular Commit Message Format can be found at
# https://github.com/angular/angular/blob/main/CONTRIBUTING.md#commit
# https://github.com/angular/angular/blob/main/contributing-docs/commit-message-guidelines.md
#
# The following is an excerpt of the specification with the most commonly needed info.
#
+2
View File
@@ -7,6 +7,8 @@ export const commitMessage: CommitMessageConfig = {
maxLineLength: Infinity,
minBodyLength: 20,
minBodyLengthTypeExcludes: ['docs'],
// If you update this, also update the docs.
// https://github.com/angular/angular/blob/main/contributing-docs/commit-message-guidelines.md#scope
scopes: [
'animations',
'bazel',
+3 -29
View File
@@ -144,7 +144,6 @@ groups:
- >
contains_any_globs(files.exclude('packages/core/primitives/*'), [
'contributing-docs/public-api-surface.md',
'goldens/circular-deps/packages.json',
'integration/**/{*,.*}',
'modules/**/{*,.*}',
'packages/animations/**/{*,.*}',
@@ -288,6 +287,7 @@ groups:
- MarkTechson
- kirjs
- mmalerba
- ~hawkgs
# =========================================================
# Angular DevTools
@@ -395,6 +395,8 @@ groups:
- pkozlowski-opensource
- kirjs
- mmalerba
- crisbeto
- devversion
- ~iteriani
- ~tbondwilkinson
- ~rahatarmanahmed
@@ -430,28 +432,6 @@ groups:
required: 1 # Require that 1 person approve
reviewed_for: required
# ================================================
# Circular dependencies
# ================================================
circular-dependencies:
<<: *defaults
conditions:
- *no-groups-above-this-pending
- *no-groups-above-this-rejected
- >
contains_any_globs(files, [
'goldens/circular-deps/packages.json'
])
reviewers:
users:
- alxhub
- AndrewKushnir
- atscott
- ~jelbourn
- thePunderWoman
- pkozlowski-opensource
- kirjs
####################################################################################
# Special Cases
####################################################################################
@@ -511,13 +491,7 @@ groups:
reviewers:
users:
- csmick # Cameron Smick
- lannka # Hongfei Ding
- eduhmc # Eduardo Huerta-Mercado
- ehlemur # Edward Lesmes
- ellenyuan # Ellen Yuan
- jesse-good # Jesse Costello-Good
- mturco # Matt Turco
- neonstalwart # Ben Hockey
- iteriani # Thomas Nguyen
- tbondwilkinson # Tom Wilkinson
- rahatarmanahmed # Rahat Ahmed
+8 -5
View File
@@ -1,9 +1,9 @@
{
"[javascript]": {
"editor.formatOnSave": true,
"editor.formatOnSave": true
},
"[typescript]": {
"editor.formatOnSave": true,
"editor.formatOnSave": true
},
// Exclude third party modules and build artifacts from the editor watchers/searches.
"files.watcherExclude": {
@@ -11,14 +11,17 @@
"**/.git/subtree-cache/**": true,
"**/node_modules/**": true,
"**/bazel-out/**": true,
"**/dist/**": true,
"**/dist/**": true
},
"search.exclude": {
"**/node_modules": true,
"**/bower_components": true,
"**/bazel-out": true,
"**/dist": true,
".history": true,
".history": true
},
"git.ignoreLimitWarning": true,
}
"gitlens.advanced.blame.customArguments": [
"--ignore-revs-file .git-blame-ignore-revs"
]
}
+235 -101
View File
@@ -1,3 +1,238 @@
<a name="19.2.8"></a>
# 19.2.8 (2025-04-23)
### forms
| Commit | Type | Description |
| -- | -- | -- |
| [ea4a211216](https://github.com/angular/angular/commit/ea4a21121681c78652f314c78c58390dca25f266) | fix | make NgForm emit FormSubmittedEvent and FormResetEvent ([#60887](https://github.com/angular/angular/pull/60887)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="19.2.7"></a>
# 19.2.7 (2025-04-16)
### common
| Commit | Type | Description |
| -- | -- | -- |
| [37ab6814f5](https://github.com/angular/angular/commit/37ab6814f5485434d9642b9f9c28dd430864247b) | fix | issue a warning instead of an error when `NgOptimizedImage` exceeds the preload limit ([#60883](https://github.com/angular/angular/pull/60883)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [b144126612](https://github.com/angular/angular/commit/b144126612e2cd14cbccc8d3cf4e2136a2e540ff) | fix | inject migration: replace param with this. ([#60713](https://github.com/angular/angular/pull/60713)) |
### http
| Commit | Type | Description |
| -- | -- | -- |
| [d39e09da41](https://github.com/angular/angular/commit/d39e09da413732385a12ed21eb468649233e26d0) | fix | Include HTTP status code and headers when HTTP requests errored in `httpResource` ([#60802](https://github.com/angular/angular/pull/60802)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="19.2.6"></a>
# 19.2.6 (2025-04-09)
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [3441f7b914](https://github.com/angular/angular/commit/3441f7b914c73ccdaacbcd935e945dc304c5962a) | fix | error if rawText isn't estimated correctly ([#60529](https://github.com/angular/angular/pull/60529)) ([#60753](https://github.com/angular/angular/pull/60753)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [fc946c5f72](https://github.com/angular/angular/commit/fc946c5f7261ee3e49fa037bc55703b9ffcfbff3) | fix | ensure HMR works with different output module type ([#60797](https://github.com/angular/angular/pull/60797)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [f2bfa3151e](https://github.com/angular/angular/commit/f2bfa3151ee7ecb335665d55741387bd67ebee9d) | fix | fix ng generate @angular/core:output-migration. Fixes angular[#58650](https://github.com/angular/angular/pull/58650) ([#60763](https://github.com/angular/angular/pull/60763)) |
| [9241615ad0](https://github.com/angular/angular/commit/9241615ad0825156f4bf31bc4308372e4789e902) | fix | reduce total memory usage of various migration schematics ([#60776](https://github.com/angular/angular/pull/60776)) |
### language-service
| Commit | Type | Description |
| -- | -- | -- |
| [0e82d42774](https://github.com/angular/angular/commit/0e82d427743c1d22e1683da11f66e33846f38663) | fix | Do not provide element completions in end tag ([#60616](https://github.com/angular/angular/pull/60616)) |
| [fcdef1019f](https://github.com/angular/angular/commit/fcdef1019fd28c7261590ba484a949c809b9ceaf) | fix | Ensure dollar signs are escaped in completions ([#60597](https://github.com/angular/angular/pull/60597)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="19.2.5"></a>
# 19.2.5 (2025-04-02)
###
| Commit | Type | Description |
| -- | -- | -- |
| [e61d06afb5](https://github.com/angular/angular/commit/e61d06afb5f68268b204bb2630930bb213620811) | fix | step 6 tutorial docs ([#60630](https://github.com/angular/angular/pull/60630)) |
### animations
| Commit | Type | Description |
| -- | -- | -- |
| [fa48f98d9f](https://github.com/angular/angular/commit/fa48f98d9f7e7b74deba65bea9bc90843b1c283b) | fix | add missing peer dependency on `@angular/common` ([#60660](https://github.com/angular/angular/pull/60660)) |
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [ca5aa4d55b](https://github.com/angular/angular/commit/ca5aa4d55b352d1ead43d78b6a74d9e3b57f8777) | fix | throw for invalid "as" expression in if block ([#60580](https://github.com/angular/angular/pull/60580)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [f4c4b10ea8](https://github.com/angular/angular/commit/f4c4b10ea8dc263c30d1051a83a72486344d81e4) | fix | Produce fatal diagnostic on duplicate decorated properties ([#60376](https://github.com/angular/angular/pull/60376)) |
| [22a0e54ac4](https://github.com/angular/angular/commit/22a0e54ac4ae7b943740dc314ff7f26ee7530ee5) | fix | support relative imports to symbols outside `rootDir` ([#60555](https://github.com/angular/angular/pull/60555)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [64da69f7b6](https://github.com/angular/angular/commit/64da69f7b68c906544b3cb76b2fc7ec42cc434a8) | fix | check ngDevMode for undefined ([#60565](https://github.com/angular/angular/pull/60565)) |
| [8f68d1bec3](https://github.com/angular/angular/commit/8f68d1bec320c8af4c28ad6c8dbeda4581e8299b) | fix | fix ng generate @angular/core:output-migration ([#60626](https://github.com/angular/angular/pull/60626)) |
| [bc79985c65](https://github.com/angular/angular/commit/bc79985c65c38dee17f5cb53f2a14768632f72dc) | fix | fix regexp for event types ([#60592](https://github.com/angular/angular/pull/60592)) |
| [006ac7f22f](https://github.com/angular/angular/commit/006ac7f22f47b110129ca603cfa34f5514d7b4dd) | fix | fixes [#592882](https://github.com/angular/angular/pull/592882) ng generate @angular/core:signal-queries-migration ([#60688](https://github.com/angular/angular/pull/60688)) |
| [da6e93f434](https://github.com/angular/angular/commit/da6e93f4341804cd16327596c30d8f9258b40d7e) | fix | preserve comments in internal inject migration ([#60588](https://github.com/angular/angular/pull/60588)) |
| [dbbddd1617](https://github.com/angular/angular/commit/dbbddd161721990f29a037f88f930b333712550e) | fix | prevent omission of deferred pipes in full compilation ([#60571](https://github.com/angular/angular/pull/60571)) |
### language-service
| Commit | Type | Description |
| -- | -- | -- |
| [0e9e0348dd](https://github.com/angular/angular/commit/0e9e0348dd972c96ecee8bb990aba8c604dc704f) | fix | Update adapter to log instead of throw errors ([#60651](https://github.com/angular/angular/pull/60651)) |
### migrations
| Commit | Type | Description |
| -- | -- | -- |
| [15f53f035b](https://github.com/angular/angular/commit/15f53f035ba64fa761db64d48dd9daa1499370e3) | fix | handle shorthand assignments in super call ([#60602](https://github.com/angular/angular/pull/60602)) |
| [4b161e6234](https://github.com/angular/angular/commit/4b161e62344a51e87f1b5c5778fd72e56fc37922) | fix | inject migration not handling super parameter referenced via this ([#60602](https://github.com/angular/angular/pull/60602)) |
### router
| Commit | Type | Description |
| -- | -- | -- |
| [958e98e4f7](https://github.com/angular/angular/commit/958e98e4f7ab8e708440f03eb68612d1802b9a71) | fix | Add missing types to transition ([#60307](https://github.com/angular/angular/pull/60307)) |
### service-worker
| Commit | Type | Description |
| -- | -- | -- |
| [7cd89ad2c6](https://github.com/angular/angular/commit/7cd89ad2c66adeb625f75d23fea32e762162d3d5) | fix | assign initializing client's app version, when a request is for worker script ([#58131](https://github.com/angular/angular/pull/58131)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="19.2.4"></a>
# 19.2.4 (2025-03-26)
### core
| Commit | Type | Description |
| -- | -- | -- |
| [081f5f5a83f](https://github.com/angular/angular/commit/081f5f5a83fef99718952519bed9fe39005d6d37) | fix | fix used templates are not deleted ([#60459](https://github.com/angular/angular/pull/60459)) |
### localize
| Commit | Type | Description |
| -- | -- | -- |
| [a2f622d82d6](https://github.com/angular/angular/commit/a2f622d82d6c0f93a5fdf34fc8e5829db04c7380) | fix | handle @angular/build:karma in ng add ([#60513](https://github.com/angular/angular/pull/60513)) |
### platform-browser
| Commit | Type | Description |
| -- | -- | -- |
| [8e8ccc79279](https://github.com/angular/angular/commit/8e8ccc792790c876cf5831f3d7a504290c665a1b) | fix | ensure `platformBrowserTesting` includes `platformBrowser` providers ([#60480](https://github.com/angular/angular/pull/60480)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="19.2.3"></a>
# 19.2.3 (2025-03-19)
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [aa8ea7a5b2](https://github.com/angular/angular/commit/aa8ea7a5b227913e3f15270dac48479481c47f9a) | fix | report more accurate diagnostic for invalid import ([#60455](https://github.com/angular/angular/pull/60455)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [13a8709b2b](https://github.com/angular/angular/commit/13a8709b2ba29ef3ab7d38bfb41cdd3d44c24c51) | fix | catch hydration marker with implicit body tag ([#60429](https://github.com/angular/angular/pull/60429)) |
| [296aded9da](https://github.com/angular/angular/commit/296aded9daaf04edd3cda623a220cbd2bf57e0f1) | fix | execute timer trigger outside zone ([#60392](https://github.com/angular/angular/pull/60392)) |
| [0615ffb4f7](https://github.com/angular/angular/commit/0615ffb4f7a41cca2a408419830411897d1826e6) | fix | include input name in error message ([#60404](https://github.com/angular/angular/pull/60404)) |
### platform-browser-dynamic
| Commit | Type | Description |
| -- | -- | -- |
| [1e06c8e8b6](https://github.com/angular/angular/commit/1e06c8e8b6473a19584ceb66945fd435ea4e6af9) | fix | ensure compiler is loaded before `@angular/common` ([#60458](https://github.com/angular/angular/pull/60458)) |
### upgrade
| Commit | Type | Description |
| -- | -- | -- |
| [9e1a1030c8](https://github.com/angular/angular/commit/9e1a1030c818e9849c00ded5f79535ea56976ea8) | fix | handle output emitters when downgrading a component ([#60369](https://github.com/angular/angular/pull/60369)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="19.2.2"></a>
# 19.2.2 (2025-03-12)
### common
| Commit | Type | Description |
| -- | -- | -- |
| [90a16a1088](https://github.com/angular/angular/commit/90a16a10888eee37d8a61cdbfad070e002a3cfdf) | fix | support equality function in httpResource ([#60026](https://github.com/angular/angular/pull/60026)) |
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [56b551d273](https://github.com/angular/angular/commit/56b551d273a0978e1f2e2ef914c1d7ae942a28a8) | fix | incorrect spans for template literals ([#60323](https://github.com/angular/angular/pull/60323)) ([#60331](https://github.com/angular/angular/pull/60331)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [23ca88522b](https://github.com/angular/angular/commit/23ca88522bbc23e24a2b20e48e62edcce3a42eb6) | fix | handle transformed classes when generating HMR code ([#60298](https://github.com/angular/angular/pull/60298)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [6dc41265fd](https://github.com/angular/angular/commit/6dc41265fd47df3fd0462bcd8f451eb6aea972ef) | fix | check whether application is destroyed before initializing event replay ([#59789](https://github.com/angular/angular/pull/59789)) |
| [bb12b30d52](https://github.com/angular/angular/commit/bb12b30d5213912f50f53aff60a11e6d47349c82) | fix | ensures immediate trigger fires properly with lazy loaded routes ([#60203](https://github.com/angular/angular/pull/60203)) |
| [b144dd946e](https://github.com/angular/angular/commit/b144dd946e38e52ce716aca7c6ba7c1a1a02f13d) | fix | fix removal of a container reference used in the component file ([#60210](https://github.com/angular/angular/pull/60210)) |
### platform-server
| Commit | Type | Description |
| -- | -- | -- |
| [15c42969fc](https://github.com/angular/angular/commit/15c42969fc42c76e3bd593201164183fb82d70f6) | fix | add missing peer dependency for `rxjs` ([#60308](https://github.com/angular/angular/pull/60308)) |
### router
| Commit | Type | Description |
| -- | -- | -- |
| [7bcdf7c143](https://github.com/angular/angular/commit/7bcdf7c1435f766b2b0bbd383358ef2ddabf217a) | fix | update symbols ([#60233](https://github.com/angular/angular/pull/60233)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="19.2.1"></a>
# 19.2.1 (2025-03-05)
### common
| Commit | Type | Description |
| -- | -- | -- |
| [c2de5f68b3](https://github.com/angular/angular/commit/c2de5f68b3d3cd8a0c43b3c4325a1a1db874e132) | fix | clean up `onUrlChange` listener when root scope is destroyed ([#60004](https://github.com/angular/angular/pull/60004)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [1dd94476b3](https://github.com/angular/angular/commit/1dd94476b35d08e753766b1d0c5d8af5faa017a9) | fix | ensure template IDs are not reused if a source file changes ([#60152](https://github.com/angular/angular/pull/60152)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [1b3b05bf72](https://github.com/angular/angular/commit/1b3b05bf7294963aa50f83b726db620b250b1a5c) | fix | cache ComponentRef inputs and outputs ([#60156](https://github.com/angular/angular/pull/60156)) |
| [330c24aed9](https://github.com/angular/angular/commit/330c24aed92e4b916fb7ac6a91fb17c3ae728869) | fix | prevent invoking replay listeners on disconnected nodes ([#60103](https://github.com/angular/angular/pull/60103)) |
| [cfad089cc3](https://github.com/angular/angular/commit/cfad089cc359cddf08d462662d2a6bf3acab9b22) | fix | prevents event replay from being called on comment nodes ([#60130](https://github.com/angular/angular/pull/60130)) |
### language-service
| Commit | Type | Description |
| -- | -- | -- |
| [3f0116607d](https://github.com/angular/angular/commit/3f0116607dc3ad7e31cb4d895a56094f77c82f5d) | fix | Forward the tags for quick info from the type definition ([#59524](https://github.com/angular/angular/pull/59524)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="19.2.0"></a>
# 19.2.0 (2025-02-26)
### common
| Commit | Type | Description |
| -- | -- | -- |
| [3e39da593a](https://github.com/angular/angular/commit/3e39da593a0a0c047a2a03b8d5fcabf9dbace40f) | feat | introduce experimental `httpResource` ([#59876](https://github.com/angular/angular/pull/59876)) |
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [5b20bab96d](https://github.com/angular/angular/commit/5b20bab96d20fe89b5cc4b4af28edbaae2604da1) | feat | Add Skip Hydration diagnostic. ([#59576](https://github.com/angular/angular/pull/59576)) |
| [fe8a68329b](https://github.com/angular/angular/commit/fe8a68329b50363f914a728579392f3fc68670a6) | feat | support untagged template literals in expressions ([#59230](https://github.com/angular/angular/pull/59230)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [2588985f43](https://github.com/angular/angular/commit/2588985f433b20a6a5a8d239347291f5d6fb2451) | feat | pass signal node to throwInvalidWriteToSignalErrorFn ([#59600](https://github.com/angular/angular/pull/59600)) |
| [168516462a](https://github.com/angular/angular/commit/168516462a9673b158fcaa38b8ce17bf684a8ac9) | feat | support default value in `resource()` ([#59655](https://github.com/angular/angular/pull/59655)) |
| [bc2ad7bfd3](https://github.com/angular/angular/commit/bc2ad7bfd37a61992b550943de5da0eab2eec98b) | feat | support streaming resources ([#59573](https://github.com/angular/angular/pull/59573)) |
| [146ab9a76e](https://github.com/angular/angular/commit/146ab9a76e6b4d8db7d08d34e2571ba5207f8756) | feat | support TypeScript 5.8 ([#59830](https://github.com/angular/angular/pull/59830)) |
| [6c92d65349](https://github.com/angular/angular/commit/6c92d653493404a5f13aa59cde390bcbed973fb6) | fix | add `hasValue` narrowing to `ResourceRef` ([#59708](https://github.com/angular/angular/pull/59708)) |
| [96e602ebe9](https://github.com/angular/angular/commit/96e602ebe9cdf7355befad22c11f9f91e0436e01) | fix | cancel in-progress request when same value is assigned ([#59280](https://github.com/angular/angular/pull/59280)) |
| [6789c7ef94](https://github.com/angular/angular/commit/6789c7ef947952551d7598fe37a3d86093b75720) | fix | Defer afterRender until after first CD ([#59455](https://github.com/angular/angular/pull/59455)) ([#59551](https://github.com/angular/angular/pull/59551)) |
| [c87e581dd9](https://github.com/angular/angular/commit/c87e581dd9e240c88cea50f222942873bdccd01d) | fix | Don't run effects in check no changes pass ([#59455](https://github.com/angular/angular/pull/59455)) ([#59551](https://github.com/angular/angular/pull/59551)) |
| [127fc0dc84](https://github.com/angular/angular/commit/127fc0dc847a4e8b62be36cdd980a067c4da974f) | fix | fix `resource()`'s `previous.state` ([#59708](https://github.com/angular/angular/pull/59708)) |
| [b592b1b051](https://github.com/angular/angular/commit/b592b1b0516786c52c7d0638c4e7545b0de8a545) | fix | fix race condition in resource() ([#59851](https://github.com/angular/angular/pull/59851)) |
| [a299e02e91](https://github.com/angular/angular/commit/a299e02e9141cdc4d74185deb58308fa010bb36e) | fix | preserve tracing snapshot until tick finishes ([#59796](https://github.com/angular/angular/pull/59796)) |
### forms
| Commit | Type | Description |
| -- | -- | -- |
| [fa0c3e3210](https://github.com/angular/angular/commit/fa0c3e3210885a36e5c9e9eb76e821032f5cd215) | feat | support type set in form validators ([#45793](https://github.com/angular/angular/pull/45793)) |
### migrations
| Commit | Type | Description |
| -- | -- | -- |
| [1cd3a7db83](https://github.com/angular/angular/commit/1cd3a7db83e1d05a31d23324676420b614cdabe2) | feat | add migration to convert templates to use self-closing tags ([#57342](https://github.com/angular/angular/pull/57342)) |
### platform-browser
| Commit | Type | Description |
| -- | -- | -- |
| [e6cb411e43](https://github.com/angular/angular/commit/e6cb411e4393a4b1f5852d3d7c5b9622504399b1) | fix | automatically disable animations on the server ([#59762](https://github.com/angular/angular/pull/59762)) |
### platform-server
| Commit | Type | Description |
| -- | -- | -- |
| [fc5d187da5](https://github.com/angular/angular/commit/fc5d187da5e8895d60caa35b7b59e234998eddf0) | fix | decouple server from animations module ([#59762](https://github.com/angular/angular/pull/59762)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="19.1.7"></a>
# 19.1.7 (2025-02-19)
### common
@@ -15,30 +250,6 @@
<!-- CHANGELOG SPLIT MARKER -->
<a name="19.2.0-next.3"></a>
# 19.2.0-next.3 (2025-02-13)
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [9e847fc60d](https://github.com/angular/angular/commit/9e847fc60d4eef47e665e789ccd2d4f0b4bb94ea) | fix | handle tracking expressions requiring temporary variables ([#58520](https://github.com/angular/angular/pull/58520)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [5cd26a9420](https://github.com/angular/angular/commit/5cd26a94206dfe8aabdf0dd15bfc09e7a8c606da) | fix | handle deferred blocks with shared dependencies correctly ([#59926](https://github.com/angular/angular/pull/59926)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [6789c7ef94](https://github.com/angular/angular/commit/6789c7ef947952551d7598fe37a3d86093b75720) | fix | Defer afterRender until after first CD ([#59455](https://github.com/angular/angular/pull/59455)) ([#59551](https://github.com/angular/angular/pull/59551)) |
| [c87e581dd9](https://github.com/angular/angular/commit/c87e581dd9e240c88cea50f222942873bdccd01d) | fix | Don't run effects in check no changes pass ([#59455](https://github.com/angular/angular/pull/59455)) ([#59551](https://github.com/angular/angular/pull/59551)) |
| [b0266bda4a](https://github.com/angular/angular/commit/b0266bda4ad4efd19710fd0363a50984f48269dc) | fix | invalidate HMR component if replacement throws an error ([#59854](https://github.com/angular/angular/pull/59854)) |
### migrations
| Commit | Type | Description |
| -- | -- | -- |
| [aa285c548c](https://github.com/angular/angular/commit/aa285c548c164917ebb5760802484843c6830daf) | fix | account for let declarations in control flow migration ([#59861](https://github.com/angular/angular/pull/59861)) |
| [1119f85ca9](https://github.com/angular/angular/commit/1119f85ca935f43641f53ee8bc50efa47ad09717) | fix | count used dependencies inside existing control flow ([#59861](https://github.com/angular/angular/pull/59861)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="19.1.6"></a>
# 19.1.6 (2025-02-12)
### compiler
@@ -61,27 +272,6 @@
<!-- CHANGELOG SPLIT MARKER -->
<a name="19.2.0-next.2"></a>
# 19.2.0-next.2 (2025-02-06)
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [a97136052f9](https://github.com/angular/angular/commit/a97136052f9cfdb696a3b335ed7a1b9fb994d408) | fix | gracefully fall back if const enum cannot be passed through ([#59815](https://github.com/angular/angular/pull/59815)) |
| [bae94b82fda](https://github.com/angular/angular/commit/bae94b82fda1669a6aafad975a3a0eb6f2743039) | fix | handle const enums used inside HMR data ([#59815](https://github.com/angular/angular/pull/59815)) |
| [03bcd30e348](https://github.com/angular/angular/commit/03bcd30e3487443983d450a5dfea2d68d551bbd3) | fix | handle enum members without initializers in partial evaluator ([#59815](https://github.com/angular/angular/pull/59815)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [146ab9a76e6](https://github.com/angular/angular/commit/146ab9a76e6b4d8db7d08d34e2571ba5207f8756) | feat | support TypeScript 5.8 ([#59830](https://github.com/angular/angular/pull/59830)) |
| [b592b1b0516](https://github.com/angular/angular/commit/b592b1b0516786c52c7d0638c4e7545b0de8a545) | fix | fix race condition in resource() ([#59851](https://github.com/angular/angular/pull/59851)) |
| [a299e02e914](https://github.com/angular/angular/commit/a299e02e9141cdc4d74185deb58308fa010bb36e) | fix | preserve tracing snapshot until tick finishes ([#59796](https://github.com/angular/angular/pull/59796)) |
### forms
| Commit | Type | Description |
| -- | -- | -- |
| [fa0c3e32108](https://github.com/angular/angular/commit/fa0c3e3210885a36e5c9e9eb76e821032f5cd215) | feat | support type set in form validators ([#45793](https://github.com/angular/angular/pull/45793)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="19.1.5"></a>
# 19.1.5 (2025-02-06)
### compiler-cli
@@ -93,45 +283,6 @@
<!-- CHANGELOG SPLIT MARKER -->
<a name="19.2.0-next.1"></a>
# 19.2.0-next.1 (2025-01-29)
### core
| Commit | Type | Description |
| -- | -- | -- |
| [168516462a9](https://github.com/angular/angular/commit/168516462a9673b158fcaa38b8ce17bf684a8ac9) | feat | support default value in `resource()` ([#59655](https://github.com/angular/angular/pull/59655)) |
| [6c92d653493](https://github.com/angular/angular/commit/6c92d653493404a5f13aa59cde390bcbed973fb6) | fix | add `hasValue` narrowing to `ResourceRef` ([#59708](https://github.com/angular/angular/pull/59708)) |
| [96e602ebe9c](https://github.com/angular/angular/commit/96e602ebe9cdf7355befad22c11f9f91e0436e01) | fix | cancel in-progress request when same value is assigned ([#59280](https://github.com/angular/angular/pull/59280)) |
| [cf9054248d1](https://github.com/angular/angular/commit/cf9054248d1b8b5658c5f8b582cea71535f081c2) | fix | check whether application is destroyed before printing hydration stats ([#59716](https://github.com/angular/angular/pull/59716)) |
| [82876242e55](https://github.com/angular/angular/commit/82876242e557abbced793cff06c4d68c4721e6d2) | fix | ensure type is preserved during HMR ([#59700](https://github.com/angular/angular/pull/59700)) |
| [127fc0dc847](https://github.com/angular/angular/commit/127fc0dc847a4e8b62be36cdd980a067c4da974f) | fix | fix `resource()`'s `previous.state` ([#59708](https://github.com/angular/angular/pull/59708)) |
| [f862ace1819](https://github.com/angular/angular/commit/f862ace18191d7fda3b12fc3c6486c035a6b431d) | fix | fixes test timer-based test flakiness in CI ([#59674](https://github.com/angular/angular/pull/59674)) |
### elements
| Commit | Type | Description |
| -- | -- | -- |
| [0c1ecb453c8](https://github.com/angular/angular/commit/0c1ecb453c8b01447fb5a9f38fdfe9936a60abe5) | fix | not setting initial value on signal-based input ([#59773](https://github.com/angular/angular/pull/59773)) |
### platform-browser
| Commit | Type | Description |
| -- | -- | -- |
| [e6cb411e439](https://github.com/angular/angular/commit/e6cb411e4393a4b1f5852d3d7c5b9622504399b1) | fix | automatically disable animations on the server ([#59762](https://github.com/angular/angular/pull/59762)) |
| [6b09716754b](https://github.com/angular/angular/commit/6b09716754b979c98489a2710eda977e51fe92d0) | fix | prepend `baseHref` to `sourceMappingURL` in CSS content ([#59730](https://github.com/angular/angular/pull/59730)) |
| [fd7ee47bf70](https://github.com/angular/angular/commit/fd7ee47bf702029e481ad40362684f0a01ef2ec0) | fix | Update pseudoevent created by createMouseSpecialEvent to populate `_originalEvent` property ([#59690](https://github.com/angular/angular/pull/59690)) |
| [65cf061feb4](https://github.com/angular/angular/commit/65cf061feb402e1532cd06d0fda5d2b7749ac421) | fix | Update pseudoevent created by createMouseSpecialEvent to populate `_originalEvent` property ([#59690](https://github.com/angular/angular/pull/59690)) |
| [af9d74710c4](https://github.com/angular/angular/commit/af9d74710c460b0aaeaf3226533e9e544025523c) | fix | Update pseudoevent created by createMouseSpecialEvent to populate `_originalEvent` property ([#59690](https://github.com/angular/angular/pull/59690)) |
### platform-server
| Commit | Type | Description |
| -- | -- | -- |
| [fc5d187da5e](https://github.com/angular/angular/commit/fc5d187da5e8895d60caa35b7b59e234998eddf0) | fix | decouple server from animations module ([#59762](https://github.com/angular/angular/pull/59762)) |
### router
| Commit | Type | Description |
| -- | -- | -- |
| [c7b6e1107c6](https://github.com/angular/angular/commit/c7b6e1107c6fcc7ed1dbb7c7b8698b09bfa8f1cc) | fix | prevent error handling when injector is destroyed ([#59457](https://github.com/angular/angular/pull/59457)) |
### service-worker
| Commit | Type | Description |
| -- | -- | -- |
| [e2987a1d4ab](https://github.com/angular/angular/commit/e2987a1d4ab09b1abf1f42597c40f2055db116e1) | fix | add missing `rxjs` peer dependency ([#59747](https://github.com/angular/angular/pull/59747)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="19.1.4"></a>
# 19.1.4 (2025-01-29)
### core
@@ -162,23 +313,6 @@
<!-- CHANGELOG SPLIT MARKER -->
<a name="19.2.0-next.0"></a>
# 19.2.0-next.0 (2025-01-22)
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [fe8a68329b](https://github.com/angular/angular/commit/fe8a68329b50363f914a728579392f3fc68670a6) | feat | support untagged template literals in expressions ([#59230](https://github.com/angular/angular/pull/59230)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [ed705a856a](https://github.com/angular/angular/commit/ed705a856a164f91d33e2173b4f371329d07c472) | feat | detect missing structural directive imports ([#59443](https://github.com/angular/angular/pull/59443)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [bc2ad7bfd3](https://github.com/angular/angular/commit/bc2ad7bfd37a61992b550943de5da0eab2eec98b) | feat | support streaming resources ([#59573](https://github.com/angular/angular/pull/59573)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="19.1.3"></a>
# 19.1.3 (2025-01-22)
### compiler
+6 -155
View File
@@ -103,7 +103,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
8. Run the full Angular test suite, as described in the [developer documentation][dev-doc], and ensure that all tests pass.
9. Commit your changes using a descriptive commit message that follows our [commit message conventions](#commit).
9. Commit your changes using a descriptive commit message that follows our [commit message conventions][commit-message-guidelines].
Adherence to these conventions is necessary because release notes are automatically generated from these messages.
```shell
@@ -145,7 +145,7 @@ That's it! Thank you for your contribution!
##### Updating the commit message
A reviewer might often suggest changes to a commit message (for example, to add more context for a change or adhere to our [commit message guidelines](#commit)).
A reviewer might often suggest changes to a commit message (for example, to add more context for a change or adhere to our [commit message guidelines][commit-message-guidelines]).
In order to update the commit message of the last commit on your branch:
1. Check out your branch:
@@ -210,163 +210,14 @@ To ensure consistency throughout the source code, keep these rules in mind as yo
An automated formatter is available, see [DEVELOPER.md](contributing-docs/building-and-testing-angular.md#formatting-your-source-code).
## <a name="commit"></a> Commit Message Format
*This specification is inspired by and supersedes the [AngularJS commit message format][commit-message-format].*
We have very precise rules over how our Git commit messages must be formatted.
This format leads to **easier to read commit history**.
Each commit message consists of a **header**, a **body**, and a **footer**.
```
<header>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
The `header` is mandatory and must conform to the [Commit Message Header](#commit-header) format.
The `body` is mandatory for all commits except for those of type "docs".
When the body is present it must be at least 20 characters long and must conform to the [Commit Message Body](#commit-body) format.
The `footer` is optional. The [Commit Message Footer](#commit-footer) format describes what the footer is used for and the structure it must have.
#### <a name="commit-header"></a>Commit Message Header
## <a name="commit"></a> Commit Message Guidelines
We have very precise rules over how our Git commit messages must be formatted:
```
<type>(<scope>): <short summary>
│ │ │
│ │ └─⫸ Summary in present tense. Not capitalized. No period at the end.
│ │
│ └─⫸ Commit Scope: animations|bazel|benchpress|common|compiler|compiler-cli|core|
│ elements|forms|http|language-service|localize|platform-browser|
│ platform-browser-dynamic|platform-server|router|service-worker|
│ upgrade|zone.js|packaging|changelog|docs-infra|migrations|
│ devtools
│
└─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|test
```
The `<type>` and `<summary>` fields are mandatory, the `(<scope>)` field is optional.
##### Type
Must be one of the following:
* **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
* **ci**: Changes to our CI configuration files and scripts (examples: Github Actions, SauceLabs)
* **docs**: Documentation only changes
* **feat**: A new feature
* **fix**: A bug fix
* **perf**: A code change that improves performance
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **test**: Adding missing tests or correcting existing tests
##### Scope
The scope should be the name of the npm package affected (as perceived by the person reading the changelog generated from commit messages).
The following is the list of supported scopes:
* `animations`
* `bazel`
* `benchpress`
* `common`
* `compiler`
* `compiler-cli`
* `core`
* `elements`
* `forms`
* `http`
* `language-service`
* `localize`
* `platform-browser`
* `platform-browser-dynamic`
* `platform-server`
* `router`
* `service-worker`
* `upgrade`
* `zone.js`
There are currently a few exceptions to the "use package name" rule:
* `packaging`: used for changes that change the npm package layout in all of our packages, e.g. public path changes, package.json changes done to all packages, d.ts file/format changes, changes to bundles, etc.
* `changelog`: used for updating the release notes in CHANGELOG.md
* `dev-infra`: used for dev-infra related changes within the directories /scripts and /tools
* `docs-infra`: used for docs-app (angular.dev) related changes within the /adev directory of the repo
* `migrations`: used for changes to the `ng update` migrations.
* `devtools`: used for changes in the [browser extension](./devtools/README.md).
* none/empty string: useful for `test` and `refactor` changes that are done across all packages (e.g. `test: add missing unit tests`) and for docs changes that are not related to a specific package (e.g. `docs: fix typo in tutorial`).
##### Summary
Use the summary field to provide a succinct description of the change:
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize the first letter
* no dot (.) at the end
#### <a name="commit-body"></a>Commit Message Body
Just as in the summary, use the imperative, present tense: "fix" not "fixed" nor "fixes".
Explain the motivation for the change in the commit message body. This commit message should explain _why_ you are making the change.
You can include a comparison of the previous behavior with the new behavior in order to illustrate the impact of the change.
#### <a name="commit-footer"></a>Commit Message Footer
The footer can contain information about breaking changes and deprecations and is also the place to reference GitHub issues, Jira tickets, and other PRs that this commit closes or is related to.
For example:
```
BREAKING CHANGE: <breaking change summary>
<BLANK LINE>
<breaking change description + migration instructions>
<BLANK LINE>
<BLANK LINE>
Fixes #<issue number>
```
or
```
DEPRECATED: <what is deprecated>
<BLANK LINE>
<deprecation description + recommended update path>
<BLANK LINE>
<BLANK LINE>
Closes #<pr number>
```
Breaking Change section should start with the phrase `BREAKING CHANGE: ` followed by a summary of the breaking change, a blank line, and a detailed description of the breaking change that also includes migration instructions.
Similarly, a Deprecation section should start with `DEPRECATED: ` followed by a short description of what is deprecated, a blank line, and a detailed description of the deprecation that also mentions the recommended update path.
### Revert commits
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit.
The content of the commit message body should contain:
- information about the SHA of the commit being reverted in the following format: `This reverts commit <SHA>`,
- a clear description of the reason for reverting the commit message.
See [Commit Message Guidelines][commit-message-guidelines] for details.
## <a name="cla"></a> Signing the CLA
@@ -390,9 +241,9 @@ The following documents can help you sort out issues with GitHub accounts and mu
[coc]: https://github.com/angular/code-of-conduct/blob/main/CODE_OF_CONDUCT.md
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
[corporate-cla]: https://cla.developers.google.com/about/google-corporate
[dev-doc]: ./contributing-docs/building-and-testing-angular.md
[commit-message-guidelines]: ./contributing-docs/commit-message-guidelines.md
[github]: https://github.com/angular/angular
[discord]: https://discord.gg/angular
[individual-cla]: https://cla.developers.google.com/about/google-individual
+3 -3
View File
@@ -143,10 +143,10 @@ cldr_xml_data_repository(
# sass rules
http_archive(
name = "io_bazel_rules_sass",
sha256 = "54bca211ea0a4de2c740a6e24b9d11225942a95452799b6a64dba36e082b7249",
strip_prefix = "rules_sass-c01e8848f30f8e4672babcbe41c3ac3551f3a800",
sha256 = "bff856619317a388292970a7d4bfea8c9e627a1886fe7132075d378d4067c09e",
strip_prefix = "rules_sass-cbe5261f925751a465a1a54bf2147e5f696ec567",
urls = [
"https://github.com/bazelbuild/rules_sass/archive/c01e8848f30f8e4672babcbe41c3ac3551f3a800.zip",
"https://github.com/bazelbuild/rules_sass/archive/cbe5261f925751a465a1a54bf2147e5f696ec567.zip",
],
)
+3 -1
View File
@@ -23,7 +23,9 @@ APPLICATION_FILES = [
exclude = [
"src/**/*.spec.ts",
],
)
) + [
"//adev/src/content/examples:embeddable",
]
TEST_FILES = APPLICATION_FILES + [
"karma.conf.js",
+1 -1
View File
@@ -20,7 +20,7 @@ cd angular
yarn
# Build and run local dev server
# Note: Initial build will take some time
# NOTE: Initial build will take some time
yarn docs
```
-1
View File
@@ -10,7 +10,6 @@ ng_module(
module_name = "@angular/docs",
deps = [
"//adev/shared-docs/components",
"//adev/shared-docs/constants",
"//adev/shared-docs/directives",
"//adev/shared-docs/interfaces",
"//adev/shared-docs/pipes",
@@ -1,5 +1,5 @@
load("//tools:defaults.bzl", "karma_web_test_suite", "ng_module", "ts_library")
load("@io_bazel_rules_sass//:defs.bzl", "sass_binary")
load("//tools:defaults.bzl", "karma_web_test_suite", "ng_module", "ts_library")
package(default_visibility = ["//visibility:private"])
@@ -23,6 +23,7 @@ ng_module(
"//packages/common",
"//packages/core",
"//packages/router",
"@npm//@angular/material",
],
)
@@ -7,8 +7,15 @@
<li class="docs-faceted-list-item">
@if (item.path) {
@if (item.isExternal) {
<a [href]="item.path" target="_blank">
<span [class.docs-external-link]="item.isExternal">{{ item.label }}</span>
<a
[href]="item.path" target="_blank"
[matTooltip]="item.label"
[matTooltipDisabled]="item.label.length < 27"
matTooltipPosition="after"
[attr.aria-label]="item.label"
[matTooltipClass]="'API-tooltip'"
>
<span [class.docs-external-link]="item.isExternal" class="docs-faceted-list-item-text">{{ item.label }}</span>
@if (item.children && item.level! > 1 && !item.isExpanded) {
<docs-icon>chevron_right</docs-icon>
}
@@ -25,8 +32,13 @@
}"
routerLinkActive="docs-faceted-list-item-active"
(click)="emitClickOnLink()"
[matTooltip]="item.label"
[matTooltipDisabled]="item.label.length < 27"
matTooltipPosition="after"
[attr.aria-label]="item.label"
[matTooltipClass]="'API-tooltip'"
>
<span>{{item.label}}</span>
<span class="docs-faceted-list-item-text">{{item.label}}</span>
@if (item.children && !item.isExpanded) {
<docs-icon>chevron_right</docs-icon>
}
@@ -35,8 +47,14 @@
} @else {
<!-- Nav Section Header -->
@if (item.level !== collapsableLevel() && item.level !== expandableLevel()) {
<div class="docs-secondary-nav-header">
<span>{{item.label}}</span>
<div class="docs-secondary-nav-header"
[matTooltip]="item.label"
[matTooltipDisabled]="item.label.length < 27"
matTooltipPosition="after"
[attr.aria-label]="item.label"
[matTooltipClass]="'API-tooltip'"
>
<span class="docs-faceted-list-item-text">{{item.label}}</span>
</div>
}
@@ -54,13 +72,17 @@
[class.docs-expanded-button]="item.children && item.level == collapsableLevel()"
[class.docs-not-expanded-button]="item.children && item.level === expandableLevel()"
[class.docs-nav-item-has-icon]="
item.children && item.level === expandableLevel() && !item.isExpanded
"
item.children && item.level === expandableLevel() && !item.isExpanded"
[matTooltip]="item.label"
[matTooltipDisabled]="item.label.length < 27"
matTooltipPosition="after"
[attr.aria-label]="item.label"
[matTooltipClass]="'API-tooltip'"
>
@if (item.children && item.level === collapsableLevel()) {
<docs-icon>arrow_back</docs-icon>
}
<span>{{ item.label }}</span>
<span class="docs-faceted-list-item-text">{{ item.label }}</span>
</button>
}
}
@@ -45,6 +45,12 @@
border: 0;
}
.docs-faceted-list-item-text {
max-width: calc(100% - 1rem);
overflow: hidden;
text-overflow: ellipsis;
}
.docs-nav-item-has-icon {
&::after {
// FIXME: for some reason this disappears when transformed
@@ -115,7 +121,7 @@ a,
// Add padding-bottom to last item in the list
.docs-navigation-list {
width: 100%;
width: 15rem;
li:last-of-type {
ul:last-of-type {
@@ -144,3 +150,12 @@ a,
margin-inline-end: 0.4rem;
}
}
::ng-deep .API-tooltip{
.mat-mdc-tooltip-surface{
max-width: unset;
width:auto;
word-break: keep-all;
white-space: pre;
}
}
@@ -13,10 +13,18 @@ import {RouterLink, RouterLinkActive} from '@angular/router';
import {IconComponent} from '../icon/icon.component';
import {IsActiveNavigationItem} from '../../pipes/is-active-navigation-item.pipe';
import {NgTemplateOutlet} from '@angular/common';
import {MatTooltipModule} from '@angular/material/tooltip';
@Component({
selector: 'docs-navigation-list',
imports: [RouterLink, RouterLinkActive, IconComponent, IsActiveNavigationItem, NgTemplateOutlet],
imports: [
RouterLink,
RouterLinkActive,
IconComponent,
IsActiveNavigationItem,
NgTemplateOutlet,
MatTooltipModule,
],
templateUrl: './navigation-list.component.html',
styleUrls: ['./navigation-list.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -3,15 +3,14 @@
<docs-text-field
[autofocus]="true"
[hideIcon]="true"
[ngModel]="searchQuery()"
(ngModelChange)="updateSearchQuery($event)"
[(ngModel)]="searchQuery"
class="docs-search-input"
placeholder="Search docs"
/>
@if (searchResults() && searchResults()!.length > 0) {
@if (searchResults.hasValue() && searchResults.value().length > 0) {
<ul class="docs-search-results docs-mini-scroll-track">
@for (result of searchResults(); track result.objectID) {
@for (result of searchResults.value(); track result.id) {
<li docsSearchItem [item]="result">
<a
[routerLink]="'/' + result.url | relativeLink: 'pathname'"
@@ -22,45 +21,35 @@
<!-- Icon -->
<span class="docs-search-result-icon" aria-hidden="true">
<i role="presentation" class="material-symbols-outlined docs-icon-small">
{{ result.hierarchy.lvl0 === 'Tutorials' ? 'code' : 'description'}}
{{ result.type === 'code' ? 'code' : 'description'}}
</i>
</span>
<!-- Results type -->
<span class="docs-search-results__type">
@let snippet = result._snippetResult.hierarchy?.lvl1?.value ?? '';
<ng-container
[ngTemplateOutlet]="highlightSnippet"
[ngTemplateOutletContext]="{snippet}"
/>
</span>
<span class="docs-search-results__type" [innerHtml]="result.labelHtml"></span>
</div>
@let content = result._snippetResult.content;
@let hierarchy = result._snippetResult.hierarchy;
@if (content || hierarchy?.lvl2 || hierarchy?.lvl3 || hierarchy?.lvl4) {
<span class="docs-search-results__type docs-search-results__lvl2">
@let snippet = getBestSnippetForMatch(result);
<ng-container
[ngTemplateOutlet]="highlightSnippet"
[ngTemplateOutletContext]="{snippet}"
/>
@if (result.subLabelHtml) {
<span
class="docs-search-results__type docs-search-results__lvl2"
[innerHtml]="result.subLabelHtml"
>
</span>
}
</div>
<!-- Page title -->
<span class="docs-result-page-title">{{ result.hierarchy?.lvl0 }}</span>
<span class="docs-result-page-title">{{ result.category }}</span>
</a>
</li>
}
</ul>
} @else {
<div class="docs-search-results docs-mini-scroll-track">
@if (searchResults() === undefined) {
@if (!searchResults.hasValue()) {
<div class="docs-search-results__start-typing">
<span>Start typing to see results</span>
</div>
} @else if (searchResults()?.length === 0) {
} @else if (searchResults.value().length === 0) {
<div class="docs-search-results__no-results">
<span>No results found</span>
</div>
@@ -70,21 +59,13 @@
<div class="docs-algolia">
<span>Search by</span>
<a target="_blank" rel="noopener"
href="https://www.algolia.com/developers/?utm_source=angular.dev&utm_medium=referral&utm_content=powered_by&utm_campaign=docsearch">
<a
target="_blank"
rel="noopener"
href="https://www.algolia.com/developers/?utm_source=angular.dev&utm_medium=referral&utm_content=powered_by&utm_campaign=docsearch"
>
<docs-algolia-icon />
</a>
</div>
</div>
</dialog>
<ng-template #highlightSnippet let-snippet="snippet">
@let parts = splitMarkedText(snippet);
@for (part of parts; track $index) {
@if (part.highlight) {
<mark>{{part.text}}</mark>
} @else {
<span>{{part.text}}</span>
}
}
</ng-template>
@@ -2,6 +2,8 @@ dialog {
background-color: transparent;
border: none;
padding-block-end: 3rem;
margin: 0 auto;
top: 15vh;
&::backdrop {
backdrop-filter: blur(5px);
@@ -49,12 +51,17 @@ dialog {
padding-inline-end: 1rem;
padding-block: 0.25rem;
mark {
background: #e62600;
background: var(--red-to-orange-horizontal-gradient);
background-clip: text;
-webkit-background-clip: text;
color: transparent;
/**
* This rule needs ng-deep to be applied to elements that are created via a [innerHTML] binding
*/
::ng-deep {
mark {
background: #e62600;
background: var(--red-to-orange-horizontal-gradient);
background-clip: text;
-webkit-background-clip: text;
color: transparent;
}
}
a {
@@ -148,8 +155,8 @@ dialog {
border-radius: 0 0 0.25rem 0.25rem;
docs-algolia-icon {
display: inline-flex;
margin-block-start: 0.12rem;
display: block;
margin-block-start: 5px;
margin-inline-start: 0.15rem;
width: 4rem;
}
@@ -9,54 +9,59 @@
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {SearchDialog} from './search-dialog.component';
import {WINDOW} from '../../providers';
import {Search} from '../../services';
import {ENVIRONMENT, WINDOW} from '../../providers';
import {ALGOLIA_CLIENT, Search} from '../../services';
import {FakeEventTarget} from '../../testing/index';
import {By} from '@angular/platform-browser';
import {AlgoliaIcon} from '../algolia-icon/algolia-icon.component';
import {RouterTestingModule} from '@angular/router/testing';
import {Router} from '@angular/router';
import {provideExperimentalZonelessChangeDetection} from '@angular/core';
import {
ApplicationRef,
provideExperimentalZonelessChangeDetection,
ResourceStatus,
} from '@angular/core';
import {SearchResult} from '../../interfaces';
describe('SearchDialog', () => {
let fixture: ComponentFixture<SearchDialog>;
const fakeSearch = {
searchQuery: jasmine.createSpy(),
searchResults: jasmine.createSpy(),
};
const searchResults = jasmine.createSpy();
const fakeWindow = new FakeEventTarget();
beforeEach(async () => {
fakeSearch.searchResults.and.returnValue([]);
fakeSearch.searchQuery.and.returnValue('');
let search: Search;
await TestBed.configureTestingModule({
beforeEach(async () => {
searchResults.and.returnValue([]);
TestBed.configureTestingModule({
imports: [SearchDialog, RouterTestingModule],
providers: [
provideExperimentalZonelessChangeDetection(),
{
provide: Search,
useValue: fakeSearch,
},
{
provide: WINDOW,
useValue: fakeWindow,
},
{provide: ENVIRONMENT, useValue: {algolia: {index: 'fakeIndex'}}},
{provide: ALGOLIA_CLIENT, useValue: {search: searchResults}},
{provide: WINDOW, useValue: fakeWindow},
],
}).compileComponents();
});
fixture = TestBed.createComponent(SearchDialog);
fixture.detectChanges();
search = TestBed.inject(Search);
});
it('should navigate to active item when user pressed Enter', () => {
it('should navigate to active item when user pressed Enter', async () => {
const router = TestBed.inject(Router);
const navigateByUrlSpy = spyOn(router, 'navigateByUrl');
fakeSearch.searchResults.and.returnValue(fakeSearchResults);
fixture.detectChanges();
search.searchQuery.set('fakeQuery');
searchResults.and.returnValue(Promise.resolve({results: [{hits: fakeSearchResults}]}));
// Fire the request
TestBed.inject(ApplicationRef).tick();
// Wait for the resource to resolve
await TestBed.inject(ApplicationRef).whenStable();
fakeWindow.dispatchEvent(
new KeyboardEvent('keydown', {
@@ -78,9 +83,15 @@ describe('SearchDialog', () => {
expect(algoliaIcon).toBeTruthy();
});
it('should display `No results found` message when there are no results for provided query', () => {
fakeSearch.searchResults.and.returnValue([]);
fixture.detectChanges();
it('should display `No results found` message when there are no results for provided query', async () => {
search.searchQuery.set('fakeQuery');
searchResults.and.returnValue(Promise.resolve({results: [{hits: []}]}));
// Fire the request
TestBed.inject(ApplicationRef).tick();
// Wait for the resource to resolve
await TestBed.inject(ApplicationRef).whenStable();
const noResultsContainer = fixture.debugElement.query(
By.css('.docs-search-results__no-results'),
@@ -90,7 +101,7 @@ describe('SearchDialog', () => {
});
it('should display `Start typing to see results` message when there are no provided query', () => {
fakeSearch.searchResults.and.returnValue(undefined);
searchResults.and.returnValue(undefined);
fixture.detectChanges();
const startTypingContainer = fixture.debugElement.query(
@@ -100,9 +111,15 @@ describe('SearchDialog', () => {
expect(startTypingContainer).toBeTruthy();
});
it('should display list of the search results when results exist', () => {
fakeSearch.searchResults.and.returnValue(fakeSearchResults);
fixture.detectChanges();
it('should display list of the search results when results exist', async () => {
search.searchQuery.set('fakeQuery');
searchResults.and.returnValue(Promise.resolve({results: [{hits: fakeSearchResults}]}));
// Fire the request
TestBed.inject(ApplicationRef).tick();
// Wait for the resource to resolve
await TestBed.inject(ApplicationRef).whenStable();
const resultListContainer = fixture.debugElement.query(By.css('ul.docs-search-results'));
const resultItems = fixture.debugElement.queryAll(By.css('ul.docs-search-results li a'));
@@ -12,7 +12,6 @@ import {
ElementRef,
Injector,
OnDestroy,
Signal,
afterNextRender,
effect,
inject,
@@ -20,7 +19,6 @@ import {
viewChild,
viewChildren,
} from '@angular/core';
import {NgTemplateOutlet} from '@angular/common';
import {WINDOW} from '../../providers/index';
import {ClickOutside} from '../../directives/index';
@@ -32,10 +30,9 @@ 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 {filter, fromEvent} from 'rxjs';
import {fromEvent} from 'rxjs';
import {AlgoliaIcon} from '../algolia-icon/algolia-icon.component';
import {RelativeLink} from '../../pipes/relative-link.pipe';
import {SearchResult, SnippetResult} from '../../interfaces';
@Component({
selector: 'docs-search-dialog',
@@ -48,7 +45,6 @@ import {SearchResult, SnippetResult} from '../../interfaces';
AlgoliaIcon,
RelativeLink,
RouterLink,
NgTemplateOutlet,
],
templateUrl: './search-dialog.component.html',
styleUrls: ['./search-dialog.component.scss'],
@@ -106,46 +102,6 @@ export class SearchDialog implements OnDestroy {
});
}
splitMarkedText(snippet: string): Array<{highlight: boolean; text: string}> {
const parts: Array<{highlight: boolean; text: string}> = [];
while (snippet.indexOf('<ɵ>') !== -1) {
const beforeMatch = snippet.substring(0, snippet.indexOf('<ɵ>'));
const match = snippet.substring(snippet.indexOf('<ɵ>') + 3, snippet.indexOf('</ɵ>'));
parts.push({highlight: false, text: beforeMatch});
parts.push({highlight: true, text: match});
snippet = snippet.substring(snippet.indexOf('</ɵ>') + 4);
}
parts.push({highlight: false, text: snippet});
return parts;
}
getBestSnippetForMatch(result: SearchResult): string {
// if there is content, return it
if (result._snippetResult.content !== undefined) {
return result._snippetResult.content.value;
}
const hierarchy = result._snippetResult.hierarchy;
if (hierarchy === undefined) {
return '';
}
function matched(snippet: SnippetResult | undefined) {
return snippet?.matchLevel !== undefined && snippet.matchLevel !== 'none';
}
// return the most specific subheader match
if (matched(hierarchy.lvl4)) {
return hierarchy.lvl4!.value;
}
if (matched(hierarchy.lvl3)) {
return hierarchy.lvl3!.value;
}
if (matched(hierarchy.lvl2)) {
return hierarchy.lvl2!.value;
}
// if no subheader matched the query, fall back to just returning the most specific one
return hierarchy.lvl3?.value ?? hierarchy.lvl2?.value ?? '';
}
ngOnDestroy(): void {
this.keyManager.destroy();
}
@@ -155,10 +111,6 @@ export class SearchDialog implements OnDestroy {
this.onClose.emit();
}
updateSearchQuery(query: string) {
this.search.updateSearchQuery(query);
}
private navigateToTheActiveItem(): void {
const activeItemLink: string | undefined = this.keyManager.activeItem?.item?.url;
@@ -6,26 +6,18 @@
<ul class="docs-faceted-list">
<!-- TODO: Hide li elements with class docs-toc-item-h3 for laptop, table and phone screen resolutions -->
@for (item of tableOfContentItems(); track item.id) {
<li
class="docs-faceted-list-item"
[class.docs-toc-item-h2]="item.level === TableOfContentsLevel.H2"
[class.docs-toc-item-h3]="item.level === TableOfContentsLevel.H3"
>
<!-- Not using routerLink + fragment because of: https://github.com/angular/angular/issues/30139 -->
<a
[href]="location.path() + '#' + item.id"
[class.docs-faceted-list-item-active]="item.id === activeItemId()"
>
{{ item.title }}
</a>
</li>
<li class="docs-faceted-list-item" [class.docs-toc-item-h2]="item.level === TableOfContentsLevel.H2"
[class.docs-toc-item-h3]="item.level === TableOfContentsLevel.H3">
<!-- Not using routerLink + fragment because of: https://github.com/angular/angular/issues/30139 -->
<a [href]="location.path() + '#' + item.id" [class.docs-faceted-list-item-active]="item.id === activeItemId()">
{{ item.title }}
</a>
</li>
}
</ul>
</nav>
@if (shouldDisplayScrollToTop()) {
<button type="button" (click)="scrollToTop()">
<docs-icon role="presentation">arrow_upward_alt</docs-icon>
Back to the top
</button>
}
</aside>
<button type="button" (click)="scrollToTop()">
<docs-icon role="presentation">arrow_upward_alt</docs-icon>
Back to the top
</button>
</aside>
@@ -9,6 +9,7 @@
padding-inline: 1rem;
max-height: 100vh;
overflow-y: scroll;
box-sizing: border-box;
aside {
margin-bottom: 2rem;
@@ -11,8 +11,8 @@ import {
Component,
DestroyRef,
input,
computed,
inject,
afterNextRender,
} from '@angular/core';
import {Location} from '@angular/common';
import {TableOfContentsLevel} from '../../interfaces/index';
@@ -39,12 +39,15 @@ export class TableOfContents {
tableOfContentItems = this.tableOfContentsLoader.tableOfContentItems;
activeItemId = this.scrollSpy.activeItemId;
shouldDisplayScrollToTop = computed(() => !this.scrollSpy.scrollbarThumbOnTop());
TableOfContentsLevel = TableOfContentsLevel;
ngAfterViewInit() {
this.tableOfContentsLoader.buildTableOfContent(this.contentSourceElement());
this.scrollSpy.startListeningToScroll(this.contentSourceElement(), this.destroyRef);
constructor() {
afterNextRender({
read: () => {
this.tableOfContentsLoader.buildTableOfContent(this.contentSourceElement());
this.scrollSpy.setupActiveItemListener(this.contentSourceElement(), this.destroyRef);
},
});
}
scrollToTop(): void {
@@ -121,7 +121,7 @@ describe('DocViewer', () => {
expect(checkIcon.nativeElement.innerHTML).toBe('check');
});
it('should display example viewer in multi file mode when user clicks expand', async () => {
it('should display example viewer in multi file mode when provided example is multi file snippet', async () => {
const fixture = TestBed.createComponent(DocViewer);
fixture.componentRef.setInput(
'docContent',
@@ -131,10 +131,6 @@ describe('DocViewer', () => {
await fixture.whenStable();
const exampleViewer = fixture.debugElement.query(By.directive(ExampleViewer));
const expandButton = fixture.debugElement.query(
By.css('button[aria-label="Expand code example"]'),
);
expandButton.nativeElement.click();
expect(exampleViewer).not.toBeNull();
expect(exampleViewer.componentInstance.view()).toBe(CodeExampleViewMode.MULTI_FILE);
@@ -196,13 +196,13 @@ export class DocViewer implements OnChanges {
const exampleRef = this.viewContainer.createComponent(ExampleViewer);
this.countOfExamples++;
exampleRef.instance.metadata = {
exampleRef.setInput('metadata', {
title: title ?? firstCodeSnippetTitle,
path,
files: snippets,
preview,
id: this.countOfExamples,
};
});
exampleRef.instance.githubUrl = `${GITHUB_CONTENT_URL}/${snippets[0].name}`;
exampleRef.instance.stackblitzUrl = `${ASSETS_EXAMPLES_PATH}/${snippets[0].name}.html`;
@@ -293,9 +293,6 @@ export class DocViewer implements OnChanges {
}
}
// Trigger change detection after setting inputs.
componentRef.changeDetectorRef.detectChanges();
// Attach a view to the ApplicationRef for change detection
// purposes and for hydration serialization to pick it up
// during SSG.
@@ -100,26 +100,59 @@ describe('ExampleViewer', () => {
expect(component.tabs()![2].name).toBe('another-example.ts');
});
it('should expandable be false when none of the example files have defined visibleLinesRange ', waitForAsync(async () => {
it('should expand button not appear when there is no hidden line', waitForAsync(async () => {
component.metadata = getMetadata();
await component.renderExample();
expect(component.expandable()).toBeFalse();
const button = fixture.debugElement.query(By.css('button[aria-label="Expand code example"]'));
expect(button).toBeNull();
}));
it('should expandable be true when at least one example file has defined visibleLinesRange ', waitForAsync(async () => {
it('should have line with hidden line class when expand button is present', waitForAsync(async () => {
const expectedCodeSnippetContent =
'typescript code<br/>' + '<div class="line">hidden line</div>';
component.metadata = getMetadata({
files: [
{name: 'example.ts', content: 'typescript file'},
{
name: 'example.html',
content: 'html file',
visibleLinesRange: '[1, 2]',
name: 'example.ts',
content: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
visibleLinesRange: '[1]',
},
{name: 'another-example.ts', content: 'css file'},
],
});
await component.renderExample();
expect(component.expandable()).toBeTrue();
fixture.detectChanges();
const hiddenLine = fixture.debugElement.query(By.css('div[class="line hidden"]'));
expect(hiddenLine).toBeTruthy();
}));
it('should have no more line with hidden line class when expand button is clicked', waitForAsync(async () => {
const expectedCodeSnippetContent =
'typescript code<br/>' + '<div class="line">hidden line</div>';
component.metadata = getMetadata({
files: [
{
name: 'example.ts',
content: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
visibleLinesRange: '[1]',
},
],
});
await component.renderExample();
fixture.detectChanges();
const expandButton = fixture.debugElement.query(
By.css('button[aria-label="Expand code example"]'),
);
expandButton.nativeElement.click();
fixture.detectChanges();
const hiddenLine = fixture.debugElement.query(By.css('div[class="line hidden"]'));
expect(hiddenLine).toBeNull();
}));
it('should set exampleComponent when metadata contains path and preview is true', waitForAsync(async () => {
@@ -7,18 +7,21 @@
*/
import {
afterNextRender,
ChangeDetectionStrategy,
Component,
DestroyRef,
Input,
Type,
computed,
inject,
ChangeDetectorRef,
ViewChild,
signal,
Component,
computed,
DestroyRef,
ElementRef,
forwardRef,
inject,
Injector,
input,
Input,
signal,
Type,
viewChild,
} from '@angular/core';
import {CommonModule, DOCUMENT} from '@angular/common';
import {MatTabGroup, MatTabsModule} from '@angular/material/tabs';
@@ -47,19 +50,17 @@ export const HIDDEN_CLASS_NAME = 'hidden';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ExampleViewer {
// TODO: replace by signal-based input when it'll be available
@Input({required: true}) set metadata(value: ExampleMetadata) {
this.exampleMetadata.set(value);
}
exampleMetadata = input.required<ExampleMetadata>({alias: 'metadata'});
@Input() githubUrl: string | null = null;
@Input() stackblitzUrl: string | null = null;
@ViewChild('codeTabs') matTabGroup?: MatTabGroup;
readonly matTabGroup = viewChild<MatTabGroup>('codeTabs');
private readonly changeDetector = inject(ChangeDetectorRef);
private readonly clipboard = inject(Clipboard);
private readonly destroyRef = inject(DestroyRef);
private readonly document = inject(DOCUMENT);
private readonly injector = inject(Injector);
private readonly elementRef = inject(ElementRef<HTMLElement>);
private readonly exampleViewerContentLoader = inject(EXAMPLE_VIEWER_CONTENT_LOADER);
@@ -74,8 +75,8 @@ export class ExampleViewer {
CodeExampleViewMode = CodeExampleViewMode;
exampleComponent?: Type<unknown>;
expandable = signal<boolean>(false);
expanded = signal<boolean>(false);
exampleMetadata = signal<ExampleMetadata | null>(null);
snippetCode = signal<Snippet | undefined>(undefined);
tabs = computed(() =>
this.exampleMetadata()?.files.map((file) => ({
@@ -89,9 +90,6 @@ export class ExampleViewer {
? CodeExampleViewMode.SNIPPET
: CodeExampleViewMode.MULTI_FILE,
);
expandable = computed(() =>
this.exampleMetadata()?.files.some((file) => !!file.visibleLinesRange),
);
async renderExample(): Promise<void> {
// Lazy load live example component
@@ -103,18 +101,27 @@ export class ExampleViewer {
this.snippetCode.set(this.exampleMetadata()?.files[0]);
this.changeDetector.detectChanges();
afterNextRender(
() => {
// Several function below query the DOM directly, we need to wait until the DOM is rendered.
this.setCodeLinesVisibility();
this.setCodeLinesVisibility();
this.elementRef.nativeElement.setAttribute(
'id',
`example-${this.exampleMetadata()?.id.toString()!}`,
);
this.elementRef.nativeElement.setAttribute(
'id',
`example-${this.exampleMetadata()?.id.toString()!}`,
this.matTabGroup()?.realignInkBar();
this.listenToMatTabIndexChange();
const lines = this.getHiddenCodeLines();
const lineNumbers = this.getHiddenCodeLineNumbers();
this.expandable.set(lines.length > 0 || lineNumbers.length > 0);
},
{injector: this.injector},
);
this.matTabGroup?.realignInkBar();
this.listenToMatTabIndexChange();
}
toggleExampleVisibility(): void {
@@ -135,8 +142,9 @@ export class ExampleViewer {
}
private listenToMatTabIndexChange(): void {
this.matTabGroup?.realignInkBar();
this.matTabGroup?.selectedIndexChange
const matTabGroup = this.matTabGroup();
matTabGroup?.realignInkBar();
matTabGroup?.selectedIndexChange
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((index) => {
this.snippetCode.set(this.exampleMetadata()?.files[index]);
@@ -157,21 +165,9 @@ export class ExampleViewer {
}
private handleExpandedStateForCodeBlock(): void {
const lines = <HTMLDivElement[]>(
Array.from(
this.elementRef.nativeElement.querySelectorAll(
`.${CODE_LINE_CLASS_NAME}.${HIDDEN_CLASS_NAME}`,
),
)
);
const lines = this.getHiddenCodeLines();
const lineNumbers = <HTMLSpanElement[]>(
Array.from(
this.elementRef.nativeElement.querySelectorAll(
`.${CODE_LINE_NUMBER_CLASS_NAME}.${HIDDEN_CLASS_NAME}`,
),
)
);
const lineNumbers = this.getHiddenCodeLineNumbers();
const gapLines = <HTMLDivElement[]>(
Array.from(
@@ -239,4 +235,24 @@ export class ExampleViewer {
element.parentNode?.insertBefore(separator, element);
}
}
private getHiddenCodeLines(): HTMLDivElement[] {
return <HTMLDivElement[]>(
Array.from(
this.elementRef.nativeElement.querySelectorAll(
`.${CODE_LINE_CLASS_NAME}.${HIDDEN_CLASS_NAME}`,
),
)
);
}
private getHiddenCodeLineNumbers(): HTMLSpanElement[] {
return <HTMLSpanElement[]>(
Array.from(
this.elementRef.nativeElement.querySelectorAll(
`.${CODE_LINE_NUMBER_CLASS_NAME}.${HIDDEN_CLASS_NAME}`,
),
)
);
}
}
-28
View File
@@ -1,28 +0,0 @@
load("//tools:defaults.bzl", "ts_library")
package(default_visibility = ["//visibility:private"])
ts_library(
name = "constants",
srcs = [
"index.ts",
],
visibility = [
"//adev/shared-docs:__subpackages__",
],
deps = [
":lib",
],
)
ts_library(
name = "lib",
srcs = glob(
[
"*.ts",
],
exclude = [
"index.ts",
],
),
)
-13
View File
@@ -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
*/
// Used for both the table of contents and the home animation
export const RESIZE_EVENT_DELAY = 500;
// Used for the home animation
export const WEBGL_LOADED_DELAY = 250;
@@ -8,7 +8,7 @@
import {Directive, ElementRef, Input, inject, signal} from '@angular/core';
import {Highlightable} from '@angular/cdk/a11y';
import {SearchResult} from '../../interfaces/search-results';
import {SearchResultItem} from '../../interfaces';
@Directive({
selector: '[docsSearchItem]',
@@ -17,7 +17,7 @@ import {SearchResult} from '../../interfaces/search-results';
},
})
export class SearchItem implements Highlightable {
@Input() item?: SearchResult;
@Input() item?: SearchResultItem;
@Input() disabled = false;
private readonly elementRef = inject(ElementRef<HTMLLIElement>);
@@ -36,14 +36,6 @@ export class SearchItem implements Highlightable {
this._isActive.set(false);
}
getLabel(): string {
if (!this.item?.hierarchy) {
return '';
}
const {hierarchy} = this.item;
return `${hierarchy.lvl0}${hierarchy.lvl1}${hierarchy.lvl2}`;
}
scrollIntoView(): void {
this.elementRef?.nativeElement.scrollIntoView({block: 'nearest'});
}
+2
View File
@@ -1,11 +1,13 @@
load("//adev/shared-docs/pipeline:_guides.bzl", _generate_guides = "generate_guides")
load("//adev/shared-docs/pipeline:_navigation.bzl", _generate_nav_items = "generate_nav_items")
load("//adev/shared-docs/pipeline:_playground.bzl", _generate_playground = "generate_playground")
load("//adev/shared-docs/pipeline:_previews.bzl", _generate_previews = "generate_previews")
load("//adev/shared-docs/pipeline:_stackblitz.bzl", _generate_stackblitz = "generate_stackblitz")
load("//adev/shared-docs/pipeline:_tutorial.bzl", _generate_tutorial = "generate_tutorial")
generate_guides = _generate_guides
generate_stackblitz = _generate_stackblitz
generate_previews = _generate_previews
generate_playground = _generate_playground
generate_tutorial = _generate_tutorial
generate_nav_items = _generate_nav_items
-1
View File
@@ -12,7 +12,6 @@
export * from './directives/index';
export * from './components/index';
export * from './constants/index';
export * from './interfaces/index';
export * from './providers/index';
export * from './services/index';
@@ -54,3 +54,14 @@ export interface Hierarchy {
lvl5: string | null;
lvl6: string | null;
}
/** Parsed & Structured search results */
export interface SearchResultItem {
type: 'doc' | 'code';
labelHtml: string | null;
subLabelHtml: string | null;
url: string;
id: string;
category: string | null;
}
@@ -19,6 +19,4 @@ export interface TableOfContentsItem {
level: TableOfContentsLevel;
/** The unique title for this document page. */
title: string;
/** The top offset px of the heading */
top: number;
}
+2 -2
View File
@@ -19,8 +19,8 @@
"emoji-regex": "~10.4.0",
"fast-glob": "~3.3.2",
"fflate": "^0.8.2",
"html-entities": "~2.5.2",
"jsdom": "~26.0.0",
"html-entities": "~2.6.0",
"jsdom": "~26.1.0",
"marked": "~15.0.0",
"mermaid": "^11.0.0",
"shiki": "^3.0.0"
+26
View File
@@ -61,6 +61,22 @@ esbuild_esm_bundle(
],
)
esbuild_esm_bundle(
name = "previews-bundle",
entry_point = "//adev/shared-docs/pipeline/examples/previews:index.ts",
external = [
"typescript",
],
output = "previews.mjs",
platform = "node",
target = "es2022",
visibility = ["//visibility:public"],
deps = [
"//adev/shared-docs/pipeline/examples/previews:index",
"@npm//typescript",
],
)
esbuild_esm_bundle(
name = "zip-bundle",
entry_point = "//adev/shared-docs/pipeline/examples/zip:index.ts",
@@ -112,6 +128,7 @@ esbuild_esm_bundle(
exports_files([
"_guides.bzl",
"_stackblitz.bzl",
"_previews.bzl",
"_playground.bzl",
"_tutorial.bzl",
"_navigation.bzl",
@@ -129,6 +146,15 @@ nodejs_binary(
visibility = ["//visibility:public"],
)
nodejs_binary(
name = "previews",
data = [
"@npm//typescript",
],
entry_point = "//adev/shared-docs/pipeline:previews.mjs",
visibility = ["//visibility:public"],
)
nodejs_binary(
name = "zip",
entry_point = "//adev/shared-docs/pipeline:zip.mjs",
+56
View File
@@ -0,0 +1,56 @@
load("@build_bazel_rules_nodejs//:providers.bzl", "run_node")
def _generate_previews_impl(ctx):
"""Implementation of the previews generator rule"""
# File declaration of the generated ts file
ts_output = ctx.actions.declare_file("previews.ts")
# Set the arguments for the actions inputs and out put location.
args = ctx.actions.args()
# Path to the examples for which previews are being generated.
args.add(ctx.attr.example_srcs.label.package)
# Path to the preview map template.
args.add(ctx.file._template_src)
# Path to the ts output file to write to.
args.add(ts_output.path)
ctx.runfiles(files = ctx.files._template_src)
run_node(
ctx = ctx,
inputs = depset(ctx.files.example_srcs + ctx.files._template_src),
executable = "_generate_previews",
outputs = [ts_output],
arguments = [args],
)
# The return value describes what the rule is producing. In this case we need to specify
# the "DefaultInfo" with the output ts file.
return [DefaultInfo(files = depset([ts_output]))]
generate_previews = rule(
# Point to the starlark function that will execute for this rule.
implementation = _generate_previews_impl,
doc = """Rule that generates a map of example previews to their component""",
# The attributes that can be set to this rule.
attrs = {
"example_srcs": attr.label(
doc = """Files used for the previews map generation.""",
),
"_template_src": attr.label(
doc = """The previews map template file to base the generated file on.""",
default = Label("//adev/shared-docs/pipeline/examples/previews:template"),
allow_single_file = True,
),
"_generate_previews": attr.label(
default = Label("//adev/shared-docs/pipeline:previews"),
executable = True,
cfg = "exec",
),
},
)
@@ -133,7 +133,8 @@ export interface DirectiveEntry extends ClassEntry {
export interface PipeEntry extends ClassEntry {
pipeName: string;
isStandalone: boolean;
// TODO: add `isPure`.
isPure: boolean;
usage: string;
}
export interface FunctionSignatureMetadata extends DocEntry {
@@ -18,6 +18,7 @@ import {
JsDocTagEntry,
MemberEntry,
ParameterEntry,
PipeEntry,
TypeAliasEntry,
} from '../entities';
@@ -60,6 +61,12 @@ export type ClassEntryRenderable = ClassEntry &
members: MemberEntryRenderable[];
};
export type PipeEntryRenderable = PipeEntry &
DocEntryRenderable &
HasRenderableToc & {
members: MemberEntryRenderable[];
};
export type DecoratorEntryRenderable = DecoratorEntry &
DocEntryRenderable &
HasRenderableToc & {
@@ -8,6 +8,7 @@
import {Renderer, Tokens} from 'marked';
import {codeToHtml} from '../shiki/shiki';
import {SECTION_HEADING, SECTION_SUB_HEADING} from '../styling/css-classes';
/**
* Custom renderer for marked that will be used to transform markdown files to HTML
@@ -55,21 +56,39 @@ export const renderer: Partial<Renderer> = {
<div class="docs-table docs-scroll-track-transparent">
<table>
<thead>
${this.tablerow({
text: header.map((cell) => this.tablecell(cell)).join(''),
})}
${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(''),
}),
)
.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}>
`;
},
};
@@ -27,3 +27,4 @@ export const HEADER_ENTRY_LABEL = 'docs-api-item-label';
export const SECTION_CONTAINER = 'docs-reference-section';
export const SECTION_HEADING = 'docs-reference-section-heading';
export const SECTION_SUB_HEADING = 'docs-reference-section-heading--sub';
@@ -38,8 +38,6 @@ export function getCurrentSymbol(): string | undefined {
return currentSymbol;
}
export function logUnknownSymbol(link: string, symbol: string): void {
console.warn(
`WARNING: {@link ${link}} is invalid, ${symbol} or ${currentSymbol}.${symbol} is unknown in this context`,
);
export function unknownSymbolMessage(link: string, symbol: string): string {
return `WARNING: {@link ${link}} is invalid, ${symbol} or ${currentSymbol}.${symbol} is unknown in this context`;
}
@@ -7,19 +7,43 @@
*/
import {Fragment, h} from 'preact';
import {ClassEntryRenderable, DecoratorEntryRenderable} from '../entities/renderables';
import {
ClassEntryRenderable,
DecoratorEntryRenderable,
PipeEntryRenderable,
} from '../entities/renderables';
import {ClassMemberList} from './class-member-list';
import {HeaderApi} from './header-api';
import {API_REFERENCE_CONTAINER, REFERENCE_MEMBERS} from '../styling/css-classes';
import {
API_REFERENCE_CONTAINER,
REFERENCE_MEMBERS,
SECTION_CONTAINER,
} from '../styling/css-classes';
import {SectionDescription} from './section-description';
import {SectionUsageNotes} from './section-usage-notes';
import {SectionApi} from './section-api';
import {SectionHeading} from './section-heading';
import {PipeEntry} from '../entities';
import {codeToHtml} from '../shiki/shiki';
import {RawHtml} from './raw-html';
/** Component to render a class API reference document. */
export function ClassReference(entry: ClassEntryRenderable | DecoratorEntryRenderable) {
export function ClassReference(
entry: ClassEntryRenderable | DecoratorEntryRenderable | PipeEntryRenderable,
) {
return (
<div className={API_REFERENCE_CONTAINER}>
<HeaderApi entry={entry} />
{entry.entryType === 'pipe' ? (
<>
<div className={SECTION_CONTAINER + ' docs-reference-api-section'}>
<SectionHeading name="Pipe usage" />
<RawHtml value={codeToHtml((entry as PipeEntry).usage, 'angular-html')} />
</div>
</>
) : (
''
)}
<SectionApi entry={entry} />
{entry.members.length > 0 ? (
<div class={REFERENCE_MEMBERS}>
@@ -7,8 +7,8 @@
*/
import {h} from 'preact';
import {EntryType, isDocEntryWithSourceInfo} from '../entities';
import {DocEntryRenderable} from '../entities/renderables';
import {EntryType, isDocEntryWithSourceInfo, PipeEntry} from '../entities';
import {DocEntryRenderable, PipeEntryRenderable} from '../entities/renderables';
import {
HEADER_CLASS_NAME,
HEADER_ENTRY_CATEGORY,
@@ -18,16 +18,14 @@ import {
import {DocsPillRow} from './docs-pill-row';
/** Component to render a header of the API page. */
export function HeaderApi(props: {entry: DocEntryRenderable; showFullDescription?: boolean}) {
export function HeaderApi(props: {entry: DocEntryRenderable | PipeEntryRenderable; showFullDescription?: boolean}) {
const entry = props.entry;
// TODO: This link point to the main branch.
// When ADEV is not deployed on the main branch branch anymore,
// We should update it to point to the tag of the released version which ADEV runs on.
const sourceUrl = isDocEntryWithSourceInfo(entry)
? `https://github.com/angular/angular/blob/main${entry.source.filePath}#L${entry.source.startLine}-L${entry.source.endLine}`
: null;
const sourceUrl = sourceUrlForEntry(entry);
return (
<header className={HEADER_CLASS_NAME}>
@@ -40,9 +38,7 @@ export function HeaderApi(props: {entry: DocEntryRenderable; showFullDescription
{getEntryTypeDisplayName(entry.entryType)}
</div>
{entry.isDeprecated && (
<div className={`${HEADER_ENTRY_LABEL} type-deprecated full`}>
Deprecated
</div>
<div className={`${HEADER_ENTRY_LABEL} type-deprecated full`}>Deprecated</div>
)}
{entry.isDeveloperPreview && (
<div className={`${HEADER_ENTRY_LABEL} type-developer_preview full`}>
@@ -54,6 +50,12 @@ export function HeaderApi(props: {entry: DocEntryRenderable; showFullDescription
<a href="/reference/releases#experimental">Experimental</a>
</div>
)}
{entry.entryType === EntryType.Pipe && !(entry as PipeEntry).isPure && (
<div className={`${HEADER_ENTRY_LABEL} type-impure-pipe full`}>
Impure
</div>
)}
</div>
{sourceUrl && (
<a
@@ -95,3 +97,16 @@ function getEntryTypeDisplayName(entryType: EntryType | string): string {
}
return entryType;
}
function sourceUrlForEntry(entry: DocEntryRenderable): string | null {
if (!isDocEntryWithSourceInfo(entry)) {
return null;
}
if (entry.source.filePath.includes('node_modules')) {
// We don't know the source path in external repos link the CLI
return null;
} else {
return `https://github.com/angular/angular/blob/main${entry.source.filePath}#L${entry.source.startLine}-L${entry.source.endLine}`;
}
}
@@ -754,6 +754,525 @@
"startLine": 112,
"endLine": 115
}
},
{
"name": "HttpRequest",
"isAbstract": false,
"entryType": "undecorated_class",
"members": [
{
"name": "constructor",
"signatures": [
{
"name": "constructor",
"params": [
{
"name": "method",
"description": "",
"type": "\"GET\" | \"HEAD\"",
"isOptional": false,
"isRestParam": false
},
{
"name": "url",
"description": "",
"type": "string",
"isOptional": false,
"isRestParam": false
},
{
"name": "init",
"description": "",
"type": "{ headers?: HttpHeaders | undefined; context?: HttpContext | undefined; reportProgress?: boolean | undefined; params?: HttpParams | undefined; responseType?: \"arraybuffer\" | \"blob\" | \"text\" | \"json\" | undefined; withCredentials?: boolean | undefined; transferCache?: boolean | { includeHeaders?: string[] | undefined; } | undefined; } | undefined",
"isOptional": true,
"isRestParam": false
}
],
"returnType": "foobar",
"description": "",
"entryType": "function",
"jsdocTags": [],
"rawComment": "",
"generics": [],
"isNewType": false
},
{
"name": "constructor",
"params": [
{
"name": "method",
"description": "",
"type": "\"DELETE\" | \"JSONP\" | \"OPTIONS\"",
"isOptional": false,
"isRestParam": false
},
{
"name": "url",
"description": "",
"type": "string",
"isOptional": false,
"isRestParam": false
},
{
"name": "init",
"description": "",
"type": "{ headers?: HttpHeaders | undefined; context?: HttpContext | undefined; reportProgress?: boolean | undefined; params?: HttpParams | undefined; responseType?: \"arraybuffer\" | \"blob\" | \"text\" | \"json\" | undefined; withCredentials?: boolean | undefined; } | undefined",
"isOptional": true,
"isRestParam": false
}
],
"returnType": "foobar",
"description": "",
"entryType": "function",
"jsdocTags": [],
"rawComment": "",
"generics": [],
"isNewType": false
},
{
"name": "constructor",
"params": [
{
"name": "method",
"description": "",
"type": "\"POST\"",
"isOptional": false,
"isRestParam": false
},
{
"name": "url",
"description": "",
"type": "string",
"isOptional": false,
"isRestParam": false
},
{
"name": "body",
"description": "",
"type": "T | null",
"isOptional": false,
"isRestParam": false
},
{
"name": "init",
"description": "",
"type": "{ headers?: HttpHeaders | undefined; context?: HttpContext | undefined; reportProgress?: boolean | undefined; params?: HttpParams | undefined; responseType?: \"arraybuffer\" | \"blob\" | \"text\" | \"json\" | undefined; withCredentials?: boolean | undefined; transferCache?: boolean | { includeHeaders?: string[] | undefined; } | undefined; } | undefined",
"isOptional": true,
"isRestParam": false
}
],
"returnType": "foobar",
"description": "",
"entryType": "function",
"jsdocTags": [],
"rawComment": "",
"generics": [],
"isNewType": false
},
{
"name": "constructor",
"params": [
{
"name": "method",
"description": "",
"type": "\"PUT\" | \"PATCH\"",
"isOptional": false,
"isRestParam": false
},
{
"name": "url",
"description": "",
"type": "string",
"isOptional": false,
"isRestParam": false
},
{
"name": "body",
"description": "",
"type": "T | null",
"isOptional": false,
"isRestParam": false
},
{
"name": "init",
"description": "",
"type": "{ headers?: HttpHeaders | undefined; context?: HttpContext | undefined; reportProgress?: boolean | undefined; params?: HttpParams | undefined; responseType?: \"arraybuffer\" | \"blob\" | \"text\" | \"json\" | undefined; withCredentials?: boolean | undefined; } | undefined",
"isOptional": true,
"isRestParam": false
}
],
"returnType": "foobar",
"description": "",
"entryType": "function",
"jsdocTags": [],
"rawComment": "",
"generics": [],
"isNewType": false
},
{
"name": "constructor",
"params": [
{
"name": "method",
"description": "",
"type": "string",
"isOptional": false,
"isRestParam": false
},
{
"name": "url",
"description": "",
"type": "string",
"isOptional": false,
"isRestParam": false
},
{
"name": "body",
"description": "",
"type": "T | null",
"isOptional": false,
"isRestParam": false
},
{
"name": "init",
"description": "",
"type": "{ headers?: HttpHeaders | undefined; context?: HttpContext | undefined; reportProgress?: boolean | undefined; params?: HttpParams | undefined; responseType?: \"arraybuffer\" | \"blob\" | \"text\" | \"json\" | undefined; withCredentials?: boolean | undefined; transferCache?: boolean | { includeHeaders?: string[] | undefined; } | undefined; } | undefined",
"isOptional": true,
"isRestParam": false
}
],
"returnType": "foobar",
"description": "",
"entryType": "function",
"jsdocTags": [],
"rawComment": "",
"generics": [],
"isNewType": false
},
{
"name": "constructor",
"params": [
{
"name": "method",
"description": "",
"type": "string",
"isOptional": false,
"isRestParam": false
},
{
"name": "url",
"description": "",
"type": "string",
"isOptional": false,
"isRestParam": false
},
{
"name": "third",
"description": "",
"type": "T | { headers?: HttpHeaders | undefined; context?: HttpContext | undefined; reportProgress?: boolean | undefined; params?: HttpParams | undefined; responseType?: \"arraybuffer\" | \"blob\" | \"text\" | \"json\" | undefined; withCredentials?: boolean | undefined; transferCache?: boolean | { includeHeaders?: string[] | undefined; } | undefined; } | null | undefined",
"isOptional": true,
"isRestParam": false
},
{
"name": "fourth",
"description": "",
"type": "{ headers?: HttpHeaders | undefined; context?: HttpContext | undefined; reportProgress?: boolean | undefined; params?: HttpParams | undefined; responseType?: \"arraybuffer\" | \"blob\" | \"text\" | \"json\" | undefined; withCredentials?: boolean | undefined; transferCache?: boolean | { includeHeaders?: string[] | undefined; } | undefined; } | undefined",
"isOptional": true,
"isRestParam": false
}
],
"returnType": "foobar",
"description": "",
"entryType": "function",
"jsdocTags": [],
"rawComment": "",
"generics": [],
"isNewType": false
}
],
"implementation": {
"params": [
{
"name": "method",
"description": "",
"type": "string",
"isOptional": false,
"isRestParam": false
},
{
"name": "url",
"description": "",
"type": "string",
"isOptional": false,
"isRestParam": false
},
{
"name": "third",
"description": "",
"type": "T | { headers?: HttpHeaders | undefined; context?: HttpContext | undefined; reportProgress?: boolean | undefined; params?: HttpParams | undefined; responseType?: \"arraybuffer\" | \"blob\" | \"text\" | \"json\" | undefined; withCredentials?: boolean | undefined; transferCache?: boolean | { includeHeaders?: string[] | undefined; } | undefined; } | null | undefined",
"isOptional": true,
"isRestParam": false
},
{
"name": "fourth",
"description": "",
"type": "{ headers?: HttpHeaders | undefined; context?: HttpContext | undefined; reportProgress?: boolean | undefined; params?: HttpParams | undefined; responseType?: \"arraybuffer\" | \"blob\" | \"text\" | \"json\" | undefined; withCredentials?: boolean | undefined; transferCache?: boolean | { includeHeaders?: string[] | undefined; } | undefined; } | undefined",
"isOptional": true,
"isRestParam": false
}
],
"isNewType": false,
"returnType": "HttpRequest<T>",
"generics": [],
"name": "constructor",
"description": "",
"entryType": "function",
"jsdocTags": [],
"rawComment": ""
},
"entryType": "function",
"description": "",
"jsdocTags": [],
"rawComment": "",
"memberType": "method",
"memberTags": []
},
{
"name": "body",
"type": "T | null",
"memberType": "property",
"memberTags": ["readonly"],
"description": "The request body, or `null` if one isn't set.\n\nBodies are not enforced to be immutable, as they can include a reference to any\nuser-defined data type. However, interceptors should take care to preserve\nidempotence by treating them as such.",
"jsdocTags": []
},
{
"name": "headers",
"type": "HttpHeaders",
"memberType": "property",
"memberTags": ["readonly"],
"description": "Outgoing headers for this request.",
"jsdocTags": []
},
{
"name": "context",
"type": "HttpContext",
"memberType": "property",
"memberTags": ["readonly"],
"description": "Shared and mutable context that can be used by interceptors",
"jsdocTags": []
},
{
"name": "reportProgress",
"type": "boolean",
"memberType": "property",
"memberTags": ["readonly"],
"description": "Whether this request should be made in a way that exposes progress events.\n\nProgress events are expensive (change detection runs on each event) and so\nthey should only be requested if the consumer intends to monitor them.\n\nNote: The `FetchBackend` doesn't support progress report on uploads.",
"jsdocTags": []
},
{
"name": "withCredentials",
"type": "boolean",
"memberType": "property",
"memberTags": ["readonly"],
"description": "Whether this request should be sent with outgoing credentials (cookies).",
"jsdocTags": []
},
{
"name": "responseType",
"type": "\"arraybuffer\" | \"blob\" | \"text\" | \"json\"",
"memberType": "property",
"memberTags": ["readonly"],
"description": "The expected response type of the server.\n\nThis is used to parse the response appropriately before returning it to\nthe requestee.",
"jsdocTags": []
},
{
"name": "method",
"type": "string",
"memberType": "property",
"memberTags": ["readonly"],
"description": "The outgoing HTTP request method.",
"jsdocTags": []
},
{
"name": "params",
"type": "HttpParams",
"memberType": "property",
"memberTags": ["readonly"],
"description": "Outgoing URL parameters.\n\nTo pass a string representation of HTTP parameters in the URL-query-string format,\nthe `HttpParamsOptions`' `fromString` may be used. For example:\n\n```ts\nnew HttpParams({fromString: 'angular=awesome'})\n```",
"jsdocTags": []
},
{
"name": "urlWithParams",
"type": "string",
"memberType": "property",
"memberTags": ["readonly"],
"description": "The outgoing URL with all URL parameters set.",
"jsdocTags": []
},
{
"name": "transferCache",
"type": "boolean | { includeHeaders?: string[] | undefined; } | undefined",
"memberType": "property",
"memberTags": ["readonly", "optional"],
"description": "The HttpTransferCache option for the request",
"jsdocTags": []
},
{
"name": "serializeBody",
"signatures": [
{
"name": "serializeBody",
"entryType": "function",
"description": "Transform the free-form body into a serialized format suitable for\ntransmission to the server.",
"generics": [],
"isNewType": false,
"jsdocTags": [],
"params": [],
"rawComment": "/**\n * Transform the free-form body into a serialized format suitable for\n * transmission to the server.\n */",
"returnType": "string | ArrayBuffer | Blob | FormData | URLSearchParams | null"
}
],
"implementation": {
"params": [],
"isNewType": false,
"returnType": "string | ArrayBuffer | Blob | FormData | URLSearchParams | null",
"generics": [],
"name": "serializeBody",
"description": "Transform the free-form body into a serialized format suitable for\ntransmission to the server.",
"entryType": "function",
"jsdocTags": [],
"rawComment": "/**\n * Transform the free-form body into a serialized format suitable for\n * transmission to the server.\n */"
},
"entryType": "function",
"description": "Transform the free-form body into a serialized format suitable for\ntransmission to the server.",
"jsdocTags": [],
"rawComment": "/**\n * Transform the free-form body into a serialized format suitable for\n * transmission to the server.\n */",
"memberType": "method",
"memberTags": []
},
{
"name": "detectContentTypeHeader",
"signatures": [
{
"name": "detectContentTypeHeader",
"entryType": "function",
"description": "Examine the body and attempt to infer an appropriate MIME type\nfor it.\n\nIf no such type can be inferred, this method will return `null`.",
"generics": [],
"isNewType": false,
"jsdocTags": [],
"params": [],
"rawComment": "/**\n * Examine the body and attempt to infer an appropriate MIME type\n * for it.\n *\n * If no such type can be inferred, this method will return `null`.\n */",
"returnType": "string | null"
}
],
"implementation": {
"params": [],
"isNewType": false,
"returnType": "string | null",
"generics": [],
"name": "detectContentTypeHeader",
"description": "Examine the body and attempt to infer an appropriate MIME type\nfor it.\n\nIf no such type can be inferred, this method will return `null`.",
"entryType": "function",
"jsdocTags": [],
"rawComment": "/**\n * Examine the body and attempt to infer an appropriate MIME type\n * for it.\n *\n * If no such type can be inferred, this method will return `null`.\n */"
},
"entryType": "function",
"description": "Examine the body and attempt to infer an appropriate MIME type\nfor it.\n\nIf no such type can be inferred, this method will return `null`.",
"jsdocTags": [],
"rawComment": "/**\n * Examine the body and attempt to infer an appropriate MIME type\n * for it.\n *\n * If no such type can be inferred, this method will return `null`.\n */",
"memberType": "method",
"memberTags": []
},
{
"name": "clone",
"signatures": [
{
"name": "clone",
"entryType": "function",
"description": "",
"generics": [],
"isNewType": false,
"jsdocTags": [],
"params": [],
"rawComment": "",
"returnType": "HttpRequest<T>"
},
{
"name": "clone",
"entryType": "function",
"description": "",
"generics": [],
"isNewType": false,
"jsdocTags": [],
"params": [
{
"name": "update",
"description": "",
"type": "{ headers?: HttpHeaders | undefined; context?: HttpContext | undefined; reportProgress?: boolean | undefined; params?: HttpParams | undefined; responseType?: \"arraybuffer\" | \"blob\" | \"text\" | \"json\" | undefined; withCredentials?: boolean | undefined; transferCache?: boolean | { includeHeaders?: string[] | undefined; } | undefined; body?: T | null | undefined; method?: string | undefined; url?: string | undefined; setHeaders?: { [name: string]: string | string[]; } | undefined; setParams?: { [param: string]: string; } | undefined; }",
"isOptional": false,
"isRestParam": false
}
],
"rawComment": "",
"returnType": "HttpRequest<T>"
},
{
"name": "clone",
"entryType": "function",
"description": "",
"generics": [{"name": "V"}],
"isNewType": false,
"jsdocTags": [],
"params": [
{
"name": "update",
"description": "",
"type": "{ headers?: HttpHeaders | undefined; context?: HttpContext | undefined; reportProgress?: boolean | undefined; params?: HttpParams | undefined; responseType?: \"arraybuffer\" | \"blob\" | \"text\" | \"json\" | undefined; withCredentials?: boolean | undefined; transferCache?: boolean | { includeHeaders?: string[] | undefined; } | undefined; body?: V | null | undefined; method?: string | undefined; url?: string | undefined; setHeaders?: { [name: string]: string | string[]; } | undefined; setParams?: { [param: string]: string; } | undefined; }",
"isOptional": false,
"isRestParam": false
}
],
"rawComment": "",
"returnType": "HttpRequest<V>"
}
],
"implementation": {
"params": [
{
"name": "update",
"description": "",
"type": "{ headers?: HttpHeaders | undefined; context?: HttpContext | undefined; reportProgress?: boolean | undefined; params?: HttpParams | undefined; responseType?: \"arraybuffer\" | \"blob\" | \"text\" | \"json\" | undefined; withCredentials?: boolean | undefined; transferCache?: boolean | { includeHeaders?: string[] | undefined; } | undefined; body?: any; method?: string | undefined; url?: string | undefined; setHeaders?: { [name: string]: string | string[]; } | undefined; setParams?: { [param: string]: string; } | undefined; }",
"isOptional": true,
"isRestParam": false
}
],
"isNewType": false,
"returnType": "HttpRequest<any>",
"generics": [],
"name": "clone",
"description": "",
"entryType": "function",
"jsdocTags": [],
"rawComment": ""
},
"entryType": "function",
"description": "",
"jsdocTags": [],
"rawComment": "",
"memberType": "method",
"memberTags": []
}
],
"generics": [{"name": "T"}],
"description": "An outgoing HTTP request with an optional typed body.\n\n`HttpRequest` represents an outgoing request, including URL, method,\nheaders, body, and other request configuration options. Instances should be\nassumed to be immutable. To modify a `HttpRequest`, the `clone`\nmethod should be used.",
"jsdocTags": [{"name": "publicApi", "comment": ""}],
"rawComment": "/**\n * An outgoing HTTP request with an optional typed body.\n *\n * `HttpRequest` represents an outgoing request, including URL, method,\n * headers, body, and other request configuration options. Instances should be\n * assumed to be immutable. To modify a `HttpRequest`, the `clone`\n * method should be used.\n *\n * @publicApi\n */",
"implements": [],
"source": {
"filePath": "/packages/common/http/src/request.ts",
"startLine": 131,
"endLine": 578
}
}
]
}
@@ -34,6 +34,13 @@ describe('markdown to html', () => {
const symbols = new Map<string, string>([
['AfterRenderPhase', 'core'],
['afterRender', 'core'],
['EmbeddedViewRef', 'core'],
['ChangeDetectionStrategy', 'core'],
['ChangeDetectorRef', 'core'],
['withNoHttpTransferCache', 'platform-browser'],
['withHttpTransferCacheOptions', 'platform-browser'],
['withI18nSupport', 'platform-browser'],
['withEventReplay', 'platform-browser'],
]);
setSymbols(symbols);
for (const entry of entryJson.entries) {
@@ -12,6 +12,7 @@ import {getRenderable} from '../processing';
import {DocEntryRenderable} from '../entities/renderables';
import {initHighlighter} from '../shiki/shiki';
import {configureMarkedGlobally} from '../marked/configuration';
import {setSymbols} from '../symbol-context';
// 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.
@@ -28,6 +29,19 @@ describe('renderable', () => {
encoding: 'utf-8',
});
const entryJson = JSON.parse(entryContent) as any;
const symbols = new Map<string, string>([
['AfterRenderPhase', 'core'],
['afterRender', 'core'],
['EmbeddedViewRef', 'core'],
['ChangeDetectionStrategy', 'core'],
['ChangeDetectorRef', 'core'],
['withNoHttpTransferCache', 'platform-browser'],
['withHttpTransferCacheOptions', 'platform-browser'],
['withI18nSupport', 'platform-browser'],
['withEventReplay', 'platform-browser'],
]);
setSymbols(symbols);
for (const entry of entryJson.entries) {
const renderableJson = getRenderable(entry, '@angular/fakeentry') as DocEntryRenderable;
entries.set(entry['name'], renderableJson);
@@ -66,6 +66,14 @@ describe('jsdoc transforms', () => {
name: 'see',
comment: '{@link https://angular.dev}',
},
{
name: 'see',
comment: '{@link /cli/build ng build}',
},
{
name: 'see',
comment: '{@link /ecosystem/rxjs-interop/output-interop Output Interop}',
},
],
moduleName: 'test',
});
@@ -117,5 +125,30 @@ describe('jsdoc transforms', () => {
label: 'angular.dev',
url: 'https://angular.dev',
});
expect(entry.additionalLinks[10]).toEqual({
label: 'ng build',
url: '/cli/build',
});
expect(entry.additionalLinks[11]).toEqual({
label: 'Output Interop',
url: '/ecosystem/rxjs-interop/output-interop',
});
});
it('should throw on invalid relatie @link', () => {
const entryFn = () =>
addHtmlAdditionalLinks({
jsdocTags: [
{
name: 'see',
comment: '{@link cli/build ng build}',
},
],
moduleName: 'test',
});
expect(entryFn).toThrowError(/Forbidden relative link: cli\/build ng build/);
});
});
@@ -476,10 +476,11 @@ function appendPrefixAndSuffix(entry: DocEntry, codeTocData: CodeTableOfContents
*/
export function addApiLinksToHtml(htmlString: string): string {
const result = htmlString.replace(
// This regex looks for span/code blocks not wrapped by an anchor block.
// This regex looks for span/code blocks not wrapped by an anchor block
// or the tag doesn't contain `data-skip-anchor` attribute.
// Their content are then replaced with a link if the symbol is known
// The captured content ==> vvvvvvvv
/(?<!<a[^>]*>)(<(?:(?:span)|(?:code))[^>]*>\s*)([^<]*?)(\s*<\/(?:span|code)>)/g,
// The captured content ==> vvvvvvvv
/(?<!<a[^>]*>)(<(?:(?:span)|(?:code))(?!\sdata-skip-anchor)[^>]*>\s*)([^<]*?)(\s*<\/(?:span|code)>)/g,
(type: string, span1: string, potentialSymbolName: string, span2: string) => {
let [symbol, subSymbol] = potentialSymbolName.split(/(?:#|\.)/) as [string, string?];
@@ -31,10 +31,9 @@ import {
import {getLinkToModule} from './url-transforms';
import {addApiLinksToHtml} from './code-transforms';
import {getCurrentSymbol, getModuleName, logUnknownSymbol} from '../symbol-context';
import {getCurrentSymbol, getModuleName, unknownSymbolMessage} from '../symbol-context';
export const JS_DOC_REMARKS_TAG = 'remarks';
export const JS_DOC_USAGE_NOTES_TAG = 'usageNotes';
const JS_DOC_USAGE_NOTE_TAGS: Set<string> = new Set(['remarks', 'usageNotes', 'example']);
export const JS_DOC_SEE_TAG = 'see';
export const JS_DOC_DESCRIPTION_TAG = 'description';
@@ -58,16 +57,10 @@ export function addHtmlDescription<T extends HasDescription & HasModuleName>(
const description = !!entry.description ? entry.description : jsDocDescription;
const shortTextMatch = description.match(firstParagraphRule);
const htmlDescription = getHtmlForJsDocText(description, entry).trim();
const shortHtmlDescription = getHtmlForJsDocText(
shortTextMatch ? shortTextMatch[0] : '',
entry,
).trim();
return {
...entry,
htmlDescription,
shortHtmlDescription,
};
const htmlDescription = getHtmlForJsDocText(description).trim();
const shortHtmlDescription = getHtmlForJsDocText(shortTextMatch ? shortTextMatch[0] : '').trim();
return {...entry, htmlDescription, shortHtmlDescription};
}
/**
@@ -81,7 +74,7 @@ export function addHtmlJsDocTagComments<T extends HasJsDocTags & HasModuleName>(
...entry,
jsdocTags: entry.jsdocTags.map((tag) => ({
...tag,
htmlComment: getHtmlForJsDocText(tag.comment, entry),
htmlComment: getHtmlForJsDocText(tag.comment),
})),
};
}
@@ -97,23 +90,20 @@ export function addHtmlAdditionalLinks<T extends HasJsDocTags & HasModuleName>(
}
export function addHtmlUsageNotes<T extends HasJsDocTags>(entry: T): T & HasHtmlUsageNotes {
const usageNotesTag = entry.jsdocTags.find(
({name}) => name === JS_DOC_USAGE_NOTES_TAG || name === JS_DOC_REMARKS_TAG,
);
const htmlUsageNotes = usageNotesTag
? (marked.parse(wrapExampleHtmlElementsWithCode(usageNotesTag.comment)) as string)
: '';
const transformedHtml = addApiLinksToHtml(htmlUsageNotes);
const usageNotesTags = entry.jsdocTags.filter(({name}) => JS_DOC_USAGE_NOTE_TAGS.has(name)) ?? [];
let htmlUsageNotes = '';
for (const {comment} of usageNotesTags) {
htmlUsageNotes += getHtmlForJsDocText(comment);
}
return {
...entry,
htmlUsageNotes: transformedHtml,
htmlUsageNotes,
};
}
/** Given a markdown JsDoc text, gets the rendered HTML. */
function getHtmlForJsDocText<T extends HasModuleName>(text: string, entry: T): string {
function getHtmlForJsDocText(text: string): string {
const parsed = marked.parse(convertLinks(wrapExampleHtmlElementsWithCode(text))) as string;
return addApiLinksToHtml(parsed);
}
@@ -126,7 +116,7 @@ export function setEntryFlags<T extends HasJsDocTags & HasModuleName>(
...entry,
isDeprecated: isDeprecatedEntry(entry),
deprecationMessage: deprecationMessage
? getHtmlForJsDocText(deprecationMessage, entry)
? getHtmlForJsDocText(deprecationMessage)
: deprecationMessage,
isDeveloperPreview: isDeveloperPreview(entry),
isExperimental: isExperimental(entry),
@@ -195,10 +185,16 @@ function parseAtLink(link: string): {label: string; url: string} {
let [rawSymbol, description] = link.split(/\s(.+)/);
if (rawSymbol.startsWith('#')) {
rawSymbol = rawSymbol.substring(1);
} else if (rawSymbol.startsWith('http://') || rawSymbol.startsWith('https://')) {
} else if (rawSymbol.includes('/')) {
if (!rawSymbol.startsWith('/') && !rawSymbol.startsWith('http')) {
throw Error(
`Forbidden relative link: ${link}. Links should be absolute and start with a slash`,
);
}
return {
url: rawSymbol,
label: rawSymbol.split('/').pop()!,
label: description ?? rawSymbol.split('/').pop()!,
};
}
@@ -214,11 +210,9 @@ function parseAtLink(link: string): {label: string; url: string} {
moduleName = getModuleName(`${currentSymbol}.${symbol}`);
if (!moduleName || !currentSymbol) {
// TODO: remove the links that generate this error
// TODO: throw an error when there are no more warning generated
logUnknownSymbol(link, symbol);
return {label, url: '#'};
throw unknownSymbolMessage(link, symbol);
}
subSymbol = symbol;
symbol = currentSymbol;
}
@@ -0,0 +1,29 @@
load("//tools:defaults.bzl", "ts_library")
package(default_visibility = ["//visibility:public"])
ts_library(
name = "index",
srcs = [
"index.ts",
],
visibility = [
"//adev/shared-docs:__subpackages__",
],
deps = [
"@npm//@types/node",
"@npm//tinyglobby",
"@npm//typescript",
],
)
filegroup(
name = "template",
srcs = ["previews.template"],
visibility = ["//visibility:public"],
)
exports_files([
"index.ts",
"previews.template",
])
@@ -0,0 +1,139 @@
/*!
* @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 fs from 'fs';
import {readFile, writeFile} from 'fs/promises';
import {join, relative} from 'path';
import {glob} from 'tinyglobby';
import ts from 'typescript';
const [examplesDir, templateFilePath, outputFilePath] = process.argv.slice(2);
const EXAMPLES_PATH = `../../content/examples`;
interface File {
path: string;
content: string;
}
interface AnalyzedFiles {
path: string;
componentNames: string[];
}
main();
/**
* Creates a map of example path to dynamic component import for loading embedded examples.
*
* For example, given the following inputs:
* examplesDir: 'adev/src/content/examples',
* templateFilePath: 'adev/shared-docs/pipeline/examples/previews/previews.template',
* outputFilePath: 'bazel-out/k8-fastbuild/bin/adev/src/assets/previews/previews.ts'
*
* The script will generate a mapping of all example components under adev/src/content/examples and
* fill them into the given template file, writing the result to the output file.
*
* It will replace the placeholder text `${previewsComponents}` in the template with mappings like:
* ['adev/src/content/examples/accessibility/src/app/app.component.ts']:
* () => import('../../content/examples/accessibility/src/app/app.component').then(c => c.AppComponent),
* ['adev/src/content/examples/accessibility/src/app/progress-bar.component.ts']:
* () => import('../../content/examples/accessibility/src/app/progress-bar.component').then(c => c.ExampleProgressbarComponent),
* ...
*/
async function main() {
const files = await glob(join(examplesDir, '**/*.ts'), {
ignore: ['**/*.e2e-spec.ts', '**/*.spec.ts', '**/*.po.ts'],
}).then((paths) =>
Promise.all(
paths.map((path) =>
readFile(path, {encoding: 'utf-8'}).then((fileContent) => {
return {
path: relative(examplesDir, path),
content: fileContent,
};
}),
),
),
);
const filesWithComponent = files
.map((file) => ({
componentNames: analyzeFile(file),
path: file.path,
}))
.filter((result) => result.componentNames.length > 0);
const previewsComponentMap = generatePreviewsComponentMap(filesWithComponent);
await writeFile(outputFilePath, previewsComponentMap);
}
/** Returns list of the `Standalone` @Component class names for given file */
function analyzeFile(file: File): string[] {
const componentClassNames: string[] = [];
const sourceFile = ts.createSourceFile(file.path, file.content, ts.ScriptTarget.Latest, false);
const visitNode = (node: ts.Node): void => {
if (ts.isClassDeclaration(node)) {
const decorators = ts.getDecorators(node);
const componentName = node.name ? node.name.text : null;
if (decorators && decorators.length) {
for (const decorator of decorators) {
const call = decorator.expression;
if (
ts.isCallExpression(call) &&
ts.isIdentifier(call.expression) &&
call.expression.text === 'Component' &&
call.arguments.length > 0 &&
ts.isObjectLiteralExpression(call.arguments[0])
) {
const standaloneProperty = call.arguments[0].properties.find(
(property) =>
property.name &&
ts.isIdentifier(property.name) &&
property.name.text === 'standalone',
);
const isStandalone =
!standaloneProperty ||
(ts.isPropertyAssignment(standaloneProperty) &&
standaloneProperty.initializer.kind === ts.SyntaxKind.TrueKeyword);
if (isStandalone && componentName) {
componentClassNames.push(componentName);
}
}
}
}
}
ts.forEachChild(node, visitNode);
};
visitNode(sourceFile);
return componentClassNames;
}
function generatePreviewsComponentMap(data: AnalyzedFiles[]): string {
let result = '';
for (const fileData of data) {
for (const componentName of fileData.componentNames) {
const key = `adev/src/content/examples/${fileData.path}${
fileData.componentNames.length > 1 ? '_' + componentName : ''
}`.replace(/\\/g, '/');
result += `['${key}']: () => import('${EXAMPLES_PATH}/${fileData.path
.replace(/\\/g, '/')
.replace('.ts', '')}').then(c => c.${componentName}),\n`;
}
}
return fs.readFileSync(templateFilePath, 'utf8').replace(/\${previewsComponents}/g, result);
}
@@ -6,16 +6,12 @@
* found in the LICENSE file at https://angular.dev/license
*/
/**
******************************************************************************
* DO NOT MANUALLY EDIT THIS FILE. THIS FILE IS AUTOMATICALLY GENERATED.
******************************************************************************
*/
import {Type} from '@angular/core';
/**
* Map of the previews components, values are functions which returns the promise of the component type, which will be displayed as preview in the ExampleViewer component.
* Keys has to be equal to paths written down in the docs markdown files.
*/
export const PREVIEWS_COMPONENTS_MAP: Record<string, () => Promise<Type<unknown>>> = {};
export const PREVIEWS_COMPONENTS_MAP: Record<string, () => Promise<Type<unknown>>> = {
${previewsComponents}
};
@@ -21,7 +21,7 @@
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"builder": "@angular/build:application",
"options": {
"outputPath": "dist/example-app",
"index": "src/index.html",
@@ -66,7 +66,7 @@
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"builder": "@angular/build:dev-server",
"configurations": {
"production": {
"browserTarget": "example-app:build:production"
@@ -78,13 +78,13 @@
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"builder": "@angular/build:extract-i18n",
"options": {
"browserTarget": "example-app:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"builder": "@angular/build:karma",
"options": {
"main": "src/test.ts",
"polyfills": ["zone.js", "zone.js/testing"],
@@ -23,7 +23,7 @@
"zone.js": "~0.13.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^19.0.0",
"@angular/build": "^19.0.0",
"@angular/cli": "^19.0.0",
"@angular/compiler-cli": "^19.0.0",
"@types/jasmine": "~3.10.0",
@@ -10,12 +10,12 @@ import {RendererThis, Token, TokenizerThis, Tokens} from 'marked';
/** Enum of all available alert severities. */
export enum AlertSeverityLevel {
Note = 'NOTE',
Tip = 'TIP',
NOTE = 'NOTE',
TIP = 'TIP',
TODO = 'TODO',
QUESTION = 'QUESTION',
Summary = 'SUMMARY',
TLDR = 'TLDR',
SUMMARY = 'SUMMARY',
TLDR = 'TL;DR',
CRITICAL = 'CRITICAL',
IMPORTANT = 'IMPORTANT',
HELPFUL = 'HELPFUL',
@@ -39,14 +39,14 @@ export const docsAlertExtension = {
level: 'block' as const,
tokenizer(this: TokenizerThis, src: string): DocsAlertToken | undefined {
let match: DocsAlert | undefined;
for (let level in AlertSeverityLevel) {
for (const key of Object.keys(AlertSeverityLevel)) {
// Capture group 1: all alert text content after the severity level
const rule = new RegExp('^s*' + level + ': (.*?)\n(\n|$)', 's');
const rule = new RegExp('^s*' + key + ': (.*?)\n(\n|$)', 's');
const possibleMatch = rule.exec(src);
if (possibleMatch?.[1]) {
match = {
severityLevel: level,
severityLevel: key,
alert: possibleMatch,
};
}
@@ -57,12 +57,11 @@ export const docsAlertExtension = {
type: 'docs-alert',
raw: match.alert[0],
body: match.alert[1].trim(),
severityLevel: match.severityLevel,
severityLevel: match.severityLevel.toLowerCase(),
tokens: [],
};
token.body = `**${
token.severityLevel === AlertSeverityLevel.TLDR ? 'TL;DR' : token.severityLevel
}:** ${token.body}`;
token.body = `**${AlertSeverityLevel[match.severityLevel as keyof typeof AlertSeverityLevel]}:** ${token.body}`;
this.lexer.blockTokens(token.body, token.tokens);
return token;
}
@@ -1,13 +1,13 @@
Note: Use Note for ancillary/additional information that's not _essential_ to the main text.
NOTE: Use Note for ancillary/additional information that's not _essential_ to the main text.
This is a multiline note
Tip: Use Tip to call out a specific task/action users can perform, or a fact that plays directly into a task/action.
TIP: Use Tip to call out a specific task/action users can perform, or a fact that plays directly into a task/action.
TODO: Use TODO for incomplete documentation that you plan to expand soon. You can also assign the TODO, e.g. TODO(emmatwersky): Text.
QUESTION: Use Question to pose a question to the reader, kind of like a mini-quiz that they should be able to answer.
Summary: Use Summary to provide a two- or three-sentence synopsis of the page or section content, so readers can figure out whether this is the right place for them.
SUMMARY: Use Summary to provide a two- or three-sentence synopsis of the page or section content, so readers can figure out whether this is the right place for them.
TLDR: Use TLDR if you can provide the essential information about a page or section in a sentence or two.
@@ -24,15 +24,10 @@ describe('markdown to html', () => {
markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, {}));
});
for (let level in AlertSeverityLevel) {
it(`should create a docs-alert for ${level}:`, () => {
const noteEl = markdownDocument.querySelector(`.docs-alert-${level.toLowerCase()}`);
// TLDR is written without a semi colon in the markdown, but is rendered
// with a colon, as such we have to adjust our expectation here.
if (level === AlertSeverityLevel.TLDR) {
level = 'TL;DR';
}
expect(noteEl?.textContent?.trim()).toMatch(`^${level}:`);
for (const [key, level] of Object.entries(AlertSeverityLevel)) {
it(`should create a docs-alert for ${key}:`, () => {
const noteEl = markdownDocument.querySelector(`.docs-alert-${key.toLowerCase()}`);
expect(noteEl?.textContent?.trim()).toMatch(new RegExp(`^${level}:`));
});
}
@@ -39,7 +39,7 @@
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"builder": "@angular/build:application",
"options": {
"outputPath": "dist/first-app",
"index": "src/index.html",
@@ -76,7 +76,7 @@
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"builder": "@angular/build:dev-server",
"configurations": {
"production": {
"buildTarget": "first-app:build:production"
@@ -88,7 +88,7 @@
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"builder": "@angular/build:extract-i18n",
"options": {
"buildTarget": "first-app:build"
}
File diff suppressed because it is too large Load Diff
@@ -3,7 +3,7 @@
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "NG_BUILD_PARALLEL_TS=0 ng serve",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development"
},
@@ -15,12 +15,12 @@
"@angular/platform-browser": "^19.0.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.14.0"
"zone.js": "~0.15.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^19.0.0",
"@angular/build": "^19.0.0",
"@angular/cli": "^19.0.0",
"@angular/compiler-cli": "^19.0.0",
"typescript": "~5.6.3"
"typescript": "~5.7.3"
}
}
-1
View File
@@ -25,7 +25,6 @@ ng_module(
],
),
deps = [
"//adev/shared-docs/constants",
"//adev/shared-docs/interfaces",
"//adev/shared-docs/providers",
"//adev/shared-docs/utils",
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.dev/license
*/
import {Injectable, inject, signal} from '@angular/core';
import {Injectable, inject, linkedSignal, signal} from '@angular/core';
import {NavigationItem} from '../interfaces/index';
import {Router} from '@angular/router';
@@ -19,11 +19,13 @@ export class NavigationState {
private readonly _activeNavigationItem = signal<NavigationItem | null>(null);
private readonly _expandedItems = signal<NavigationItem[]>([]);
private readonly _isMobileNavVisible = signal<boolean>(false);
private readonly _level = linkedSignal(() => this._expandedItems().length);
primaryActiveRouteItem = signal<string | null>(null);
activeNavigationItem = this._activeNavigationItem.asReadonly();
expandedItems = this._expandedItems.asReadonly();
isMobileNavVisible = this._isMobileNavVisible.asReadonly();
level = this._level.asReadonly();
async toggleItem(item: NavigationItem): Promise<void> {
if (!item.children) {
@@ -59,7 +61,7 @@ export class NavigationState {
return;
}
// Returns item when parent node was already expanded
const parentItem = this._expandedItems().find(
const parentItem = this.actualExpandedItems().find(
(expandedItem) =>
item.parent?.label === expandedItem.label && item.parent?.path === expandedItem.path,
);
@@ -100,13 +102,25 @@ export class NavigationState {
private expand(item: NavigationItem): void {
// Add item to the expanded items list
this._expandedItems.update((expandedItems) => {
return [...(expandedItems ?? []), {...item, isExpanded: true}];
return [...(this.actualExpandedItems() ?? []), {...item, isExpanded: true}];
});
// No need to update the level here, this is handled by linkedSignal already
}
private collapse(item: NavigationItem): void {
item.isExpanded = false;
this._expandedItems.update((expandedItems) => expandedItems.slice(0, -1));
// We won't remove the item, just update the level,
// this allows animation on the items to hide them without destroying them
this._level.set(this.actualExpandedItems().length - 1);
}
/**
* return the actual navigation items, that is to say the one that match the current level
*/
private actualExpandedItems() {
return this.expandedItems().slice(0, this.level());
}
private async navigateToFirstPageOfTheCategory(path: string): Promise<boolean> {
+194 -76
View File
@@ -6,95 +6,105 @@
* found in the LICENSE file at https://angular.dev/license
*/
import {Injectable, afterNextRender, inject, signal} from '@angular/core';
import {ENVIRONMENT} from '../providers/index';
import {SearchResult} from '../interfaces/index';
import {toObservable} from '@angular/core/rxjs-interop';
import {debounceTime, filter, from, of, switchMap} from 'rxjs';
import {liteClient as algoliasearch} from 'algoliasearch/lite';
import {
DestroyRef,
Injectable,
InjectionToken,
Provider,
ResourceRef,
inject,
resource,
signal,
} from '@angular/core';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {NavigationEnd, Router} from '@angular/router';
import {ENVIRONMENT} from '../providers/index';
import type {Environment, SearchResult, SearchResultItem, SnippetResult} from '../interfaces/index';
import {filter} from 'rxjs';
import {
liteClient as algoliasearch,
SearchResponses,
SearchResult as AlgoliaSearchResult,
Hit,
} from 'algoliasearch/lite';
export const SEARCH_DELAY = 200;
// Maximum number of facet values to return for each facet during a regular search.
export const MAX_VALUE_PER_FACET = 5;
export const ALGOLIA_CLIENT = new InjectionToken<ReturnType<typeof algoliasearch>>(
'Search service',
);
export const provideAlgoliaSearchClient = (config: Environment): Provider => {
return {
provide: ALGOLIA_CLIENT,
useFactory: () => algoliasearch(config.algolia.appId, config.algolia.apiKey),
};
};
@Injectable({
providedIn: 'root',
})
export class Search {
private readonly _searchQuery = signal('');
private readonly _searchResults = signal<undefined | SearchResult[]>(undefined);
readonly searchQuery = signal('');
private readonly destroyRef = inject(DestroyRef);
private readonly router = inject(Router);
private readonly config = inject(ENVIRONMENT);
private readonly client = algoliasearch(this.config.algolia.appId, this.config.algolia.apiKey);
private readonly client = inject(ALGOLIA_CLIENT);
searchQuery = this._searchQuery.asReadonly();
searchResults = this._searchResults.asReadonly();
searchResults = resource({
request: () => this.searchQuery() || undefined, // coerces empty string to undefined
loader: async ({request: query, abortSignal}) => {
// Until we have a better alternative we debounce by awaiting for a short delay.
await wait(SEARCH_DELAY, abortSignal);
searchResults$ = toObservable(this.searchQuery).pipe(
debounceTime(SEARCH_DELAY),
switchMap((query) => {
return !!query
? from(
this.client.search([
{
indexName: this.config.algolia.indexName,
params: {
query: query,
maxValuesPerFacet: MAX_VALUE_PER_FACET,
attributesToRetrieve: [
'hierarchy.lvl0',
'hierarchy.lvl1',
'hierarchy.lvl2',
'hierarchy.lvl3',
'hierarchy.lvl4',
'hierarchy.lvl5',
'hierarchy.lvl6',
'content',
'type',
'url',
],
hitsPerPage: 20,
snippetEllipsisText: '…',
highlightPreTag: '<ɵ>',
highlightPostTag: '</ɵ>',
attributesToHighlight: [],
attributesToSnippet: [
'hierarchy.lvl1:10',
'hierarchy.lvl2:10',
'hierarchy.lvl3:10',
'hierarchy.lvl4:10',
'hierarchy.lvl5:10',
'hierarchy.lvl6:10',
'content:10',
],
},
type: 'default',
},
]),
)
: of(undefined);
}),
);
return this.client
.search([
{
indexName: this.config.algolia.indexName,
params: {
query: query,
maxValuesPerFacet: MAX_VALUE_PER_FACET,
attributesToRetrieve: [
'hierarchy.lvl0',
'hierarchy.lvl1',
'hierarchy.lvl2',
'hierarchy.lvl3',
'hierarchy.lvl4',
'hierarchy.lvl5',
'hierarchy.lvl6',
'content',
'type',
'url',
],
hitsPerPage: 20,
snippetEllipsisText: '…',
highlightPreTag: '<ɵ>',
highlightPostTag: '</ɵ>',
attributesToHighlight: [],
attributesToSnippet: [
'hierarchy.lvl1:10',
'hierarchy.lvl2:10',
'hierarchy.lvl3:10',
'hierarchy.lvl4:10',
'hierarchy.lvl5:10',
'hierarchy.lvl6:10',
'content:10',
],
},
type: 'default',
},
])
.then((response: SearchResponses<unknown>) => {
return this.parseResult(response);
});
},
});
constructor() {
afterNextRender(() => {
this.listenToSearchResults();
this.resetSearchQueryOnNavigationEnd();
});
}
updateSearchQuery(query: string): void {
this._searchQuery.set(query);
}
private listenToSearchResults(): void {
this.searchResults$.subscribe((response: any) => {
this._searchResults.set(
response ? this.getUniqueSearchResultItems(response.results[0].hits) : undefined,
);
});
this.resetSearchQueryOnNavigationEnd();
}
private getUniqueSearchResultItems(items: SearchResult[]): SearchResult[] {
@@ -115,8 +125,9 @@ export class Search {
) {
return false;
}
if (item.url && !uniqueUrls.has(item.url)) {
uniqueUrls.add(item.url);
if (item['url'] && typeof item['url'] === 'string' && !uniqueUrls.has(item['url'])) {
uniqueUrls.add(item['url']);
return true;
}
return false;
@@ -124,8 +135,115 @@ export class Search {
}
private resetSearchQueryOnNavigationEnd(): void {
this.router.events.pipe(filter((event) => event instanceof NavigationEnd)).subscribe(() => {
this.updateSearchQuery('');
this.router.events
.pipe(filter((event) => event instanceof NavigationEnd))
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(() => {
this.searchQuery.set('');
});
}
private parseResult(response: SearchResponses<unknown>): SearchResultItem[] | undefined {
if (!response) {
return;
}
const result: AlgoliaSearchResult = response.results[0];
if (!result || !('hits' in result)) {
return;
}
const items = result.hits as unknown as SearchResult[];
return this.getUniqueSearchResultItems(items).map((hitItem: SearchResult) => {
const content = hitItem._snippetResult.content;
const hierarchy = hitItem._snippetResult.hierarchy;
const hasSubLabel = content || hierarchy?.lvl2 || hierarchy?.lvl3 || hierarchy?.lvl4;
return {
id: hitItem.objectID,
type: hitItem.hierarchy.lvl0 === 'Tutorials' ? 'code' : 'doc',
url: hitItem.url,
labelHtml: this.parseLabelToHtml(hitItem._snippetResult.hierarchy?.lvl1?.value ?? ''),
subLabelHtml: this.parseLabelToHtml(
hasSubLabel ? this.getBestSnippetForMatch(hitItem) : null,
),
category: hitItem.hierarchy?.lvl0 ?? null,
};
});
}
private getBestSnippetForMatch(result: SearchResult): string {
// if there is content, return it
if (result._snippetResult.content !== undefined) {
return result._snippetResult.content.value;
}
const hierarchy = result._snippetResult.hierarchy;
if (hierarchy === undefined) {
return '';
}
// return the most specific subheader match
if (matched(hierarchy.lvl4)) {
return hierarchy.lvl4!.value;
}
if (matched(hierarchy.lvl3)) {
return hierarchy.lvl3!.value;
}
if (matched(hierarchy.lvl2)) {
return hierarchy.lvl2!.value;
}
// if no subheader matched the query, fall back to just returning the most specific one
return hierarchy.lvl3?.value ?? hierarchy.lvl2?.value ?? '';
}
/**
* Returns an HTML string with marked text for the matches
*/
private parseLabelToHtml(label: string | null): string | null {
if (label === null) {
return null;
}
const parts: Array<{highlight: boolean; text: string}> = [];
while (label.indexOf('<ɵ>') !== -1) {
const beforeMatch = label.substring(0, label.indexOf('<ɵ>'));
const match = label.substring(label.indexOf('<ɵ>') + 3, label.indexOf('</ɵ>'));
parts.push({highlight: false, text: beforeMatch});
parts.push({highlight: true, text: match});
label = label.substring(label.indexOf('</ɵ>') + 4);
}
parts.push({highlight: false, text: label});
return parts
.map((part) => {
return part.highlight ? `<mark>${part.text}</mark>` : `<span>${part.text}</span>`;
})
.join('');
}
}
function matched(snippet: SnippetResult | undefined): boolean {
return snippet?.matchLevel !== undefined && snippet.matchLevel !== 'none';
}
/**
* Temporary helper to implement the debounce functionality on the search resource
*/
function wait(ms: number, signal: AbortSignal) {
return new Promise<void>((resolve, reject) => {
const timeout = setTimeout(() => resolve(), ms);
signal.addEventListener(
'abort',
() => {
clearTimeout(timeout);
reject(new Error('Operation aborted'));
},
{once: true},
);
});
}
@@ -6,10 +6,11 @@
* found in the LICENSE file at https://angular.dev/license
*/
import {DOCUMENT, isPlatformBrowser} from '@angular/common';
import {inject, signal, Injectable, PLATFORM_ID} from '@angular/core';
import {DOCUMENT} from '@angular/common';
import {inject, signal, Injectable, PLATFORM_ID, DestroyRef} from '@angular/core';
import {TableOfContentsItem, TableOfContentsLevel} from '../interfaces/index';
import {on} from 'events';
/**
* Name of an attribute that is set on an element that should be
@@ -29,38 +30,19 @@ export class TableOfContentsLoader {
readonly tableOfContentItems = signal([] as TableOfContentsItem[]);
private readonly document = inject(DOCUMENT);
private readonly platformId = inject(PLATFORM_ID);
buildTableOfContent(docElement: Element): void {
const headings = this.getHeadings(docElement);
const tocList: TableOfContentsItem[] = headings.map((heading) => ({
id: heading.id,
level: heading.tagName.toLowerCase() as TableOfContentsLevel,
title: this.getHeadingTitle(heading),
top: this.calculateTop(heading),
}));
this.tableOfContentItems.set(tocList);
}
// Update top value of heading, it should be executed after window resize
updateHeadingsTopValue(element: HTMLElement): void {
const headings = this.getHeadings(element);
const updatedTopValues = new Map<string, number>();
for (const heading of headings) {
updatedTopValues.set(heading.id, this.calculateTop(heading));
}
this.tableOfContentItems.update((oldItems) => {
let newItems = [...oldItems];
for (const item of newItems) {
item.top = updatedTopValues.get(item.id) ?? 0;
}
return newItems;
});
}
private getHeadingTitle(heading: HTMLHeadingElement): string {
const div: HTMLDivElement = this.document.createElement('div');
div.innerHTML = heading.innerHTML;
@@ -79,11 +61,37 @@ export class TableOfContentsLoader {
);
}
private calculateTop(heading: HTMLHeadingElement): number {
if (!isPlatformBrowser(this.platformId)) return 0;
return (
Math.floor(heading.offsetTop > 0 ? heading.offsetTop : heading.getClientRects()[0]?.top) -
this.toleranceThreshold
);
/**
* The methods setups several IntersectionObservers to determine when a heading is at the top of
* the viewport. Using an IntersectionObserver is more efficient than reading DOM position
* as it won't trigger any reflow.
*/
setupIntersectionObserver(
element: Element,
destroyRef: DestroyRef,
onActiveId: (id: string) => void,
): void {
// If we're at the top the we need the default active id to be the first heading.
const headings = this.getHeadings(element);
onActiveId(headings[0].id);
headings.forEach((heading) => {
const ioConfiguration = {
/**
* This rootMargin creates a horizontal line at 5% from the top of the viewport
* that will help trigger an intersection at that the very point.
*/
rootMargin: '0% 0% -95% 0%',
/** 0 is the default */
threshold: 0,
};
const observer = new IntersectionObserver((entries, o) => {
if (entries[0].isIntersecting) {
onActiveId(entries[0].target.id);
}
}, ioConfiguration);
observer.observe(heading);
destroyRef.onDestroy(() => observer.disconnect());
});
}
}
@@ -6,153 +6,32 @@
* found in the LICENSE file at https://angular.dev/license
*/
import {DOCUMENT, ViewportScroller} from '@angular/common';
import {
DestroyRef,
EnvironmentInjector,
Injectable,
afterNextRender,
inject,
signal,
} from '@angular/core';
import {RESIZE_EVENT_DELAY} from '../constants/index';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {auditTime, debounceTime, fromEvent, startWith} from 'rxjs';
import {WINDOW} from '../providers/index';
import {ViewportScroller} from '@angular/common';
import {DestroyRef, Injectable, inject, signal} from '@angular/core';
import {TableOfContentsLoader} from './table-of-contents-loader.service';
export const SCROLL_EVENT_DELAY = 20;
@Injectable({providedIn: 'root'})
// The service is responsible for listening for scrolling and resizing,
// thanks to which it sets the active item in the Table of contents
export class TableOfContentsScrollSpy {
private readonly tableOfContentsLoader = inject(TableOfContentsLoader);
private readonly document = inject(DOCUMENT);
private readonly window = inject(WINDOW);
private readonly viewportScroller = inject(ViewportScroller);
private readonly injector = inject(EnvironmentInjector);
private contentSourceElement: HTMLElement | null = null;
private lastContentWidth = 0;
activeItemId = signal<string | null>(null);
scrollbarThumbOnTop = signal<boolean>(true);
startListeningToScroll(
contentSourceElement: HTMLElement | null,
// `destroyRef` is required because the caller may invoke `startListeningToScroll`
// multiple times. Without it, previous event listeners would not be disposed of,
// leading to the accumulation of new event listeners.
destroyRef: DestroyRef,
) {
this.contentSourceElement = contentSourceElement;
this.lastContentWidth = this.getContentWidth();
this.setScrollEventHandlers(destroyRef);
this.setResizeEventHandlers(destroyRef);
destroyRef.onDestroy(() => {
// We also need to clean up the source element once the view that calls
// `startListeningToScroll` is destroyed, as this will keep a reference
// to an element that has been removed from the DOM.
this.contentSourceElement = null;
});
}
scrollToTop(): void {
this.viewportScroller.scrollToPosition([0, 0]);
}
// After window resize, we should update top value of each table content item
private setResizeEventHandlers(destroyRef: DestroyRef) {
fromEvent(this.window, 'resize')
.pipe(debounceTime(RESIZE_EVENT_DELAY), takeUntilDestroyed(destroyRef), startWith())
.subscribe(() => {
this.updateHeadingsTopAfterResize();
});
// We need to observe the height of the docs-viewer because it may change after the
// assets (fonts, images) are loaded. They can (and will) change the y-position of the headings.
const docsViewer = this.document.querySelector('docs-viewer');
if (docsViewer) {
const ref = afterNextRender(
() => {
const resizeObserver = new ResizeObserver(() => this.updateHeadingsTopAfterResize());
resizeObserver.observe(docsViewer);
destroyRef.onDestroy(() => resizeObserver.disconnect());
setupActiveItemListener(contentSourceElement: HTMLElement, destroyRef: DestroyRef): void {
if (contentSourceElement) {
this.tableOfContentsLoader.setupIntersectionObserver(
contentSourceElement,
destroyRef,
(id) => {
this.activeItemId.set(id);
},
{injector: this.injector, manualCleanup: true},
);
destroyRef.onDestroy(() => ref.destroy());
}
}
private updateHeadingsTopAfterResize(): void {
this.lastContentWidth = this.getContentWidth();
const contentElement = this.contentSourceElement;
if (contentElement) {
this.tableOfContentsLoader.updateHeadingsTopValue(contentElement);
this.setActiveItemId();
}
}
private setScrollEventHandlers(destroyRef: DestroyRef): void {
const scroll$ = fromEvent(this.document, 'scroll').pipe(
auditTime(SCROLL_EVENT_DELAY),
takeUntilDestroyed(destroyRef),
);
scroll$.subscribe(() => this.setActiveItemId());
}
private setActiveItemId(): void {
const tableOfContentItems = this.tableOfContentsLoader.tableOfContentItems();
if (tableOfContentItems.length === 0) return;
// Resize could emit scroll event, in that case we could stop setting active item until resize will be finished
if (this.lastContentWidth !== this.getContentWidth()) {
return;
}
const scrollOffset = this.getScrollOffset();
if (scrollOffset === null) return;
for (const [i, currentLink] of tableOfContentItems.entries()) {
const nextLink = tableOfContentItems[i + 1];
// A link is considered active if the page is scrolled past the
// anchor without also being scrolled passed the next link.
const isActive =
scrollOffset >= currentLink.top && (!nextLink || nextLink.top >= scrollOffset);
// When active item was changed then trigger change detection
if (isActive && this.activeItemId() !== currentLink.id) {
this.activeItemId.set(currentLink.id);
return;
}
}
if (scrollOffset < tableOfContentItems[0].top && this.activeItemId() !== null) {
this.activeItemId.set(null);
}
const scrollOffsetZero = scrollOffset === 0;
if (scrollOffsetZero !== this.scrollbarThumbOnTop()) {
// we want to trigger change detection only when the value changes
this.scrollbarThumbOnTop.set(scrollOffsetZero);
}
}
// Gets the scroll offset of the scroll container
private getScrollOffset(): number {
return this.window.scrollY;
}
private getContentWidth(): number {
return this.document.body.clientWidth || Number.MAX_SAFE_INTEGER;
}
}
@@ -83,6 +83,10 @@
--label-theme: var(--symbolic-teal);
}
&.type-impure-pipe {
--label-theme: var(--symbolic-pink);
}
&.type-ng_module {
--label-theme: var(--symbolic-brown);
}
+9 -9
View File
@@ -1,3 +1,5 @@
@use '@angular/material' as mat;
// Colors
// Using OKLCH color space for better color reproduction on P3 displays,
// as well as better human-readability
@@ -186,9 +188,6 @@
// for the "unfilled" portion of the word that hasn't
// been highlighted by the gradient
--gray-unfilled: var(--gray-400);
// TODO: convert oklch to hex at build time
--webgl-page-background: #ffffff;
--webgl-gray-unfilled: #a39fa9;
}
@mixin dark-mode-definitions() {
@@ -254,9 +253,6 @@
// Home page - dark mode
--gray-unfilled: var(--gray-700);
// TODO: convert oklch to hex at build time
--webgl-page-background: #0f0f11;
--webgl-gray-unfilled: #413e46;
.docs-toggle {
input {
@@ -268,9 +264,13 @@
}
@mixin mdc-definitions() {
--mdc-snackbar-container-shape: 0.25rem;
--mdc-snackbar-container-color: var(--page-background);
--mdc-snackbar-supporting-text-color: var(--primary-contrast);
@include mat.snack-bar-overrides(
(
container-shape: 0.25rem,
container-color: var(--page-background),
supporting-text-color: var(--primary-contrast),
)
);
}
// LIGHT MODE (Explicit)
+7 -6
View File
@@ -9,38 +9,39 @@ $screen-xl: 1800px;
@content;
}
}
@mixin for-tablet-portrait-up {
@media (min-width: $screen-xs) {
@media (min-width: calc($screen-xs + 1px)) {
@content;
}
}
@mixin for-tablet {
@media (min-width: $screen-xs) and (max-width: $screen-md) {
@media (min-width: calc($screen-xs + 1px)) and (max-width: $screen-md) {
@content;
}
}
@mixin for-tablet-up {
@media (min-width: $screen-sm) {
@media (min-width: calc($screen-sm + 1px)) {
@content;
}
}
@mixin for-tablet-landscape-up {
@media (min-width: $screen-md) {
@media (min-width: calc($screen-md + 1px)) {
@content;
}
}
@mixin for-desktop-up {
@media (min-width: $screen-lg) {
@media (min-width: calc($screen-lg + 1px)) {
@content;
}
}
@mixin for-big-desktop-up {
@media (min-width: $screen-xl) {
@media (min-width: calc($screen-xl + 1px)) {
@content;
}
}
+10 -2
View File
@@ -66,7 +66,11 @@
.docs-reference-section-heading {
padding-block-start: 3rem;
a {
&--sub {
padding-block-start: 1rem;
}
& > a {
@include anchor.docs-anchor();
color: inherit;
}
@@ -98,7 +102,7 @@
z-index: 0;
}
&.highlighted {
&.docs-highlighted-card {
box-shadow: 10px 4px 40px 0 rgba(0, 0, 0, 0.01);
&::before {
@@ -255,6 +259,10 @@
}
}
.pipe-usage {
padding: 1rem;
}
// "API member card"-specific styles
.docs-reference-member-card {
.docs-reference-card-item {
+4 -3
View File
@@ -2,9 +2,10 @@
@mixin resets() {
:root {
--fallback-font-stack: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji',
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--fallback-font-stack:
ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol', 'Noto Color Emoji';
--page-width: 80ch;
--layout-padding: 3.12rem; // a common padding value throughout the layout
--primary-nav-width: 110px;
+2
View File
@@ -79,6 +79,7 @@
}
p > a,
p > em > a,
td > a,
div > a:not(.docs-card),
code > a,
@@ -93,6 +94,7 @@
}
p > a,
p > em > a,
.docs-list a,
.docs-card a {
margin-block: 0;
+1 -2
View File
@@ -58,7 +58,7 @@
fill: var(--page-background) !important;
}
.nodeLabel:not(.node:has(polygon) .nodeLabel) {
.nodeLabel:not(.node:has(polygon) .nodeLabel):not(.eventNode .nodeLabel) {
fill: var(--primary-contrast) !important;
color: var(--primary-contrast) !important;
}
@@ -71,7 +71,6 @@
}
.nodeLabel p {
color: var(--page-background) !important;
font-weight: 800 !important;
}
}
+21 -32
View File
@@ -85,33 +85,29 @@ export class FakeWebContainer extends WebContainer {
if (fakeOptions?.spawn) this.fakeSpawn = fakeOptions.spawn;
}
override spawn(
override async spawn(
command: unknown,
args?: unknown,
options?: unknown,
): Promise<FakeWebContainerProcess> {
if (this.fakeSpawn) return Promise.resolve(this.fakeSpawn);
if (this.fakeSpawn) return this.fakeSpawn;
const fakeProcess = new FakeWebContainerProcess();
return Promise.resolve(fakeProcess);
return new FakeWebContainerProcess();
}
override on(event: 'port', listener: PortListener): Unsubscribe;
override on(event: 'server-ready', listener: ServerReadyListener): Unsubscribe;
override on(event: 'error', listener: ErrorListener): Unsubscribe;
override on(event: 'preview-message', listener: PreviewMessageListener): Unsubscribe;
override on(event: unknown, listener: unknown): Unsubscribe {
return () => {};
}
override mount(
override async mount(
tree: FileSystemTree,
options?: {mountPoint?: string | undefined} | undefined,
): Promise<void> {
return Promise.resolve();
}
): Promise<void> {}
override get path() {
return '/fake-path';
}
override get workdir() {
return '/fake-workdir';
}
@@ -142,19 +138,15 @@ class FakeFileSystemAPI implements FileSystemAPI {
path: string,
options: {encoding?: string | null | undefined; withFileTypes: true},
): Promise<DirEnt<string>[]>;
readdir(
async readdir(
path: unknown,
options?: {encoding?: string | null | undefined; withFileTypes?: boolean} | string | null,
):
| Promise<Uint8Array[]>
| Promise<string[]>
| Promise<DirEnt<Uint8Array>[]>
| Promise<DirEnt<string>[]> {
): Promise<Uint8Array[] | string[] | DirEnt<Uint8Array>[] | DirEnt<string>[]> {
if (typeof options === 'object' && options?.withFileTypes === true) {
return Promise.resolve([{name: 'fake-file', isFile: () => true, isDirectory: () => false}]);
return [{name: 'fake-file', isFile: () => true, isDirectory: () => false}];
}
return Promise.resolve(['/fake-dirname']);
return ['/fake-dirname'];
}
readFile(path: string, encoding?: null | undefined): Promise<Uint8Array>;
@@ -162,28 +154,25 @@ class FakeFileSystemAPI implements FileSystemAPI {
readFile(path: unknown, encoding?: unknown): Promise<Uint8Array> | Promise<string> {
return Promise.resolve('fake file content');
}
writeFile(
async writeFile(
path: string,
data: string | Uint8Array,
options?: string | {encoding?: string | null | undefined} | null | undefined,
): Promise<void> {
return Promise.resolve();
}
): Promise<void> {}
mkdir(path: string, options?: {recursive?: false | undefined} | undefined): Promise<void>;
mkdir(path: string, options: {recursive: true}): Promise<string>;
mkdir(path: unknown, options?: unknown): Promise<void> | Promise<string> {
return Promise.resolve();
}
rm(
async mkdir(path: unknown, options?: unknown): Promise<void | string> {}
async rm(
path: string,
options?: {force?: boolean | undefined; recursive?: boolean | undefined} | undefined,
): Promise<void> {
return Promise.resolve();
}
): Promise<void> {}
rename(oldPath: string, newPath: string): Promise<void> {
throw Error('Not implemented');
}
watch(
filename: string,
options?: FSWatchOptions | undefined,
+1 -1
View File
@@ -8,7 +8,7 @@
declare global {
interface Window {
gtag: (...args: any[]) => void;
gtag?(...args: any[]): void;
}
}
+2 -2
View File
@@ -1,7 +1,6 @@
@use '@angular/docs/styles/media-queries' as mq;
:host {
max-width: 2560px;
margin-inline: auto;
display: flex;
flex-direction: row;
@@ -21,7 +20,7 @@
}
// show it under the navbar.
@include mq.for-tablet-landscape-down{
@include mq.for-tablet-landscape-down {
z-index: calc(var(--z-index-nav) - 1);
}
}
@@ -96,6 +95,7 @@
flex-direction: column;
min-height: 100vh;
width: 100%;
max-width: 2560px;
// If navs are open, render a blurry background over content
::after {
+2 -2
View File
@@ -8,7 +8,7 @@
import {TestBed} from '@angular/core/testing';
import {AppComponent} from './app.component';
import {provideRouter} from '@angular/router';
import {provideRouter, withComponentInputBinding} from '@angular/router';
import {routes} from './routes';
import {Search, WINDOW} from '@angular/docs';
import {CURRENT_MAJOR_VERSION} from './core/providers/current-version';
@@ -21,7 +21,7 @@ describe('AppComponent', () => {
it('should create the app', () => {
TestBed.configureTestingModule({
providers: [
provideRouter(routes),
provideRouter(routes, withComponentInputBinding()),
{
provide: WINDOW,
useValue: fakeWindow,
+18 -26
View File
@@ -13,11 +13,11 @@ import {
inject,
OnInit,
PLATFORM_ID,
input,
signal,
WritableSignal,
} from '@angular/core';
import {NavigationEnd, NavigationSkipped, Router, RouterOutlet} from '@angular/router';
import {filter, map, skip} from 'rxjs/operators';
import {filter, map} from 'rxjs/operators';
import {
CookiePopup,
getActivatedRouteSnapshotFromRouter,
@@ -56,13 +56,12 @@ export class AppComponent implements OnInit {
private readonly router = inject(Router);
private readonly headerService = inject(HeaderService);
currentUrl = signal('');
displayFooter = signal(false);
displaySecondaryNav = signal(false);
displaySearchDialog: WritableSignal<boolean> = inject(IS_SEARCH_DIALOG_OPEN);
isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
displaySecondaryNav = signal(false);
displayFooter = signal(false);
displaySearchDialog = inject(IS_SEARCH_DIALOG_OPEN);
ngOnInit(): void {
this.closeSearchDialogOnNavigationSkipped();
this.router.events
@@ -71,35 +70,24 @@ export class AppComponent implements OnInit {
map((event) => event.urlAfterRedirects),
)
.subscribe((url) => {
this.currentUrl.set(url);
this.setComponentsVisibility();
this.displaySearchDialog.set(false);
// We can't use an input binded to the route here
// because AppComponent itself is not a routed component
// so we access it via the snapshot
const activatedRoute = getActivatedRouteSnapshotFromRouter(this.router);
this.displayFooter.set(!activatedRoute.data['hideFooter']);
this.displaySecondaryNav.set(activatedRoute.data['displaySecondaryNav']);
this.displaySearchDialog.set(false);
this.updateCanonicalLink(url);
});
}
focusFirstHeading(): void {
if (!this.isBrowser) {
return;
}
const h1 = this.document.querySelector<HTMLHeadingElement>('h1:not(docs-top-level-banner h1)');
h1?.focus();
}
private updateCanonicalLink(absoluteUrl: string) {
this.headerService.setCanonical(absoluteUrl);
}
private setComponentsVisibility(): void {
const activatedRoute = getActivatedRouteSnapshotFromRouter(this.router as any);
this.displaySecondaryNav.set(activatedRoute.data['displaySecondaryNav']);
this.displayFooter.set(!activatedRoute.data['hideFooter']);
}
private setSearchDialogVisibilityOnKeyPress(event: KeyboardEvent): void {
protected setSearchDialogVisibilityOnKeyPress(event: KeyboardEvent): void {
if (event.key === SEARCH_TRIGGER_KEY && (event.metaKey || event.ctrlKey)) {
event.preventDefault();
this.displaySearchDialog.update((display) => !display);
@@ -111,6 +99,10 @@ export class AppComponent implements OnInit {
}
}
private updateCanonicalLink(absoluteUrl: string) {
this.headerService.setCanonical(absoluteUrl);
}
private closeSearchDialogOnNavigationSkipped(): void {
this.router.events.pipe(filter((event) => event instanceof NavigationSkipped)).subscribe(() => {
this.displaySearchDialog.set(false);
+2 -2
View File
@@ -21,11 +21,11 @@ import {
ENVIRONMENT,
EXAMPLE_VIEWER_CONTENT_LOADER,
PREVIEWS_COMPONENTS,
provideAlgoliaSearchClient,
WINDOW,
windowProvider,
} from '@angular/docs';
import {provideClientHydration} from '@angular/platform-browser';
import {provideAnimationsAsync} from '@angular/platform-browser/animations/async';
import {
RouteReuseStrategy,
Router,
@@ -75,9 +75,9 @@ export const appConfig: ApplicationConfig = {
provideExperimentalZonelessChangeDetection(),
provideClientHydration(),
provideHttpClient(withFetch()),
provideAnimationsAsync(),
provideEnvironmentInitializer(() => inject(AppScroller)),
provideEnvironmentInitializer(() => inject(AnalyticsService)),
provideAlgoliaSearchClient(environment),
{
provide: CURRENT_MAJOR_VERSION,
useValue: Number(VERSION.major),
@@ -119,7 +119,7 @@
</div>
</div>
<p class="docs-license">
Super-powered by Google ©2010-2024. Code licensed under an
Super-powered by Google ©2010-2025. Code licensed under an
<a routerLink="/license" title="License text">MIT-style License</a>
. Documentation licensed under
<a href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>
@@ -1,6 +1,7 @@
<!-- Primary Nav -->
<div
[attr.id]="PRIMARY_NAV_ID"
class="wrapper"
(docsClickOutside)="closeMobileNav()"
[docsClickOutsideIgnore]="[SECONDARY_NAV_ID]"
>
@@ -19,6 +19,14 @@
z-index: 50;
}
}
@include mq.for-tablet-landscape-down {
width: 100%;
.wrapper {
width: 100%;
}
}
}
.adev-mobile-nav-bar {
@@ -27,7 +35,7 @@
backdrop-filter: blur(16px);
background-color: color-mix(in srgb, var(--page-background) 70%, transparent);
position: relative;
width: 100vw;
width: 100%;
padding-block: 0.75rem;
padding-inline: var(--layout-padding);
border-block-end: 1px solid var(--septenary-contrast);
@@ -74,7 +82,7 @@
// Add a subtle border for the home page
border-block-end: 1px solid var(--septenary-contrast);
@include mq.for-tablet-up {
@include mq.for-tablet-landscape-up {
border-inline-end: 1px solid var(--septenary-contrast);
}
@@ -84,7 +92,7 @@
@include mq.for-tablet {
flex-direction: row;
width: 100vw;
width: 100%;
padding-inline: calc(var(--layout-padding) - 1.25rem);
height: auto;
padding-block: 0;
@@ -293,6 +301,7 @@
transition:
background-color 0.3s ease,
border-color 0.3s ease;
button {
display: flex;
gap: 0.5rem;
@@ -301,6 +310,7 @@
padding: 0;
font-weight: 500;
}
@include mq.for-tablet-landscape-up {
display: none;
}
@@ -25,9 +25,11 @@ describe('ProgressBarComponent', () => {
fixture.detectChanges();
});
it('should call progressBar.complete() on route change', async () => {
const progressBar = component.progressBar();
const progressBarCompleteSpy = spyOn(progressBar, 'complete');
// This test often timeouts
// We suspect a racing condition inside the RouterTestingHarness.
// Until this has been investigated, we will skip this test.
xit('should call progressBar.complete() on route change', async () => {
const progressBarCompleteSpy = spyOn(component.progressBar(), 'complete');
const harness = await RouterTestingHarness.create();
await harness.navigateByUrl('/');

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