Compare commits

...

27 Commits

Author SHA1 Message Date
Alex Rickabaugh 99723fc64e release: cut the v15.1.0 release 2023-01-10 10:49:33 -08:00
Paul Gschwendtner 6a8ea29a04 fix(language-service): expose package.json for vscode extension resolution (#48678)
The VSCode extension looks for `@angular/language-service/package.json`
using `require`. This currently breaks as of the ESM changes because
we introduced the `exports` field but did not expose the `package.json`.

This commit fixes it.

Co-authored-By: Andrew Scott <atscott@google.com>
Co-authored-By: Dylan Hunn <dylhunn@gmail.com>

PR Close #48678
2023-01-10 09:13:55 -08:00
Kristiyan Kostadinov caf7228f8a fix(compiler): resolve deprecation warning (#48652)
Fixes a deprecation warning that was being logged by compiler when generating aliases, because we weren't going through `ts.factory` to create an AST node.

PR Close #48652
2023-01-10 08:13:31 -08:00
Paul Gschwendtner 896c04fac4 test(docs-infra): increase jasmine default timeout for e2e specs (#48671)
Similar to the Saucelabs job, the jasmine default timeout can be
increased to avoid the common jasmine timeouts. We cannot control
how fast Selenium e.g. loads a page or not.

PR Close #48671
2023-01-10 08:10:24 -08:00
Alan Agius 772ddc1baa fix(docs-infra): correctly read example type (#48665)
Prior to this change the universal example was broken as the example type was not retrieved correctly in bazel which caused the `_renameFile` method to be called with incorrect context.

Closes #48664

PR Close #48665
2023-01-10 08:09:55 -08:00
Alan Agius 9e013d3dd7 docs: update universal example (#48665)
This change updates the universal example to align with latest CLI changes.

PR Close #48665
2023-01-10 08:09:55 -08:00
Angular Robot 9770964acf build: update dependency jsdom to v21 (#48660)
See associated pull request for more information.

PR Close #48660
2023-01-10 08:09:05 -08:00
Virginia Dooley 8d251fc0cf docs: Custom data Pipes doc, fixed live-example link. (#48656)
PR Close #48656
2023-01-10 08:08:08 -08:00
Andrew Kushnir f112f8d211 refactor(platform-browser): prepare the code to use MockPlatformLocation by default (#48651)
This commit prepares the code of the `BrowserTestingModule` to include the `MockPlatformLocation` by deafult in the future. With this change, the set of providers to add the `MockPlatformLocation` would be disabled by a flag, which will be switched in v16.

PR Close #48651
2023-01-10 08:06:37 -08:00
piyush132000 1c1c4555a2 docs: updated docs removed unnecessary imports and empty methods (#48628)
Removed empty methods and unnecessary imports in files

PR Close #48628
2023-01-10 08:06:05 -08:00
Tim Gates 057e495db5 docs: fix simple typo, esnure -> ensure (#48588)
There is a small typo in integration/check-dependencies.js.

Should read `ensure` rather than `esnure`.

Signed-off-by: Tim Gates <tim.gates@iress.com>

PR Close #48588
2023-01-10 08:05:34 -08:00
Matthieu Riegler b86c6a8909 docs(compiler-cli): fix commands to run compliance unit test (#48559)
PR Close #48559
2023-01-10 07:59:53 -08:00
Andrew Scott 783d21431f refactor(router): move internal router properties to transition handler where appropriate (#48475)
Working towards removing the backwards dependency on router from the
navigation transition handler, this change moves `rootComponentType` and
`afterPreactivation` to the transition handler since that is the only
location those properties are used.

PR Close #48475
2023-01-10 07:59:16 -08:00
Doug Parker 2ffa34eebc refactor(bazel): disables the Tsickle decorator transform (#47934)
This is no longer needed in google3 and actively impedes prodmode tests. See http://b/254054103#comment7 for deeper analysis.

This just turns off the transform for now, if it lands successfully I'll follow up with deleting the flag and dead code altogether.

PR Close #47934
2023-01-10 07:58:40 -08:00
Paul Gschwendtner e615b598ba fix(language-service): ship /api entry-point (#48670)
The `/api` entry-point was accidentally dropped when we switched the
compilation in the repo to full ESM- thinking the entry-point is not
needed externally.

We re-add it because the VSCode repo extension relies on it for checking
whether `ts.LanguageService` is an Angular one.

PR Close #48670
2023-01-09 10:13:35 -08:00
Greg Magolan 6ce7d76a0e fix(language-service): update packages/language-service/build.sh script to work with vscode-ng-language-service's new Bazel build (#48663)
2nd half of https://github.com/angular/vscode-ng-language-service/pull/1846. `npm_traslate_lock` in vscode-ng-language-service now has a data attribute so sed should only add another item to the list instead of adding a duplicate data attribute.

PR Close #48663
2023-01-09 10:13:07 -08:00
Matthieu Riegler 8aa8b4b77c fix(forms): Form provider FormsModule.withConfig return a FormsModule (#48526)
Because of a transitive dependency, FormsModule.withConfig wasn't providing FormModule.

fixes: #48519

PR Close #48526
2023-01-05 16:26:22 -08:00
Matthieu Riegler 61fc47475d refactor(forms): cleanup type any in forms tests (#48624)
Removing every type any in forms with a reference to #9100

PR Close #48624
2023-01-05 14:52:04 -08:00
Andrew Scott 3fe75710d9 fix(router): page refresh should not destroy history state (#48540)
The router's `initialNavigation` causes an imperative navigation using
the `navigateByUrl` method. This, however, results in the history state
being removed on a page refresh. This change calls `scheduleNavigation`
directly from `initialNavigation` to ensure the history state is correctly
retained.

PR Close #48540
2023-01-05 14:50:53 -08:00
Matthieu Riegler b09a716e80 docs: remove empty constructors & ngOnInit() (#48576)
PR Close #48576
2023-01-05 14:49:39 -08:00
Matthieu Riegler b3d0a2717e docs: remove onInit from Tour Of Heroes. (#48576)
Following #24008, the schematics don't produce ngOnInit and the constructor. Let's reflect that in the Tour of Heroes tutorial.

Fixes #48575

PR Close #48576
2023-01-05 14:49:39 -08:00
Matthieu Riegler f672d8fa46 refactor(common): remove non-null assertions (#48476)
As part of angular#24571, removing all non-null assertions from common/test/directives

PR Close #48476
2023-01-05 14:46:22 -08:00
Matthieu Riegler a8ba26561b refactor(common): code cleaning (#48476)
* removing guard as console.warn is now widely supported
* Couldn't remove non-null assertion, waiting for TS support of getters with different types (microsoft/typescript#43662)

PR Close #48476
2023-01-05 14:46:22 -08:00
Matthieu Riegler d832cb2e23 refactor(common): remove non-null assertions (#48476)
As part of angular#24571, removing all non-null assertions from common/directives

PR Close #48476
2023-01-05 14:46:21 -08:00
Matthieu Riegler 23b465e5ed refactor(common): remove non-null assertions (#48476)
As part of angular#24571, removing all non-null assertions from common/directives

PR Close #48476
2023-01-05 14:46:21 -08:00
Andrew Scott d7d23b0320 refactor(router): Remove files no longer in use (#48500)
These files exist to support internal patches that are no longer needed

PR Close #48500
2023-01-05 14:42:28 -08:00
Alex Rickabaugh 28ea114d54 release: cut the v15.1.0-rc.0 release 2023-01-05 13:18:34 -08:00
52 changed files with 283 additions and 375 deletions
+63 -115
View File
@@ -1,24 +1,77 @@
<a name="15.1.0-next.3"></a>
# 15.1.0-next.3 (2022-12-14)
### animations
| Commit | Type | Description |
| -- | -- | -- |
| [c86484507f](https://github.com/angular/angular/commit/c86484507fdc0a44b3d20ea8b988b23f25ad9ac2) | fix | fix incorrect handling of camel-case css properties ([#48436](https://github.com/angular/angular/pull/48436)) |
<a name="15.1.0"></a>
# 15.1.0 (2023-01-10)
## Deprecations
### router
* `CanLoad` guards in the Router are deprecated. Use `CanMatch`
instead.
* None of the public properties of the Router are meant to be writeable. They should all be configured using other methods, all of which have been documented:
The following strategies are meant to be configured by registering the
application strategy in DI via the `providers` in the root `NgModule` or
`bootstrapApplication`:
* `routeReuseStrategy`
* `titleStrategy`
* `urlHandlingStrategy`
The following options are meant to be configured using the options
available in `RouterModule.forRoot` or `provideRouter`.
* `onSameUrlNavigation`
* `paramsInheritanceStrategy`
* `urlUpdateStrategy`
* `canceledNavigationResolution`
The following options are available in `RouterModule.forRoot` but not
available in `provideRouter`:
* `malformedUriErrorHandler` - This was found to not be used anywhere
internally.
* `errorHandler` - Developers can instead subscribe to `Router.events`
and filter for `NavigationError`.
### common
| Commit | Type | Description |
| -- | -- | -- |
| [fe50813664](https://github.com/angular/angular/commit/fe50813664809a1177132a77bd2a316ad0858b9e) | feat | Add BrowserPlatformLocation to the public API ([#48488](https://github.com/angular/angular/pull/48488)) |
| [e362214924](https://github.com/angular/angular/commit/e362214924dbb784e5bd0efd96530134f8c91d32) | fix | Fix TestBed.overrideProvider type to include multi ([#48424](https://github.com/angular/angular/pull/48424)) |
### compiler-cli
| [2f4f0638c7](https://github.com/angular/angular/commit/2f4f0638c74dccfc2d0522f67ab226d3227c0566) | fix | Add data attribtue to NgOptimizedImage ([#48497](https://github.com/angular/angular/pull/48497)) |
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [a6849f27af](https://github.com/angular/angular/commit/a6849f27af129588091f635c6ae7a326241344fc) | fix | evaluate const tuple types statically ([#48091](https://github.com/angular/angular/pull/48091)) |
| [a532d71975](https://github.com/angular/angular/commit/a532d71975bef463223fd5d8322e3140760c9134) | feat | allow self-closing tags on custom elements ([#48535](https://github.com/angular/angular/pull/48535)) |
| [33f35b04ef](https://github.com/angular/angular/commit/33f35b04ef0f32f25624a6be59f8635675e3e131) | fix | type-only symbols incorrectly retained when downlevelling custom decorators ([#48638](https://github.com/angular/angular/pull/48638)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [6acae1477a](https://github.com/angular/angular/commit/6acae1477a212bbd85d0670913c2925fa3bc0c24) | feat | Add `TestBed.runInInjectionContext` to help test functions which use `inject` ([#47955](https://github.com/angular/angular/pull/47955)) |
| [38421578a2](https://github.com/angular/angular/commit/38421578a2573bcbc86c927ed4015e20fc39f04a) | feat | Make the `isStandalone()` function available in public API ([#48114](https://github.com/angular/angular/pull/48114)) |
| [dd42974b07](https://github.com/angular/angular/commit/dd42974b070b068135c1bc34072486ae440e45e0) | feat | support TypeScript 4.9 ([#48005](https://github.com/angular/angular/pull/48005)) |
### forms
| Commit | Type | Description |
| -- | -- | -- |
| [8aa8b4b77c](https://github.com/angular/angular/commit/8aa8b4b77cefcdd400ec9767b946b295ef42a066) | fix | Form provider FormsModule.withConfig return a FormsModule ([#48526](https://github.com/angular/angular/pull/48526)) |
### language-service
| Commit | Type | Description |
| -- | -- | -- |
| [5f0b53c735](https://github.com/angular/angular/commit/5f0b53c7352f19480185c6b5c769e5012a2d2faa) | feat | Allow auto-imports to suggest multiple possible imports. ([#47787](https://github.com/angular/angular/pull/47787)) |
| [ce8160ecb2](https://github.com/angular/angular/commit/ce8160ecb28d6765d438eb65035835984eb956ec) | fix | Prevent crashes on unemitable references ([#47938](https://github.com/angular/angular/pull/47938)) |
### localize
| Commit | Type | Description |
| -- | -- | -- |
| [a1a8e91eca](https://github.com/angular/angular/commit/a1a8e91ecaded6a2e4d700109a26d3117ad77c9c) | fix | add triple slash type reference on `@angular/localize` on `ng add ([#48502](https://github.com/angular/angular/pull/48502)) |
### migrations
| Commit | Type | Description |
| -- | -- | -- |
| [cc284afbbc](https://github.com/angular/angular/commit/cc284afbbc33b91884882204c5958a44a5d11392) | fix | combine newly-added imports in import manager ([#48620](https://github.com/angular/angular/pull/48620)) |
### router
| Commit | Type | Description |
| -- | -- | -- |
| [228e992db7](https://github.com/angular/angular/commit/228e992db75bd7a2213b4596e6e2a8696578aa19) | docs | Deprecate canLoad guards in favor of canMatch ([#48180](https://github.com/angular/angular/pull/48180)) |
| [0a8b8a66cd](https://github.com/angular/angular/commit/0a8b8a66cdfb86586811c79bec938b3ab7215e8f) | docs | Deprecate public members of Router that are meant to be configured elsewhere ([#48006](https://github.com/angular/angular/pull/48006)) |
| [332461bd0c](https://github.com/angular/angular/commit/332461bd0c5f5734a9d7f051f0f4c6c173dd87c9) | feat | Add ability to override `onSameUrlNavigation` default per-navigation ([#48050](https://github.com/angular/angular/pull/48050)) |
| [f58ad86e51](https://github.com/angular/angular/commit/f58ad86e51817f83ff18db790a347528262b850b) | feat | Add feature provider for enabling hash navigation ([#48301](https://github.com/angular/angular/pull/48301)) |
| [73f03ad2d2](https://github.com/angular/angular/commit/73f03ad2d29811dda2ee03c5f18c79ebc9519c0b) | feat | Add new NavigationSkipped event for ignored navigations ([#48024](https://github.com/angular/angular/pull/48024)) |
| [3fe75710d9](https://github.com/angular/angular/commit/3fe75710d97a0f3224b2b09c45d9b8a9ad6efe91) | fix | page refresh should not destroy history state ([#48540](https://github.com/angular/angular/pull/48540)) |
## Special Thanks
Alan Agius, Andrew Kushnir, Andrew Scott, Aristeidis Bampakos, Bob Watson, BrowserPerson, Jens, Jessica Janiuk, Joey Perrott, JoostK, Konstantin Kharitonov, Lukas Matta, Matthieu Riegler, Piotr Kowalski, Virginia Dooley, Yannick Baron, dario-piotrowicz, lsst25, piyush132000 and why520crazy
Alan Agius, Alex Castle, Alex Rickabaugh, Andrew Kushnir, Andrew Scott, Bob Watson, Charles Lyding, Derek Cormier, Doug Parker, Dylan Hunn, George Kalpakas, Greg Magolan, Jessica Janiuk, JiaLiPassion, Joey Perrott, Kristiyan Kostadinov, Matthieu Riegler, Paul Gschwendtner, Pawel Kozlowski, Renan Ferro, Tim Gates, Vadim, Virginia Dooley, ced, mgechev, piyush132000, robertIsaac and sr5434
<!-- CHANGELOG SPLIT MARKER -->
@@ -41,32 +94,6 @@ Alan Agius, Andrew Kushnir, Andrew Scott, Aristeidis Bampakos, Bob Watson, Brows
<!-- CHANGELOG SPLIT MARKER -->
<a name="15.1.0-next.2"></a>
# 15.1.0-next.2 (2022-12-07)
### common
| Commit | Type | Description |
| -- | -- | -- |
| [8e52ca2714](https://github.com/angular/angular/commit/8e52ca271496b0feebf66b2dc7c8f396b73d61a0) | fix | Don't generate srcsets with very large sources ([#47997](https://github.com/angular/angular/pull/47997)) |
| [f8ecc194e9](https://github.com/angular/angular/commit/f8ecc194e93bf9f80af0cb0e77032341bf2f9886) | fix | Update `Location` to support base href containing `origin` ([#48327](https://github.com/angular/angular/pull/48327)) |
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [4c023956d8](https://github.com/angular/angular/commit/4c023956d8dd05d8455612dff185a7e7918c9fed) | fix | make sure selectors inside container queries are correctly scoped ([#48353](https://github.com/angular/angular/pull/48353)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [27eaded62d](https://github.com/angular/angular/commit/27eaded62dbe059fc9ac02cfa7f53ccf8aebccbf) | fix | Produce diagnostic rather than crash when using invalid hostDirective ([#48314](https://github.com/angular/angular/pull/48314)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [38421578a2](https://github.com/angular/angular/commit/38421578a2573bcbc86c927ed4015e20fc39f04a) | feat | Make the `isStandalone()` function available in public API ([#48114](https://github.com/angular/angular/pull/48114)) |
| [dd42974b07](https://github.com/angular/angular/commit/dd42974b070b068135c1bc34072486ae440e45e0) | feat | support TypeScript 4.9 ([#48005](https://github.com/angular/angular/pull/48005)) |
| [5f9c7ceb90](https://github.com/angular/angular/commit/5f9c7ceb907be47dff3e203dd837fd6ee9133fcb) | fix | unable to inject ChangeDetectorRef inside host directives ([#48355](https://github.com/angular/angular/pull/48355)) |
## Special Thanks
Alan Agius, Alex Castle, Andrew Kushnir, Andrew Scott, Bob Watson, Charles Lyding, Derek Cormier, Joey Perrott, Konstantin Kharitonov, Kristiyan Kostadinov, Matthieu Riegler, Paul Gschwendtner, Pawel Kozlowski, dario-piotrowicz, piyush132000 and sr5434
<!-- CHANGELOG SPLIT MARKER -->
<a name="15.0.3"></a>
# 15.0.3 (2022-12-07)
### common
@@ -91,26 +118,6 @@ Alan Agius, Alex Castle, Andrew Kushnir, Andrew Scott, Bob Watson, Derek Cormier
<!-- CHANGELOG SPLIT MARKER -->
<a name="15.1.0-next.1"></a>
# 15.1.0-next.1 (2022-11-30)
## Deprecations
### router
- CanLoad guards in the Router are deprecated. Use CanMatch
instead.
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [7d88700933](https://github.com/angular/angular/commit/7d8870093313575d89c8abe584c43d6fa8105fc8) | fix | accept inheriting the constructor from a class in a library ([#48156](https://github.com/angular/angular/pull/48156)) |
### router
| Commit | Type | Description |
| -- | -- | -- |
| [228e992db7](https://github.com/angular/angular/commit/228e992db75bd7a2213b4596e6e2a8696578aa19) | docs | Deprecate canLoad guards in favor of canMatch ([#48180](https://github.com/angular/angular/pull/48180)) |
| [332461bd0c](https://github.com/angular/angular/commit/332461bd0c5f5734a9d7f051f0f4c6c173dd87c9) | feat | Add ability to override `onSameUrlNavigation` default per-navigation ([#48050](https://github.com/angular/angular/pull/48050)) |
## Special Thanks
Alan Agius, Andrew Scott, Aristeidis Bampakos, Bob Watson, Derek Cormier, Dylan Hunn, JoostK, Kristiyan Kostadinov, Matthieu Riegler, Paul Gschwendtner, Pawel Kozlowski, Rokas Brazdžionis and piyush132000
<!-- CHANGELOG SPLIT MARKER -->
<a name="15.0.2"></a>
# 15.0.2 (2022-11-30)
### compiler-cli
@@ -149,65 +156,6 @@ Alan Agius, Andrew Scott, Bjarki, Bob Watson, Brooke, Derek Cormier, Dylan Hunn,
<!-- CHANGELOG SPLIT MARKER -->
<a name="15.1.0-next.0"></a>
# 15.1.0-next.0 (2022-11-22)
## Deprecations
### router
- router writable properties
The following strategies are meant to be configured by registering the
application strategy in DI via the `providers` in the root `NgModule` or
`bootstrapApplication`:
* `routeReuseStrategy`
* `titleStrategy`
* `urlHandlingStrategy`
The following options are meant to be configured using the options
available in `RouterModule.forRoot` or `provideRouter`.
* `onSameUrlNavigation`
* `paramsInheritanceStrategy`
* `urlUpdateStrategy`
* `canceledNavigationResolution`
The following options are available in `RouterModule.forRoot` but not
available in `provideRouter`:
* `malformedUriErrorHandler` - This was found to not be used anywhere
internally.
* `errorHandler` - Developers can instead subscribe to `Router.events`
and filter for `NavigationError`.
### common
| Commit | Type | Description |
| -- | -- | -- |
| [b0a62bea47](https://github.com/angular/angular/commit/b0a62bea475480768f2cffeb134960dc1165181c) | fix | Fix MockPlatformLocation events and missing onPopState implementation ([#48113](https://github.com/angular/angular/pull/48113)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [6acae1477a](https://github.com/angular/angular/commit/6acae1477a212bbd85d0670913c2925fa3bc0c24) | feat | Add `TestBed.runInInjectionContext` to help test functions which use `inject` ([#47955](https://github.com/angular/angular/pull/47955)) |
### forms
| Commit | Type | Description |
| -- | -- | -- |
| [0329c13e95](https://github.com/angular/angular/commit/0329c13e95127fd6f0044b6809b9bccb27f3cb91) | fix | don't mutate validators array ([#47830](https://github.com/angular/angular/pull/47830)) |
| [d321880440](https://github.com/angular/angular/commit/d3218804401fb35d8da1de91960bbdf9ab0aa823) | fix | FormBuilder.group return right type with shorthand parameters. ([#48084](https://github.com/angular/angular/pull/48084)) |
### language-service
| Commit | Type | Description |
| -- | -- | -- |
| [5f0b53c735](https://github.com/angular/angular/commit/5f0b53c7352f19480185c6b5c769e5012a2d2faa) | feat | Allow auto-imports to suggest multiple possible imports. ([#47787](https://github.com/angular/angular/pull/47787)) |
| [fd2eea5961](https://github.com/angular/angular/commit/fd2eea59613ab3cdde871046b6086216d77a386e) | fix | correctly handle host directive inputs/outputs ([#48147](https://github.com/angular/angular/pull/48147)) |
| [ce8160ecb2](https://github.com/angular/angular/commit/ce8160ecb28d6765d438eb65035835984eb956ec) | fix | Prevent crashes on unemitable references ([#47938](https://github.com/angular/angular/pull/47938)) |
| [764fa3d9c3](https://github.com/angular/angular/commit/764fa3d9c37eb70acd21879296ec039de07173ea) | fix | update packages/language-service/build.sh script to work with vscode-ng-language-service's new Bazel build ([#48120](https://github.com/angular/angular/pull/48120)) |
### router
| Commit | Type | Description |
| -- | -- | -- |
| [0a8b8a66cd](https://github.com/angular/angular/commit/0a8b8a66cdfb86586811c79bec938b3ab7215e8f) | docs | Deprecate public members of Router that are meant to be configured elsewhere ([#48006](https://github.com/angular/angular/pull/48006)) |
| [73f03ad2d2](https://github.com/angular/angular/commit/73f03ad2d29811dda2ee03c5f18c79ebc9519c0b) | feat | Add new NavigationSkipped event for ignored navigations ([#48024](https://github.com/angular/angular/pull/48024)) |
| [b51929a394](https://github.com/angular/angular/commit/b51929a394acaa129699bc72e34882b7e577dd7f) | fix | correct type of nextState parameter in canDeactivate ([#48038](https://github.com/angular/angular/pull/48038)) |
| [1df0ed7d6e](https://github.com/angular/angular/commit/1df0ed7d6e636d921ad617465c3956dc1b6292eb) | fix | Ensure renavigating in component init works with enabledBlocking ([#48063](https://github.com/angular/angular/pull/48063)) |
| [1976e37475](https://github.com/angular/angular/commit/1976e37475e144d4df27b1558b2acd929bd439be) | fix | restore 'history.state' on popstate even if navigationId missing ([#48033](https://github.com/angular/angular/pull/48033)) |
## Special Thanks
Alan Agius, Andrew Kushnir, Andrew Scott, Bjarki, Bob Watson, Brooke, Derek Cormier, Dylan Hunn, George Kalpakas, Greg Magolan, Ikko Ashimine, Ivan Rodriguez, Jessica Janiuk, JiaLiPassion, Joe Roxbury, Joey Perrott, Kristiyan Kostadinov, Matthieu Riegler, Mikhail Savchuk, Nebojsa Cvetkovic, Pawel Kozlowski, Volodymyr, Wooshaah and mgechev
<!-- CHANGELOG SPLIT MARKER -->
<a name="12.2.17"></a>
# 12.2.17 (2022-11-22)
## Breaking Changes
@@ -7,7 +7,7 @@ import { Component, OnInit, Input } from '@angular/core';
templateUrl: './item-detail.component.html',
styleUrls: ['./item-detail.component.css']
})
export class ItemDetailComponent implements OnInit {
export class ItemDetailComponent {
// #docregion input-type
@Input() childItem = '';
@@ -18,9 +18,4 @@ export class ItemDetailComponent implements OnInit {
currentItem = 'bananas in boxes';
constructor() { }
ngOnInit() {
}
}
@@ -12,6 +12,5 @@ export class ItemListComponent {
// #docregion item-input
@Input() items: Item[] = [];
// #enddocregion item-input
constructor() { }
}
@@ -3,7 +3,4 @@ import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class MyLibService {
constructor() { }
}
export class MyLibService {}
@@ -1,6 +1,6 @@
// #docplaster
// #docregion, v1
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';
// #enddocregion v1
import { Hero } from '../hero';
// #docregion v1
@@ -10,7 +10,7 @@ import { Hero } from '../hero';
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
export class HeroesComponent {
// #enddocregion, v1
/*
// #docregion add-hero
@@ -23,11 +23,5 @@ export class HeroesComponent implements OnInit {
name: 'Windstorm'
};
// #docregion v1
constructor() { }
ngOnInit(): void {
}
}
// #enddocregion, v1
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';
import { Hero } from '../hero';
// #docregion import-heroes
import { HEROES } from '../mock-heroes';
@@ -14,7 +14,7 @@ import { HEROES } from '../mock-heroes';
// #enddocregion metadata
// #docregion component
export class HeroesComponent implements OnInit {
export class HeroesComponent {
heroes = HEROES;
// #enddocregion component
@@ -22,11 +22,6 @@ export class HeroesComponent implements OnInit {
selectedHero?: Hero;
// #enddocregion on-select
constructor() { }
ngOnInit(): void {
}
// #docregion on-select
onSelect(hero: Hero): void {
this.selectedHero = hero;
@@ -1,6 +1,6 @@
// #docregion
// #docregion import-input
import { Component, OnInit, Input } from '@angular/core';
import { Component, Input } from '@angular/core';
// #enddocregion import-input
// #docregion import-hero
import { Hero } from '../hero';
@@ -11,14 +11,8 @@ import { Hero } from '../hero';
templateUrl: './hero-detail.component.html',
styleUrls: ['./hero-detail.component.css']
})
export class HeroDetailComponent implements OnInit {
export class HeroDetailComponent {
// #docregion input-hero
@Input() hero?: Hero;
// #enddocregion input-hero
constructor() { }
ngOnInit(): void {
}
}
@@ -1,5 +1,5 @@
// #docregion
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';
// #docregion import-message-service
import { MessageService } from '../message.service';
// #enddocregion import-message-service
@@ -9,13 +9,10 @@ import { MessageService } from '../message.service';
templateUrl: './messages.component.html',
styleUrls: ['./messages.component.css']
})
export class MessagesComponent implements OnInit {
export class MessagesComponent {
// #docregion ctor
constructor(public messageService: MessageService) {}
// #enddocregion ctor
ngOnInit() {
}
}
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';
import { MessageService } from '../message.service';
@Component({
@@ -6,11 +6,8 @@ import { MessageService } from '../message.service';
templateUrl: './messages.component.html',
styleUrls: ['./messages.component.css']
})
export class MessagesComponent implements OnInit {
export class MessagesComponent {
constructor(public messageService: MessageService) {}
ngOnInit() {
}
}
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';
import { MessageService } from '../message.service';
@Component({
@@ -6,11 +6,8 @@ import { MessageService } from '../message.service';
templateUrl: './messages.component.html',
styleUrls: ['./messages.component.css']
})
export class MessagesComponent implements OnInit {
export class MessagesComponent {
constructor(public messageService: MessageService) {}
ngOnInit() {
}
}
@@ -6,7 +6,6 @@ import { Component } from '@angular/core';
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor() { }
// #docregion font-size
fontSizePx = 16;
// #enddocregion font-size
+5 -5
View File
@@ -1,15 +1,15 @@
import 'zone.js/node';
import { APP_BASE_HREF } from '@angular/common';
import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { existsSync } from 'fs';
import { join } from 'path';
import { AppServerModule } from './src/main.server';
import { APP_BASE_HREF } from '@angular/common';
import { existsSync } from 'fs';
// The Express app is exported so that it can be used by serverless Functions.
export function app() {
export function app(): express.Express {
const server = express();
const distFolder = join(process.cwd(), 'dist/browser');
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
@@ -48,8 +48,8 @@ export function app() {
return server;
}
function run() {
const port = process.env.PORT || 4000;
function run(): void {
const port = process.env['PORT'] || 4000;
// Start up the Node server
const server = app();
@@ -1,9 +1 @@
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
export { AppServerModule } from './app/app.server.module';
@@ -2,14 +2,9 @@
"extends": "./tsconfig.app.json",
"compilerOptions": {
"outDir": "./out-tsc/app-server",
"module": "commonjs",
"types": ["node"]
},
"files": [
"src/main.server.ts",
"server.ts"
],
"angularCompilerOptions": {
"entryModule": "./src/app/app.server.module#AppServerModule"
}
]
}
@@ -1,15 +1,10 @@
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor() { }
ngOnInit() {
}
export class HomeComponent {
}
+2 -2
View File
@@ -56,8 +56,8 @@ Superpower boost: 1024
<div class="alert is-helpful">
To examine the behavior of the `exponentialStrength` pipe in the <live-example></live-example>, change the value and optional exponent in the template.
To examine the behavior of the `exponentialStrength` pipe in the <live-example name="pipes"></live-example>, change the value and optional exponent in the template.
</div>
@reviewed 2022-04-01
@reviewed 2023-01-06
-3
View File
@@ -115,9 +115,6 @@ For customers to see their cart, you can create the cart view in two steps:
<code-example header="src/app/cart/cart.component.ts" path="getting-started/src/app/cart/cart.component.1.ts"></code-example>
StackBlitz also generates an `ngOnInit()` by default in components.
You can ignore the `CartComponent` `ngOnInit()` for this tutorial.
1. Notice that the newly created `CartComponent` is added to the module's `declarations` in `app.module.ts`.
<code-example header="src/app/app.module.ts" path="getting-started/src/app/app.module.ts" region="declare-cart"></code-example>
@@ -41,10 +41,6 @@ You always import the `Component` symbol from the Angular core library and annot
The [CSS element selector](https://developer.mozilla.org/docs/Web/CSS/Type_selectors), `'app-heroes'`, matches the name of the HTML element that identifies this component within a parent component's template.
The `ngOnInit()` is a [lifecycle hook](guide/lifecycle-hooks#oninit).
Angular calls `ngOnInit()` shortly after creating a component.
It's a good place to put initialization logic.
Always `export` the component class so you can `import` it elsewhere &hellip; like in the `AppModule`.
### Add a `hero` property
+1 -1
View File
@@ -131,7 +131,7 @@
"jasmine": "~4.5.0",
"jasmine-core": "~4.5.0",
"jasmine-spec-reporter": "~7.0.0",
"jsdom": "^20.0.0",
"jsdom": "^21.0.0",
"json-schema-traverse": "^1.0.0",
"json5": "^2.2.0",
"karma": "~6.4.0",
+9
View File
@@ -0,0 +1,9 @@
/**
* @file Spec file loaded by Protractor. It is not guaranteed
* to load before other spec files. Jasmine tests execute after all
* files are loaded, so this file can be used for initialization.
*/
// Increase the timeout for specs as Selenium & Protractor is slow.
// Default Protractor timeout is 30 seconds.
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000;
+4 -3
View File
@@ -57,8 +57,9 @@ export class ExampleZipper {
return archive;
}
_getExampleType(sourceFolder) {
const filePath = path.join(sourceFolder, EXAMPLE_CONFIG_NAME);
_getExampleType(exampleDirName) {
const filePath = path.join(exampleDirName, EXAMPLE_CONFIG_NAME);
try {
return this._loadJson(filePath).projectType || 'cli';
} catch (err) { // empty file, so it is cli
@@ -89,7 +90,6 @@ export class ExampleZipper {
const jsonFileName = configFileName.replace(/^.*[\\\/]/, '');
let relativeDirName = path.basename(sourceDirName);
let exampleZipName;
const exampleType = this._getExampleType(path.join(sourceDirName, relativeDirName));
if (relativeDirName.indexOf('/') !== -1) { // Special example
exampleZipName = relativeDirName.split('/').join('-');
} else {
@@ -97,6 +97,7 @@ export class ExampleZipper {
}
const exampleDirName = path.dirname(configFileName);
const exampleType = this._getExampleType(exampleDirName);
const outputFileName = path.join(outputDirName, exampleZipName + '.zip');
let defaultIncludes = ['**/*.ts', '**/*.js', '**/*.es6', '**/*.css', '**/*.html', '**/*.md', '**/*.json', '**/*.png', '**/*.svg'];
let alwaysIncludes = [
+4 -4
View File
@@ -8688,10 +8688,10 @@ jsdoc@^3.6.3:
taffydb "2.6.2"
underscore "~1.13.2"
jsdom@^20.0.0:
version "20.0.3"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-20.0.3.tgz#886a41ba1d4726f67a8858028c99489fed6ad4db"
integrity sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==
jsdom@^21.0.0:
version "21.0.0"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-21.0.0.tgz#33e22f2fc44286e50ac853c7b7656c8864a4ea45"
integrity sha512-AIw+3ZakSUtDYvhwPwWHiZsUi3zHugpMEKlNPaurviseYoBqo0zBd3zqoUi3LPCNtPFlEP8FiW9MqCZdjb2IYA==
dependencies:
abab "^2.0.6"
acorn "^8.8.1"
+1 -1
View File
@@ -553,7 +553,7 @@ export interface FormRecord<TControl> {
export class FormsModule {
static withConfig(opts: {
callSetDisabledState?: SetDisabledStateOption;
}): ModuleWithProviders<ReactiveFormsModule>;
}): ModuleWithProviders<FormsModule>;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<FormsModule, never>;
// (undocumented)
+1 -1
View File
@@ -25,7 +25,7 @@
* Ideally, we would run `yarn install` with the `--frozen-lockfile` option to verify that the
* lockfile is in-sync with `package.json`, but we cannot do that for integration projects, because
* we want to be able to install the locally built Angular packages). Therefore, we must manually
* esnure that the integration project lockfiles remain in-sync, which is error-prone.
* ensure that the integration project lockfiles remain in-sync, which is error-prone.
*
* The checks performed by this script (although not full-proof) provide another line of defense
* against indeterminism caused by unpinned dependencies.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "angular-srcs",
"version": "15.1.0-next.3",
"version": "15.1.0",
"private": true,
"description": "Angular - a web framework for modern web apps",
"homepage": "https://github.com/angular/angular",
+2 -8
View File
@@ -226,9 +226,8 @@ export function compile({
return delegate(fileName.replace(/\.(ngfactory|ngsummary)\.ts$/, '.ts'));
};
// By default, disable tsickle decorator transforming in the tsickle compiler host.
// The Angular compilers have their own logic for decorator processing and we wouldn't
// want tsickle to interfere with that.
// Never run the tsickle decorator transform.
// TODO(b/254054103): Remove the transform and this flag.
bazelHost.transformDecorators = false;
// By default in the `prodmode` output, we do not add annotations for closure compiler.
@@ -238,11 +237,6 @@ export function compile({
if (!bazelOpts.es5Mode && !bazelOpts.devmode) {
if (bazelOpts.workspaceName === 'google3') {
compilerOpts.annotateForClosureCompiler = true;
// Enable the tsickle decorator transform in google3 with Ivy mode enabled. The tsickle
// decorator transformation is still needed. This might be because of custom decorators
// with the `@Annotation` JSDoc that will be processed by the tsickle decorator transform.
// TODO: Figure out why this is needed in g3 and how we can improve this. FW-2225
bazelHost.transformDecorators = true;
} else {
compilerOpts.annotateForClosureCompiler = false;
}
+6 -7
View File
@@ -168,12 +168,9 @@ export class NgForOf<T, U extends NgIterable<T> = NgIterable<T>> implements DoCh
@Input()
set ngForTrackBy(fn: TrackByFunction<T>) {
if (NG_DEV_MODE && fn != null && typeof fn !== 'function') {
// TODO(vicb): use a log service once there is a public one available
if (<any>console && <any>console.warn) {
console.warn(
`trackBy must be a function, but received ${JSON.stringify(fn)}. ` +
`See https://angular.io/api/common/NgForOf#change-propagation for more information.`);
}
console.warn(
`trackBy must be a function, but received ${JSON.stringify(fn)}. ` +
`See https://angular.io/api/common/NgForOf#change-propagation for more information.`);
}
this._trackByFn = fn;
}
@@ -185,7 +182,9 @@ export class NgForOf<T, U extends NgIterable<T> = NgIterable<T>> implements DoCh
private _ngForOf: U|undefined|null = null;
private _ngForOfDirty: boolean = true;
private _differ: IterableDiffer<T>|null = null;
// TODO(issue/24571): remove '!'.
// TODO(issue/24571): remove '!'
// waiting for microsoft/typescript#43662 to allow the return type `TrackByFunction|undefined` for
// the getter
private _trackByFn!: TrackByFunction<T>;
constructor(
+4 -9
View File
@@ -12,7 +12,6 @@ import {getPluralCategory, NgLocalization} from '../i18n/localization';
import {SwitchView} from './ng_switch';
/**
* @ngModule CommonModule
*
@@ -49,29 +48,25 @@ import {SwitchView} from './ng_switch';
standalone: true,
})
export class NgPlural {
// TODO(issue/24571): remove '!'.
private _switchValue!: number;
// TODO(issue/24571): remove '!'.
private _activeView!: SwitchView;
private _activeView?: SwitchView;
private _caseViews: {[k: string]: SwitchView} = {};
constructor(private _localization: NgLocalization) {}
@Input()
set ngPlural(value: number) {
this._switchValue = value;
this._updateView();
this._updateView(value);
}
addCase(value: string, switchView: SwitchView): void {
this._caseViews[value] = switchView;
}
private _updateView(): void {
private _updateView(switchValue: number): void {
this._clearViews();
const cases = Object.keys(this._caseViews);
const key = getPluralCategory(this._switchValue, cases, this._localization);
const key = getPluralCategory(switchValue, cases, this._localization);
this._activateView(this._caseViews[key]);
}
+3 -8
View File
@@ -106,8 +106,7 @@ export class SwitchView {
standalone: true,
})
export class NgSwitch {
// TODO(issue/24571): remove '!'.
private _defaultViews!: SwitchView[];
private _defaultViews: SwitchView[] = [];
private _defaultUsed = false;
private _caseCount = 0;
private _lastCaseCheckIndex = 0;
@@ -129,9 +128,6 @@ export class NgSwitch {
/** @internal */
_addDefault(view: SwitchView) {
if (!this._defaultViews) {
this._defaultViews = [];
}
this._defaultViews.push(view);
}
@@ -149,10 +145,9 @@ export class NgSwitch {
}
private _updateDefaultCases(useDefault: boolean) {
if (this._defaultViews && useDefault !== this._defaultUsed) {
if (this._defaultViews.length > 0 && useDefault !== this._defaultUsed) {
this._defaultUsed = useDefault;
for (let i = 0; i < this._defaultViews.length; i++) {
const defaultView = this._defaultViews[i];
for (const defaultView of this._defaultViews) {
defaultView.enforceState(useDefault);
}
}
@@ -183,7 +183,7 @@ describe('insert/remove', () => {
fixture.componentInstance.currentComponent = Module2InjectedComponent;
fixture.detectChanges();
const moduleRef = fixture.componentInstance.ngComponentOutlet['_moduleRef']!;
const moduleRef = fixture.componentInstance.ngComponentOutlet?.['_moduleRef']!;
spyOn(moduleRef, 'destroy').and.callThrough();
expect(moduleRef.destroy).not.toHaveBeenCalled();
@@ -197,7 +197,7 @@ describe('insert/remove', () => {
fixture.componentInstance.currentComponent = Module2InjectedComponent;
fixture.detectChanges();
const moduleRef = fixture.componentInstance.ngComponentOutlet['_moduleRef']!;
const moduleRef = fixture.componentInstance.ngComponentOutlet?.['_moduleRef']!;
spyOn(moduleRef, 'destroy').and.callThrough();
expect(moduleRef.destroy).not.toHaveBeenCalled();
@@ -213,13 +213,13 @@ describe('insert/remove', () => {
fixture.componentInstance.currentComponent = Module2InjectedComponent;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('baz');
const moduleRef = fixture.componentInstance.ngComponentOutlet['_moduleRef'];
const moduleRef = fixture.componentInstance.ngComponentOutlet?.['_moduleRef'];
fixture.componentInstance.currentComponent = Module2InjectedComponent2;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('baz2');
expect(moduleRef).toBe(fixture.componentInstance.ngComponentOutlet['_moduleRef']);
expect(moduleRef).toBe(fixture.componentInstance.ngComponentOutlet?.['_moduleRef']);
}));
it('should re-create moduleRef when changed (NgModuleFactory)', waitForAsync(() => {
@@ -322,16 +322,16 @@ class TestComponent {
ngModuleFactory?: NgModuleFactory<unknown>;
get cmpRef(): ComponentRef<any>|undefined {
return this.ngComponentOutlet['_componentRef'];
return this.ngComponentOutlet?.['_componentRef'];
}
set cmpRef(value: ComponentRef<any>|undefined) {
this.ngComponentOutlet['_componentRef'] = value;
if (this.ngComponentOutlet) {
this.ngComponentOutlet['_componentRef'] = value;
}
}
// TODO(issue/24571): remove '!'.
@ViewChildren(TemplateRef) tplRefs!: QueryList<TemplateRef<any>>;
// TODO(issue/24571): remove '!'.
@ViewChild(NgComponentOutlet, {static: true}) ngComponentOutlet!: NgComponentOutlet;
@ViewChildren(TemplateRef) tplRefs: QueryList<TemplateRef<any>> = new QueryList();
@ViewChild(NgComponentOutlet, {static: true}) ngComponentOutlet?: NgComponentOutlet;
constructor(public vcRef: ViewContainerRef) {}
}
@@ -338,14 +338,12 @@ class DestroyableCmpt implements OnDestroy {
@Directive({selector: 'tpl-refs', exportAs: 'tplRefs'})
class CaptureTplRefs {
// TODO(issue/24571): remove '!'.
@ContentChildren(TemplateRef) tplRefs!: QueryList<TemplateRef<any>>;
@ContentChildren(TemplateRef) tplRefs?: QueryList<TemplateRef<any>>;
}
@Component({selector: 'test-cmp', template: ''})
class TestComponent {
// TODO(issue/24571): remove '!'.
currentTplRef!: TemplateRef<any>;
currentTplRef?: TemplateRef<any>;
context: any = {foo: 'bar'};
value = 'bar';
injector: Injector|null = null;
@@ -10,7 +10,7 @@ import ts from 'typescript';
export function aliasTransformFactory(exportStatements: Map<string, Map<string, [string, string]>>):
ts.TransformerFactory<ts.SourceFile> {
return (context: ts.TransformationContext) => {
return () => {
return (file: ts.SourceFile) => {
if (ts.isBundle(file) || !exportStatements.has(file.fileName)) {
return file;
@@ -19,10 +19,9 @@ export function aliasTransformFactory(exportStatements: Map<string, Map<string,
const statements = [...file.statements];
exportStatements.get(file.fileName)!.forEach(([moduleName, symbolName], aliasName) => {
const stmt = ts.factory.createExportDeclaration(
/* decorators */ undefined,
/* modifiers */ undefined,
/* isTypeOnly */ false,
/* exportClause */ ts.createNamedExports([ts.factory.createExportSpecifier(
/* exportClause */ ts.factory.createNamedExports([ts.factory.createExportSpecifier(
false, symbolName, aliasName)]),
/* moduleSpecifier */ ts.factory.createStringLiteral(moduleName));
statements.push(stmt);
@@ -208,19 +208,19 @@ yarn test //packages/compiler-cli/test/compliance/linked --config=debug
To debug generating the partial golden output use the following form of Bazel command:
```sh
yarn bazel run //packages/compiler-cli/test/compliance/test_cases:generate_partial_for_<path/to/test_case>.debug
yarn bazel run //packages/compiler-cli/test/compliance/test_cases:partial_<path/to/test_case>.debug
```
The `path/to/test_case` is relative to the `test_cases` directory. So for this `TEST_CASES.json` file at:
```
packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_directives/directives/matching/TEST_CASES.json
packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_directives/matching/TEST_CASES.json
```
The command to debug the test-cases would be:
```
yarn bazel run //packages/compiler-cli/test/compliance/test_cases:generate_partial_for_r3_view_compiler_directives/directives/matching.debug
yarn bazel run //packages/compiler-cli/test/compliance/test_cases:partial_r3_view_compiler_directives/matching.debug
```
+1 -1
View File
@@ -38,7 +38,7 @@ export class FormsModule {
*/
static withConfig(opts: {
callSetDisabledState?: SetDisabledStateOption,
}): ModuleWithProviders<ReactiveFormsModule> {
}): ModuleWithProviders<FormsModule> {
return {
ngModule: FormsModule,
providers: [{
+14 -14
View File
@@ -112,14 +112,14 @@ class CustomValidatorDirective implements Validator {
describe('composeValidators', () => {
it('should compose functions', () => {
const dummy1 = (_: any /** TODO #9100 */) => ({'dummy1': true});
const dummy2 = (_: any /** TODO #9100 */) => ({'dummy2': true});
const dummy1 = () => ({'dummy1': true});
const dummy2 = () => ({'dummy2': true});
const v = composeValidators([dummy1, dummy2])!;
expect(v(new FormControl(''))).toEqual({'dummy1': true, 'dummy2': true});
});
it('should compose validator directives', () => {
const dummy1 = (_: any /** TODO #9100 */) => ({'dummy1': true});
const dummy1 = () => ({'dummy1': true});
const v = composeValidators([dummy1, new CustomValidatorDirective()])!;
expect(v(new FormControl(''))).toEqual({'dummy1': true, 'custom': true});
});
@@ -309,10 +309,10 @@ class CustomValidatorDirective implements Validator {
});
describe('NgForm', () => {
let form: any /** TODO #9100 */;
let form: NgForm;
let formModel: FormGroup;
let loginControlDir: any /** TODO #9100 */;
let personControlGroupDir: any /** TODO #9100 */;
let loginControlDir: NgModel;
let personControlGroupDir: NgModelGroup;
beforeEach(() => {
form = new NgForm([], []);
@@ -384,7 +384,7 @@ class CustomValidatorDirective implements Validator {
});
it('should set up sync validator', fakeAsync(() => {
const formValidator = (c: any /** TODO #9100 */) => ({'custom': true});
const formValidator = () => ({'custom': true});
const f = new NgForm([formValidator], []);
tick();
@@ -402,8 +402,8 @@ class CustomValidatorDirective implements Validator {
});
describe('FormGroupName', () => {
let formModel: any /** TODO #9100 */;
let controlGroupDir: any /** TODO #9100 */;
let formModel: FormGroup;
let controlGroupDir: FormGroupName;
beforeEach(() => {
formModel = new FormGroup({'login': new FormControl(null)});
@@ -481,9 +481,9 @@ class CustomValidatorDirective implements Validator {
});
describe('FormControlDirective', () => {
let controlDir: any /** TODO #9100 */;
let control: any /** TODO #9100 */;
const checkProperties = function(control: AbstractControl) {
let controlDir: FormControlDirective;
let control: FormControl;
const checkProperties = function(control: FormControl) {
expect(controlDir.control).toBe(control);
expect(controlDir.value).toBe(control.value);
expect(controlDir.valid).toBe(control.valid);
@@ -648,8 +648,8 @@ class CustomValidatorDirective implements Validator {
});
describe('FormControlName', () => {
let formModel: any /** TODO #9100 */;
let controlNameDir: any /** TODO #9100 */;
let formModel: FormControl;
let controlNameDir: FormControlName;
beforeEach(() => {
formModel = new FormControl('name');
+1 -1
View File
@@ -850,7 +850,7 @@ describe('FormArray', () => {
describe('valueChanges', () => {
let a: FormArray;
let c1: any /** TODO #9100 */, c2: any /** TODO #9100 */;
let c1: FormControl, c2: FormControl;
beforeEach(() => {
c1 = new FormControl('old1');
+2 -2
View File
@@ -11,10 +11,10 @@ import {FormBuilder, NonNullableFormBuilder, ReactiveFormsModule, UntypedFormBui
import {of} from 'rxjs';
(function() {
function syncValidator(_: any /** TODO #9100 */): any /** TODO #9100 */ {
function syncValidator() {
return null;
}
function asyncValidator(_: any /** TODO #9100 */) {
function asyncValidator() {
return Promise.resolve(null);
}
+6 -5
View File
@@ -7,7 +7,7 @@
*/
import {fakeAsync, tick} from '@angular/core/testing';
import {FormArray, FormControl, FormGroup, Validators} from '@angular/forms';
import {AsyncValidatorFn, FormArray, FormControl, FormGroup, Validators} from '@angular/forms';
import {asyncValidator, asyncValidatorReturningObservable} from './util';
@@ -16,7 +16,7 @@ function otherAsyncValidator() {
return Promise.resolve({'other': true});
}
function syncValidator(_: any /** TODO #9100 */): any /** TODO #9100 */ {
function syncValidator() {
return null;
}
@@ -1105,7 +1105,7 @@ describe('FormControl', () => {
it('should fire an event after the status has been updated to pending', fakeAsync(() => {
const c = new FormControl('old', Validators.required, asyncValidator('expected'));
const log: any[] /** TODO #9100 */ = [];
const log: string[] = [];
c.valueChanges.subscribe({next: (value: any) => log.push(`value: '${value}'`)});
c.statusChanges.subscribe({next: (status: any) => log.push(`status: '${status}'`)});
@@ -1133,7 +1133,7 @@ describe('FormControl', () => {
// TODO: remove the if statement after making observable delivery sync
it('should update set errors and status before emitting an event', done => {
c.valueChanges.subscribe((value: any /** TODO #9100 */) => {
c.valueChanges.subscribe(() => {
expect(c.valid).toEqual(false);
expect(c.errors).toEqual({'required': true});
done();
@@ -1507,7 +1507,8 @@ describe('FormControl', () => {
});
it('should throw when sync validator passed into async validator param', () => {
const fn = () => new FormControl('', syncValidator, syncValidator);
const fn = () =>
new FormControl('', syncValidator, syncValidator as unknown as AsyncValidatorFn);
// test for the specific error since without the error check it would still throw an error
// but
// not a meaningful one
+14 -3
View File
@@ -30,9 +30,19 @@ esbuild(
deps = [":factory_lib"],
)
esbuild(
name = "api_bundle",
entry_point = ":api.ts",
format = "cjs",
deps = [":api"],
)
extract_types(
name = "factory_types",
deps = [":factory_lib"],
name = "types",
deps = [
":api",
":factory_lib",
],
)
pkg_npm(
@@ -55,8 +65,9 @@ pkg_npm(
"//integration:__subpackages__",
],
deps = [
":api_bundle",
":factory_bundle",
":factory_types",
":types",
"//packages/language-service/bundles:language-service.js",
],
)
+1 -1
View File
@@ -38,6 +38,6 @@ npm_package(
visibility = ["//visibility:public"],
)
EOT
_sedi 's#\# PLACE_HOLDER_FOR_packages/language-service/build.sh_IN_angular_REPO#data = ["//.angular_packages/language-service:package.json"], \# FOR TESTING ONLY! DO NOT COMMIT THIS LINE!#' WORKSPACE
_sedi 's#\# PLACE_HOLDER_FOR_angular/angular_packages/language-service/build.sh#"//.angular_packages/language-service:package.json", \# FOR TESTING ONLY! DO NOT COMMIT THIS LINE!#' WORKSPACE
yarn add @angular/language-service@file:".angular_packages/language-service"
popd
+13
View File
@@ -9,6 +9,19 @@
"engines": {
"node": "^14.20.0 || ^16.13.0 || >=18.10.0"
},
"exports": {
".": {
"types": "./index.d.ts",
"default": "./index.js"
},
"./package.json": {
"default": "./package.json"
},
"./api": {
"types": "./api.d.ts",
"default": "./api_bundle.js"
}
},
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.git",
@@ -8,6 +8,7 @@ ng_module(
name = "testing",
srcs = glob(["**/*.ts"]),
deps = [
"//packages/common/testing",
"//packages/core",
"//packages/core/testing",
"//packages/platform-browser",
@@ -5,10 +5,13 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {PlatformLocation} from '@angular/common';
import {MockPlatformLocation} from '@angular/common/testing';
import {APP_ID, createPlatformFactory, NgModule, NgZone, PLATFORM_INITIALIZER, platformCore, StaticProvider} from '@angular/core';
import {BrowserModule, ɵBrowserDomAdapter as BrowserDomAdapter} from '@angular/platform-browser';
import {BrowserDetection, createNgZone} from './browser_util';
import {ENABLE_MOCK_PLATFORM_LOCATION} from './mock_platform_location_flag';
function initBrowserTests() {
BrowserDomAdapter.makeCurrent();
@@ -36,6 +39,8 @@ export const platformBrowserTesting =
providers: [
{provide: APP_ID, useValue: 'a'},
{provide: NgZone, useFactory: createNgZone},
(ENABLE_MOCK_PLATFORM_LOCATION ? [{provide: PlatformLocation, useClass: MockPlatformLocation}] :
[]),
]
})
export class BrowserTestingModule {
@@ -0,0 +1,17 @@
/**
* @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.io/license
*/
/**
* Controls whether the `MockPlatformLocation` class should be used
* as the `PlatformLocation` implementation when the `BrowserTestingModule`
* is imported.
*
* In v16, the value of this flag will be switched to `true` to enable
* the `MockPlatformLocation` by default.
*/
export const ENABLE_MOCK_PLATFORM_LOCATION = false;
+1
View File
@@ -19,6 +19,7 @@ import {ActivatedRouteSnapshot, RouterStateSnapshot} from './router_state';
* @publicApi
*/
export type NavigationTrigger = 'imperative'|'popstate'|'hashchange';
export const IMPERATIVE_NAVIGATION = 'imperative';
/**
* Identifies the type of a router event.
+22 -14
View File
@@ -11,7 +11,7 @@ import {BehaviorSubject, combineLatest, EMPTY, Observable, of, Subject} from 'rx
import {catchError, defaultIfEmpty, filter, finalize, map, switchMap, take, tap} from 'rxjs/operators';
import {createRouterState} from './create_router_state';
import {Event, GuardsCheckEnd, GuardsCheckStart, NavigationCancel, NavigationCancellationCode, NavigationEnd, NavigationError, NavigationSkipped, NavigationSkippedCode, NavigationStart, NavigationTrigger, ResolveEnd, ResolveStart, RouteConfigLoadEnd, RouteConfigLoadStart, RoutesRecognized} from './events';
import {Event, GuardsCheckEnd, GuardsCheckStart, IMPERATIVE_NAVIGATION, NavigationCancel, NavigationCancellationCode, NavigationEnd, NavigationError, NavigationSkipped, NavigationSkippedCode, NavigationStart, NavigationTrigger, ResolveEnd, ResolveStart, RouteConfigLoadEnd, RouteConfigLoadStart, RoutesRecognized} from './events';
import {NavigationBehaviorOptions, QueryParamsHandling, Route, Routes} from './models';
import {isNavigationCancelingError, isRedirectingNavigationCancelingError, redirectingNavigationError} from './navigation_canceling_error';
import {activateRoutes} from './operators/activate_routes';
@@ -270,7 +270,6 @@ interface InternalRouterInterface {
errorHandler: ErrorHandler;
titleStrategy?: TitleStrategy;
navigated: boolean;
afterPreactivation: () => Observable<void>;
urlHandlingStrategy: UrlHandlingStrategy;
routeReuseStrategy: RouteReuseStrategy;
onSameUrlNavigation: 'reload'|'ignore';
@@ -278,7 +277,6 @@ interface InternalRouterInterface {
urlUpdateStrategy: 'deferred'|'eager';
serializeUrl(url: UrlTree): string;
config: Routes;
rootComponentType: Type<any>|null;
setBrowserUrl(url: UrlTree, t: NavigationTransition): void;
restoreHistory(t: NavigationTransition, restoringFromCaughtError?: boolean): void;
scheduleNavigation(
@@ -301,6 +299,15 @@ export class NavigationTransitions {
return this.navigationId !== 0;
}
private transitions?: BehaviorSubject<NavigationTransition>;
/**
* Hook that enables you to pause navigation after the preactivation phase.
* Used by `RouterModule`.
*
* @internal
*/
afterPreactivation: () => Observable<void> = () => of(void 0);
/** @internal */
rootComponentType: Type<any>|null = null;
constructor() {
const onLoadStart = (r: Route) => this.events.next(new RouteConfigLoadStart(r));
@@ -335,7 +342,7 @@ export class NavigationTransitions {
resolve: null,
reject: null,
promise: Promise.resolve(true),
source: 'imperative',
source: IMPERATIVE_NAVIGATION,
restoredState: null,
currentSnapshot: router.routerState.snapshot,
targetSnapshot: null,
@@ -437,7 +444,7 @@ export class NavigationTransitions {
// Recognize
recognize(
this.environmentInjector, router.rootComponentType,
this.environmentInjector, this.rootComponentType,
router.config, this.urlSerializer,
router.paramsInheritanceStrategy),
@@ -472,7 +479,7 @@ export class NavigationTransitions {
restoredState);
this.events.next(navStart);
const targetSnapshot =
createEmptyState(extractedUrl, router.rootComponentType).snapshot;
createEmptyState(extractedUrl, this.rootComponentType).snapshot;
overallTransitionState = {
...t,
@@ -614,7 +621,7 @@ export class NavigationTransitions {
.pipe(defaultIfEmpty(), take(1));
}),
switchTap(() => router.afterPreactivation()),
switchTap(() => this.afterPreactivation()),
map((t: NavigationTransition) => {
const targetRouterState = createRouterState(
@@ -726,11 +733,12 @@ export class NavigationTransitions {
isBrowserTriggeredNavigation(overallTransitionState.source)
};
router.scheduleNavigation(mergedTree, 'imperative', null, extras, {
resolve: overallTransitionState.resolve,
reject: overallTransitionState.reject,
promise: overallTransitionState.promise
});
router.scheduleNavigation(
mergedTree, IMPERATIVE_NAVIGATION, null, extras, {
resolve: overallTransitionState.resolve,
reject: overallTransitionState.reject,
promise: overallTransitionState.promise
});
}
/* All other errors should reset to the router's internal URL reference
@@ -764,6 +772,6 @@ export class NavigationTransitions {
}
}
export function isBrowserTriggeredNavigation(source: 'imperative'|'popstate'|'hashchange') {
return source !== 'imperative';
export function isBrowserTriggeredNavigation(source: NavigationTrigger) {
return source !== IMPERATIVE_NAVIGATION;
}
+1 -1
View File
@@ -358,7 +358,7 @@ export function withEnabledBlockingInitialNavigation(): EnabledBlockingInitialNa
resolve(true);
});
router.afterPreactivation = () => {
injector.get(NavigationTransitions).afterPreactivation = () => {
// Unblock APP_INITIALIZER once we get to `afterPreactivation`. At this point, we
// assume activation will complete successfully (even though this is not
// guaranteed).
+44 -46
View File
@@ -12,7 +12,7 @@ import {BehaviorSubject, Observable, of, SubscriptionLike} from 'rxjs';
import {CreateUrlTreeStrategy} from './create_url_tree_strategy';
import {RuntimeErrorCode} from './errors';
import {Event, NavigationTrigger} from './events';
import {Event, IMPERATIVE_NAVIGATION, NavigationTrigger} from './events';
import {NavigationBehaviorOptions, OnSameUrlNavigation, Routes} from './models';
import {Navigation, NavigationExtras, NavigationTransition, NavigationTransitions, RestoredState, UrlCreationOptions} from './navigation_transition';
import {TitleStrategy} from './page_title_strategy';
@@ -203,14 +203,6 @@ export class Router {
navigated: boolean = false;
private lastSuccessfulId: number = -1;
/**
* Hook that enables you to pause navigation after the preactivation phase.
* Used by `RouterModule`.
*
* @internal
*/
afterPreactivation: () => Observable<void> = () => of(void 0);
/**
* A strategy for extracting and merging URLs.
* Used for AngularJS to Angular migrations.
@@ -316,9 +308,6 @@ export class Router {
private readonly urlSerializer = inject(UrlSerializer);
private readonly location = inject(Location);
/** @internal */
rootComponentType: Type<any>|null = null;
constructor() {
this.isNgZoneEnabled = inject(NgZone) instanceof NgZone && NgZone.isInAngularZone();
@@ -327,7 +316,7 @@ export class Router {
this.rawUrlTree = this.currentUrlTree;
this.browserUrlTree = this.currentUrlTree;
this.routerState = createEmptyState(this.currentUrlTree, this.rootComponentType);
this.routerState = createEmptyState(this.currentUrlTree, null);
this.navigationTransitions.setupNavigations(this).subscribe(
t => {
@@ -341,10 +330,10 @@ export class Router {
/** @internal */
resetRootComponentType(rootComponentType: Type<any>): void {
this.rootComponentType = rootComponentType;
// TODO: vsavkin router 4.0 should make the root component set to null
// this will simplify the lifecycle of the router.
this.routerState.root.component = this.rootComponentType;
this.routerState.root.component = rootComponentType;
this.navigationTransitions.rootComponentType = rootComponentType;
}
/**
@@ -353,7 +342,8 @@ export class Router {
initialNavigation(): void {
this.setUpLocationChangeListener();
if (!this.navigationTransitions.hasRequestedNavigation) {
this.navigateByUrl(this.location.path(true), {replaceUrl: true});
const state = this.location.getState() as RestoredState;
this.navigateToSyncWithBrowser(this.location.path(true), IMPERATIVE_NAVIGATION, state);
}
}
@@ -373,37 +363,49 @@ export class Router {
// The `setTimeout` was added in #12160 and is likely to support Angular/AngularJS
// hybrid apps.
setTimeout(() => {
const extras: NavigationExtras = {replaceUrl: true};
// TODO: restoredState should always include the entire state, regardless
// of navigationId. This requires a breaking change to update the type on
// NavigationStart’s restoredState, which currently requires navigationId
// to always be present. The Router used to only restore history state if
// a navigationId was present.
// The stored navigationId is used by the RouterScroller to retrieve the scroll
// position for the page.
const restoredState = event.state?.navigationId ? event.state : null;
// Separate to NavigationStart.restoredState, we must also restore the state to
// history.state and generate a new navigationId, since it will be overwritten
if (event.state) {
const stateCopy = {...event.state} as Partial<RestoredState>;
delete stateCopy.navigationId;
delete stateCopy.ɵrouterPageId;
if (Object.keys(stateCopy).length !== 0) {
extras.state = stateCopy;
}
}
const urlTree = this.parseUrl(event['url']!);
this.scheduleNavigation(urlTree, source, restoredState, extras);
this.navigateToSyncWithBrowser(event['url']!, source, event.state);
}, 0);
}
});
}
}
/**
* Schedules a router navigation to synchronize Router state with the browser state.
*
* This is done as a response to a popstate event and the initial navigation. These
* two scenarios represent times when the browser URL/state has been updated and
* the Router needs to respond to ensure its internal state matches.
*/
private navigateToSyncWithBrowser(
url: string, source: NavigationTrigger, state: RestoredState|undefined) {
const extras: NavigationExtras = {replaceUrl: true};
// TODO: restoredState should always include the entire state, regardless
// of navigationId. This requires a breaking change to update the type on
// NavigationStart’s restoredState, which currently requires navigationId
// to always be present. The Router used to only restore history state if
// a navigationId was present.
// The stored navigationId is used by the RouterScroller to retrieve the scroll
// position for the page.
const restoredState = state?.navigationId ? state : null;
// Separate to NavigationStart.restoredState, we must also restore the state to
// history.state and generate a new navigationId, since it will be overwritten
if (state) {
const stateCopy = {...state} as Partial<RestoredState>;
delete stateCopy.navigationId;
delete stateCopy.ɵrouterPageId;
if (Object.keys(stateCopy).length !== 0) {
extras.state = stateCopy;
}
}
const urlTree = this.parseUrl(url);
this.scheduleNavigation(urlTree, source, restoredState, extras);
}
/** The current URL. */
get url(): string {
return this.serializeUrl(this.currentUrlTree);
@@ -561,7 +563,7 @@ export class Router {
const urlTree = isUrlTree(url) ? url : this.parseUrl(url);
const mergedTree = this.urlHandlingStrategy.merge(urlTree, this.rawUrlTree);
return this.scheduleNavigation(mergedTree, 'imperative', null, extras);
return this.scheduleNavigation(mergedTree, IMPERATIVE_NAVIGATION, null, extras);
}
/**
@@ -686,10 +688,6 @@ export class Router {
let targetPageId: number;
if (this.canceledNavigationResolution === 'computed') {
const isInitialPage = this.currentPageId === 0;
if (isInitialPage) {
restoredState = this.location.getState() as RestoredState | null;
}
// If the `ɵrouterPageId` exist in the state then `targetpageId` should have the value of
// `ɵrouterPageId`. This is the case for something like a page refresh where we assign the
// target id to the previously set value for that page.
@@ -1,10 +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.io/license
*/
// This file exists to easily patch the SpyNgModuleFactoryLoader into g3
export const EXTRA_ROUTER_TESTING_PROVIDERS = [];
@@ -11,8 +11,6 @@ import {provideLocationMocks} from '@angular/common/testing';
import {Compiler, inject, Injector, ModuleWithProviders, NgModule} from '@angular/core';
import {ChildrenOutletContexts, ExtraOptions, NoPreloading, Route, Router, ROUTER_CONFIGURATION, RouteReuseStrategy, RouterModule, ROUTES, Routes, TitleStrategy, UrlHandlingStrategy, UrlSerializer, ɵflatten as flatten, ɵROUTER_PROVIDERS as ROUTER_PROVIDERS, ɵwithPreloading as withPreloading} from '@angular/router';
import {EXTRA_ROUTER_TESTING_PROVIDERS} from './extra_router_testing_providers';
function isUrlHandlingStrategy(opts: ExtraOptions|
UrlHandlingStrategy): opts is UrlHandlingStrategy {
// This property check is needed because UrlHandlingStrategy is an interface and doesn't exist at
@@ -117,7 +115,6 @@ export function setupTestingRouter(
exports: [RouterModule],
providers: [
ROUTER_PROVIDERS,
EXTRA_ROUTER_TESTING_PROVIDERS,
provideLocationMocks(),
withPreloading(NoPreloading).ɵproviders,
{provide: ROUTES, multi: true, useValue: []},
@@ -1,10 +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.io/license
*/
// This file exists for easily patching SpyNgModuleFactoryLoader in g3
export default {};
-1
View File
@@ -12,4 +12,3 @@
* Entry point for all public APIs of the router/testing package.
*/
export * from './router_testing_module';
export * from './spy_ng_module_factory_loader';