mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ee5b1cf076 | |||
| b79b4aca91 | |||
| 019a0f4c22 | |||
| 78533324dc | |||
| 54ea3b65c3 | |||
| 372dd0ab7d | |||
| 3afee8716d | |||
| 56c93d02b5 | |||
| fd88d6a7aa | |||
| 36873596be | |||
| 1693846a9b | |||
| 8239a8f19e | |||
| fbf49b5e9c | |||
| bf70bf6d4f | |||
| b4c4b42222 | |||
| 2643d0a45d | |||
| 55e41d876d | |||
| 1a09d3e44b | |||
| 2820425e38 | |||
| 06ce49aeeb | |||
| d6070afdc2 | |||
| 37e7f2d933 | |||
| 81018d7562 | |||
| 6997c525b5 | |||
| d75eaa7375 | |||
| 630e906747 | |||
| 25788b2919 | |||
| f52eee8eb2 | |||
| 5f2a33ac58 | |||
| 753792856d | |||
| c8f87c8eff |
@@ -22,7 +22,7 @@ jobs:
|
||||
(github.event.action == 'labeled' && github.event.label.name == 'aio: preview') ||
|
||||
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'aio: preview'))
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: ./.github/actions/yarn-install
|
||||
|
||||
- uses: angular/dev-infra/github-actions/bazel/configure-remote@0109d498b0f6aae418ed4924a5e5c65695f0ac61
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
assistant_to_the_branch_manager:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: angular/dev-infra/github-actions/branch-manager@0109d498b0f6aae418ed4924a5e5c65695f0ac61
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
- uses: alessbell/pull-request-comment-branch@aad01d65d6982b8eacabed5e9a684cd8ceb98da6 # v1.1
|
||||
id: comment-branch
|
||||
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
# Specify repository as the PR branch might be from a fork.
|
||||
repository: ${{steps.comment-branch.outputs.head_owner}}/${{steps.comment-branch.outputs.head_repo}}
|
||||
|
||||
@@ -12,14 +12,14 @@ jobs:
|
||||
labels:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
- uses: angular/dev-infra/github-actions/commit-message-based-labels@9b1adb2ad5a049ea9985734f197dca43dd4d3f1b
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: angular/dev-infra/github-actions/commit-message-based-labels@031962443584a0ac5cbd9d1c1b78b241453e4702
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
post_approval_changes:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@9b1adb2ad5a049ea9985734f197dca43dd4d3f1b
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@031962443584a0ac5cbd9d1c1b78b241453e4702
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -13,8 +13,8 @@ jobs:
|
||||
statuses: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
- uses: angular/dev-infra/github-actions/google-internal-tests@9b1adb2ad5a049ea9985734f197dca43dd4d3f1b
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: angular/dev-infra/github-actions/google-internal-tests@031962443584a0ac5cbd9d1c1b78b241453e4702
|
||||
with:
|
||||
run-tests-guide-url: http://go/angular-g3sync-start
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -25,12 +25,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 'Checkout code'
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: 'Run analysis'
|
||||
uses: ossf/scorecard-action@08b4669551908b1024bb425080c797723083c031 # v2.2.0
|
||||
uses: ossf/scorecard-action@483ef80eb98fb506c348f7d62e28055e49fe2398 # v2.3.0
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: 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@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9
|
||||
uses: github/codeql-action/upload-sarif@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
# Setting `persist-credentials: false` prevents the github-action account from being the
|
||||
# account that is attempted to be used for authentication, instead the remote is set to
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
# Setting `persist-credentials: false` prevents the github-action account from being the
|
||||
# account that is attempted to be used for authentication, instead the remote is set to
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
<a name="16.2.11"></a>
|
||||
# 16.2.11 (2023-10-25)
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [54ea3b65c3](https://github.com/angular/angular/commit/54ea3b65c35254b220054541f2fbc52384486156) | fix | emit provider configured event when a service is configured with `providedIn` ([#52365](https://github.com/angular/angular/pull/52365)) |
|
||||
| [78533324dc](https://github.com/angular/angular/commit/78533324dcda2e884fbe489aaa6b37fa9a6fadbc) | fix | get root and platform injector providers in special cases ([#52365](https://github.com/angular/angular/pull/52365)) |
|
||||
| [019a0f4c22](https://github.com/angular/angular/commit/019a0f4c225d6bb6f741b37bf272b62899fe1f69) | fix | load global utils before creating platform injector in the standalone case ([#52365](https://github.com/angular/angular/pull/52365)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [b79b4aca91](https://github.com/angular/angular/commit/b79b4aca914aefda1605fc8d069ac8d84283f1b3) | fix | `RouterTestingHarness` should throw if a component is expected but navigation fails ([#52357](https://github.com/angular/angular/pull/52357)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.2.10"></a>
|
||||
# 16.2.10 (2023-10-18)
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.2.9"></a>
|
||||
# 16.2.9 (2023-10-11)
|
||||
### forms
|
||||
|
||||
@@ -194,10 +194,10 @@ cldr_xml_data_repository(
|
||||
# sass rules
|
||||
http_archive(
|
||||
name = "io_bazel_rules_sass",
|
||||
sha256 = "923b2c470e981b6e96b17e5b9ec7a6141eab808d52ebffdbd94695f5a42a5184",
|
||||
strip_prefix = "rules_sass-9a327e5badc3fdd5141479410675c356133e1e41",
|
||||
sha256 = "7a90567717c3417a23ff4b21963a698a6e9aa669ac9e682121ea33f218a2816a",
|
||||
strip_prefix = "rules_sass-425ecafa8268bc013d684216363fe75bc802323e",
|
||||
urls = [
|
||||
"https://github.com/bazelbuild/rules_sass/archive/9a327e5badc3fdd5141479410675c356133e1e41.zip",
|
||||
"https://github.com/bazelbuild/rules_sass/archive/425ecafa8268bc013d684216363fe75bc802323e.zip",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -215,7 +215,6 @@
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "src/test.ts",
|
||||
"polyfills": ["zone.js", "zone.js/testing"],
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"webWorkerTsConfig": "tsconfig.worker.json",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"branchName": "refs/heads/16.2.x",
|
||||
"sha": "99ff60cdfe5ca0a8b9ad6bf77ac60a929a27de38"
|
||||
"sha": "36adedc25c729e418ce3984b9f94bc32a1ff8a38"
|
||||
}
|
||||
@@ -160,7 +160,7 @@
|
||||
{
|
||||
"name": "output-path",
|
||||
"type": "string",
|
||||
"description": "The full path for the new output directory, relative to the current workspace.\nBy default, writes output to a folder named dist/ in the current project."
|
||||
"description": "The full path for the new output directory, relative to the current workspace."
|
||||
},
|
||||
{
|
||||
"name": "poll",
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
{
|
||||
"name": "from",
|
||||
"type": "string",
|
||||
"description": "Version from which to migrate from. Only available with a single package being updated, and only with 'migrate-only'."
|
||||
"description": "Version from which to migrate from. Only available when a single package is updated, and only with 'migrate-only'."
|
||||
},
|
||||
{
|
||||
"name": "help",
|
||||
@@ -46,7 +46,7 @@
|
||||
{
|
||||
"name": "name",
|
||||
"type": "string",
|
||||
"description": "The name of the migration to run. Only available with a single package being updated, and only with 'migrate-only' option."
|
||||
"description": "The name of the migration to run. Only available when a single package is updated."
|
||||
},
|
||||
{
|
||||
"name": "next",
|
||||
@@ -71,7 +71,7 @@
|
||||
{
|
||||
"name": "to",
|
||||
"type": "string",
|
||||
"description": "Version up to which to apply migrations. Only available with a single package being updated, and only with 'migrate-only' option. Requires 'from' to be specified. Default to the installed version detected."
|
||||
"description": "Version up to which to apply migrations. Only available when a single package is updated, and only with 'migrate-only' option. Requires 'from' to be specified. Default to the installed version detected."
|
||||
},
|
||||
{
|
||||
"name": "verbose",
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
@shortDescription Root element was not found during bootstrap.
|
||||
|
||||
@description
|
||||
Boostraped components are defined in the `bootstrap` property of an `@NgModule` decorator or as the first parameter of `boopstrapApplication` for standalone components.
|
||||
Bootstrapped components are defined in the `bootstrap` property of an `@NgModule` decorator or as the first parameter of `bootstrapApplication` for standalone components.
|
||||
|
||||
This error happens when Angular tries to boostrap one of these components but cannot find its corresponing node in the DOM.
|
||||
This error happens when Angular tries to bootstrap one of these components but cannot find its corresponding node in the DOM.
|
||||
|
||||
@debugging
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ Avoiding the use of modules with non-local side effects (outside of polyfills) i
|
||||
|
||||
### Long build times when using Sass combined with pnpm or yarn PnP
|
||||
|
||||
Applications may have increased build times due to the need to workaround Sass resolution incompabilities when using either the pnpm or Yarn PnP package managers.
|
||||
Applications may have increased build times due to the need to workaround Sass resolution incompatibilities when using either the pnpm or Yarn PnP package managers.
|
||||
Sass files with `@import` or `@use` directives referencing a package when using either of these package managers can trigger the performance problem.
|
||||
|
||||
An alternative workaround that alleviates the build time increases is in development and will be available before the build system moves to stable status.
|
||||
|
||||
@@ -141,6 +141,31 @@ This lets the Angular Language Service provide diagnostics and completions in `.
|
||||
|
||||
Either directly install the "Eclipse IDE for Web and JavaScript developers" package which comes with the Angular Language Server included, or from other Eclipse IDE packages, use Help > Eclipse Marketplace to find and install [Eclipse Wild Web Developer](https://marketplace.eclipse.org/content/wild-web-developer-html-css-javascript-typescript-nodejs-angular-json-yaml-kubernetes-xml).
|
||||
|
||||
### Neovim
|
||||
|
||||
1. [Setup coc.nvim](https://github.com/neoclide/coc.nvim)
|
||||
|
||||
2. [Configure the Angular Language Service](https://github.com/iamcco/coc-angular/issues/70#issuecomment-1616340751)
|
||||
|
||||
```
|
||||
{
|
||||
"languageserver": {
|
||||
"angular": {
|
||||
"command": "ngserver",
|
||||
"args": [
|
||||
"--stdio",
|
||||
"--tsProbeLocations",
|
||||
"/usr/local/lib/node_modules/typescript/lib",
|
||||
"--ngProbeLocations",
|
||||
"/usr/local/lib/node_modules/@angular/language-server/bin"
|
||||
],
|
||||
"filetypes": ["ts", "typescript", "html"],
|
||||
"trace.server.verbosity": "verbose"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## How the Language Service works
|
||||
|
||||
When you use an editor with a language service, the editor starts a separate language-service process and communicates with it through an [RPC](https://en.wikipedia.org/wiki/Remote_procedure_call), using the [Language Server Protocol](https://microsoft.github.io/language-server-protocol).
|
||||
@@ -168,4 +193,4 @@ The Angular Language Services then looks at `data.---` within its context, asks
|
||||
|
||||
<!-- end links -->
|
||||
|
||||
@reviewed 2022-02-28
|
||||
@reviewed 2022-02-28
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 841 KiB |
@@ -779,6 +779,14 @@
|
||||
"bio": "I'm Software Senior Developer. With more than 8 years of professional software development experience focusing in Web Development, Tech Management and skills for problem-solving. I'm passionate about sharing my knowledge with the community about Web Development and I do this through code contributions, videos, conferences, articles and, creating online content therefore I got recognized by Google like an GDE (Google Developer Expert) in Angular and by Microsoft like an MVP (Most Value Professional).",
|
||||
"groups": ["GDE"]
|
||||
},
|
||||
"nicoss54": {
|
||||
"name": "Nicolas Frizzarin",
|
||||
"picture": "nicolasfrizzarin.jpeg",
|
||||
"twitter": "Nicooss54",
|
||||
"website": "https://dev.to/nicoss54",
|
||||
"bio": "Google Developer Expert in Web Technologies and Angular and OpenJs Foundation Member, Nicolas is a FontEnd specialist and user Interface Designer from Metz, France. He works as a Developer Advocate and Senior Staff Engineer at Sfeir Luxembourg. His daily mission is to help teams to make robust, powerful and beautiful web applications. Besides that, Nicolas is a speaker, and likes to contribute to the community by giving talks, trainings, writing articles or participating in open source projects.",
|
||||
"groups": ["GDE"]
|
||||
},
|
||||
"nirkaufman": {
|
||||
"name": "Nir Kaufman",
|
||||
"picture": "nirkaufman.jpg",
|
||||
@@ -987,6 +995,14 @@
|
||||
"bio": "Owner and trainer at Ultimate Angular. Lives in England, UK. Has a love for teaching, OSS and speaking at conferences. Google Developer Expert for Web Technologies and Angular.",
|
||||
"groups": ["GDE"]
|
||||
},
|
||||
"thomaslaforge": {
|
||||
"name": "Thomas Laforge",
|
||||
"picture": "thomaslaforge.png",
|
||||
"twitter": "laforge_toma",
|
||||
"website": "https://thomaslaforge.dev/home",
|
||||
"bio": "Thomas is a contractor with a strong passion for frontend development, specifically focusing on Angular. He is the creator and maintainer of Angular Challenges, a platform that gathers multiple challenges to help you improve your skills in Angular.",
|
||||
"groups": ["GDE"]
|
||||
},
|
||||
"tomastrajan": {
|
||||
"name": "Tomas Trajan",
|
||||
"picture": "tomastrajan.jpg",
|
||||
|
||||
@@ -1217,6 +1217,18 @@
|
||||
},
|
||||
"name": "GraphQL SF"
|
||||
},
|
||||
{
|
||||
"date": {
|
||||
"start": "2023-09-26"
|
||||
},
|
||||
"name": "IJS New York"
|
||||
},
|
||||
{
|
||||
"date": {
|
||||
"start": "2023-10-03"
|
||||
},
|
||||
"name": "Angular London Meetup"
|
||||
},
|
||||
{
|
||||
"date": {
|
||||
"start": "2023-10-05"
|
||||
@@ -1229,6 +1241,18 @@
|
||||
},
|
||||
"name": "All Things Open"
|
||||
},
|
||||
{
|
||||
"date": {
|
||||
"start": "2023-10-26"
|
||||
},
|
||||
"name": "Connect.tech"
|
||||
},
|
||||
{
|
||||
"date": {
|
||||
"start": "2023-10-27"
|
||||
},
|
||||
"name": "REFACTR.tech"
|
||||
},
|
||||
{
|
||||
"date": {
|
||||
"start": "2023-11-08"
|
||||
|
||||
@@ -665,9 +665,9 @@
|
||||
"logo": ""
|
||||
},
|
||||
"butter-cms": {
|
||||
"title":"How to integrate ButterCMS into Angular 2+ App",
|
||||
"title": "How to integrate ButterCMS into Angular 2+ App",
|
||||
"desc": "Integrate a Headless CMS into your Angular App, create blog posts and pages",
|
||||
"url":"https://medium.com/orlyknop/how-to-integrate-buttercms-into-angular-2-app-a1baaa51402",
|
||||
"url": "https://medium.com/orlyknop/how-to-integrate-buttercms-into-angular-2-app-a1baaa51402",
|
||||
"logo": ""
|
||||
},
|
||||
"angular-projects": {
|
||||
@@ -822,6 +822,11 @@
|
||||
"desc": "Want to learn #Angular, but not sure where to start? Check out this in-depth “Angular for Beginners Course“ created by Angular #GDE @SantoshYadavDev.",
|
||||
"title": "Angular for Beginners Course",
|
||||
"url": "https://youtu.be/3qBXWUpoPHo"
|
||||
},
|
||||
"angular-challenges": {
|
||||
"desc": "Learn angular its ecosystem and open-source by practising on real-life examples.",
|
||||
"title": "Angular Challenges",
|
||||
"url": "https://angular-challenges.vercel.app/"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -102,4 +102,8 @@ Here's the application in action:
|
||||
|
||||
</div>
|
||||
|
||||
## Next steps
|
||||
|
||||
* [Create a new project](tutorial/tour-of-heroes/toh-pt0)
|
||||
|
||||
@reviewed 2022-05-16
|
||||
|
||||
+2
-2
@@ -110,7 +110,7 @@
|
||||
"dgeni": "^0.4.14",
|
||||
"dgeni-packages": "^0.30.0",
|
||||
"entities": "^4.0.0",
|
||||
"eslint": "8.50.0",
|
||||
"eslint": "8.51.0",
|
||||
"eslint-plugin-import": "2.28.1",
|
||||
"eslint-plugin-jasmine": "4.1.3",
|
||||
"eslint-plugin-jsdoc": "46.8.2",
|
||||
@@ -144,7 +144,7 @@
|
||||
"lunr": "^2.3.9",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"protractor": "~7.0.0",
|
||||
"puppeteer-core": "21.3.6",
|
||||
"puppeteer-core": "21.3.8",
|
||||
"rehype-slug": "^4.0.1",
|
||||
"remark": "^12.0.0",
|
||||
"remark-html": "^13.0.0",
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
<header>
|
||||
<mat-toolbar #appToolbar color="primary" class="app-toolbar no-print" [class.transitioning]="isTransitioning">
|
||||
<mat-toolbar-row class="notification-container">
|
||||
<aio-notification notificationId="survey-august-2023" expirationDate="2023-10-08" [dismissOnContentClick]="true" (dismissed)="notificationDismissed()">
|
||||
<a href="https://goo.gle/angular-devsat-q3-2023">
|
||||
<aio-notification notificationId="angular-event" expirationDate="2023-11-08" [dismissOnContentClick]="true" (dismissed)="notificationDismissed()">
|
||||
<a href="https://goo.gle/angular-event">
|
||||
<mat-icon class="icon" svgIcon="insert_comment" aria-label="Announcement"></mat-icon>
|
||||
<span class="message">Help Angular by taking a <strong>quick survey</strong>!</span>
|
||||
<span class="action-button">Go to survey</span>
|
||||
<span class="message">We have a lot to share, tune in on November 6th!</span>
|
||||
<span class="action-button">Join us live</span>
|
||||
</a>
|
||||
</aio-notification>
|
||||
</mat-toolbar-row>
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import {
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting(),
|
||||
);
|
||||
@@ -57,8 +57,8 @@
|
||||
"@types/angular-resource": "^1.5.17",
|
||||
"@types/angular-route": "^1.7.2",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/jasmine": "~4.3.0",
|
||||
"@types/jquery": "3.5.20",
|
||||
"@types/jasmine": "~5.1.0",
|
||||
"@types/jquery": "3.5.23",
|
||||
"@types/node": "^16.11.35",
|
||||
"canonical-path": "1.0.0",
|
||||
"concurrently": "^8.0.0",
|
||||
|
||||
@@ -1844,15 +1844,15 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/jasmine@~4.3.0":
|
||||
version "4.3.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-4.3.5.tgz#05c6b401c041b8a4f3303c3a58c9580aac2b898c"
|
||||
integrity sha512-9YHUdvuNDDRJYXZwHqSsO72Ok0vmqoJbNn73ttyITQp/VA60SarnZ+MPLD37rJAhVoKp+9BWOvJP5tHIRfZylQ==
|
||||
"@types/jasmine@~5.1.0":
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-5.1.1.tgz#7d2a2a983e1e822858ea9e30d90e11a3fe408fc0"
|
||||
integrity sha512-qL4GoZHHJl1JQ0vK31OtXMfkfGxYJnysmYz9kk0E8j5W96ThKykBF90uD3PcVmQUAzulbsaus2eFiBhCH5itfw==
|
||||
|
||||
"@types/jquery@3.5.20":
|
||||
version "3.5.20"
|
||||
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.20.tgz#a23eece847591c7aaa47c52d6910052af473df4e"
|
||||
integrity sha512-UI+EGhgYD4LdSZ8gaiziFqXYIIB38VQSDsnAs8jL/div7FGrzrShx4HKCykVzk3tPfiIlusdNP9Wi3G60LCF2Q==
|
||||
"@types/jquery@3.5.23":
|
||||
version "3.5.23"
|
||||
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.23.tgz#f99f08533ad5a5c4cb1d0dc131ecf5e2a73eb182"
|
||||
integrity sha512-LwtD05mlY8iPF/1aB8dOZaYhRDothbHA7csnAxhyqMnQxj90Fo3J4nPhmHiA0OMTwHhjwZdE1Lpd6UK+b+C6Bw==
|
||||
dependencies:
|
||||
"@types/sizzle" "*"
|
||||
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"src/test.ts",
|
||||
],
|
||||
"include": [
|
||||
"src/testing/**/*.ts",
|
||||
"src/**/*.spec.ts",
|
||||
|
||||
+18
-18
@@ -2038,10 +2038,10 @@
|
||||
minimatch "^3.1.2"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@eslint/js@8.50.0":
|
||||
version "8.50.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.50.0.tgz#9e93b850f0f3fa35f5fa59adfd03adae8488e484"
|
||||
integrity sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==
|
||||
"@eslint/js@8.51.0":
|
||||
version "8.51.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.51.0.tgz#6d419c240cfb2b66da37df230f7e7eef801c32fa"
|
||||
integrity sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==
|
||||
|
||||
"@google-cloud/paginator@^4.0.0":
|
||||
version "4.0.1"
|
||||
@@ -5287,10 +5287,10 @@ chrome-trace-event@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
|
||||
integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
|
||||
|
||||
chromium-bidi@0.4.28:
|
||||
version "0.4.28"
|
||||
resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.4.28.tgz#05befef4f3f19003198237245780d1c60e6f4dbc"
|
||||
integrity sha512-2HZ74QlAApJrEwcGlU/sUu0s4VS+FI3CJ09Toc9aE9VemMyhHZXeaROQgJKNRaYMUTUx6qIv1cLBs3F+vfgjSw==
|
||||
chromium-bidi@0.4.31:
|
||||
version "0.4.31"
|
||||
resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.4.31.tgz#a28c4329880706e61ff07ed49aed22e6d04e17d1"
|
||||
integrity sha512-OtvEg2JMRQrHsmLx4FV3u1Hf9waYxB5PmL+yM0HkFpc9H2x3TMbUqS+GP2/fC4399hzOO+EQF8uVU43By9ILag==
|
||||
dependencies:
|
||||
mitt "3.0.1"
|
||||
urlpattern-polyfill "9.0.0"
|
||||
@@ -6946,15 +6946,15 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
|
||||
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
||||
|
||||
eslint@8.50.0:
|
||||
version "8.50.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.50.0.tgz#2ae6015fee0240fcd3f83e1e25df0287f487d6b2"
|
||||
integrity sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==
|
||||
eslint@8.51.0:
|
||||
version "8.51.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.51.0.tgz#4a82dae60d209ac89a5cff1604fea978ba4950f3"
|
||||
integrity sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.2.0"
|
||||
"@eslint-community/regexpp" "^4.6.1"
|
||||
"@eslint/eslintrc" "^2.1.2"
|
||||
"@eslint/js" "8.50.0"
|
||||
"@eslint/js" "8.51.0"
|
||||
"@humanwhocodes/config-array" "^0.11.11"
|
||||
"@humanwhocodes/module-importer" "^1.0.1"
|
||||
"@nodelib/fs.walk" "^1.2.8"
|
||||
@@ -11898,13 +11898,13 @@ pupa@^2.1.1:
|
||||
dependencies:
|
||||
escape-goat "^2.0.0"
|
||||
|
||||
puppeteer-core@21.3.6:
|
||||
version "21.3.6"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-21.3.6.tgz#5507fafb790692ff887e368de71a1c5a0d08af1e"
|
||||
integrity sha512-ZH6tjTdRXwW2fx5W3jBbG+yUVQdDfZW1kjfwvWwMzsnKEli5ZwV70Zp97GOebHQHrK8zM3vX5VqI9sd48c9PnQ==
|
||||
puppeteer-core@21.3.8:
|
||||
version "21.3.8"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-21.3.8.tgz#7ac4879c9f73e8426431d8ca4c58680e517a4b08"
|
||||
integrity sha512-yv12E/+zZ7Lei5tJB4sUkSrsuqKibuYpYxLGbmtLUjjYIqGE5HKz9OUI2I/RFHEvF+pHi2bTbv5bWydeCGJ6Mw==
|
||||
dependencies:
|
||||
"@puppeteer/browsers" "1.7.1"
|
||||
chromium-bidi "0.4.28"
|
||||
chromium-bidi "0.4.31"
|
||||
cross-fetch "4.0.0"
|
||||
debug "4.3.4"
|
||||
devtools-protocol "0.0.1179426"
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ want Bazel to create several symlinks in your project directory
|
||||
`.bazelrc` file.
|
||||
|
||||
[GitHub]: https://github.com/bazelbuild/rules_typescript
|
||||
[bazelrc doc]: https://bazel.build/versions/master/docs/bazel-user-manual.html#bazelrc
|
||||
[bazelrc doc]: https://bazel.build/run/bazelrc
|
||||
|
||||
## Building Angular
|
||||
|
||||
|
||||
+16
-16
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "angular-srcs",
|
||||
"version": "16.2.9",
|
||||
"version": "16.2.11",
|
||||
"private": true,
|
||||
"description": "Angular - a web framework for modern web apps",
|
||||
"homepage": "https://github.com/angular/angular",
|
||||
@@ -53,14 +53,14 @@
|
||||
"@angular/cdk": "16.2.0-next.4",
|
||||
"@angular/cli": "16.2.0-next.3",
|
||||
"@angular/material": "16.2.0-next.4",
|
||||
"@babel/cli": "7.22.5",
|
||||
"@babel/core": "7.22.5",
|
||||
"@babel/generator": "7.22.5",
|
||||
"@babel/parser": "7.22.5",
|
||||
"@babel/preset-env": "7.22.5",
|
||||
"@babel/template": "7.22.5",
|
||||
"@babel/traverse": "7.22.5",
|
||||
"@babel/types": "7.22.5",
|
||||
"@babel/cli": "7.23.0",
|
||||
"@babel/core": "7.23.2",
|
||||
"@babel/generator": "7.23.0",
|
||||
"@babel/parser": "7.23.0",
|
||||
"@babel/preset-env": "7.23.2",
|
||||
"@babel/template": "7.22.15",
|
||||
"@babel/traverse": "7.23.2",
|
||||
"@babel/types": "7.23.0",
|
||||
"@bazel/concatjs": "5.8.1",
|
||||
"@bazel/esbuild": "5.8.1",
|
||||
"@bazel/jasmine": "5.8.1",
|
||||
@@ -81,17 +81,17 @@
|
||||
"@types/babel__template": "7.4.1",
|
||||
"@types/babel__traverse": "7.20.1",
|
||||
"@types/bluebird": "^3.5.27",
|
||||
"@types/chrome": "^0.0.246",
|
||||
"@types/chrome": "^0.0.248",
|
||||
"@types/convert-source-map": "^2.0.0",
|
||||
"@types/diff": "^5.0.0",
|
||||
"@types/dom-view-transitions": "^1.0.1",
|
||||
"@types/hammerjs": "2.0.42",
|
||||
"@types/jasmine": "^4.0.0",
|
||||
"@types/hammerjs": "2.0.43",
|
||||
"@types/jasmine": "^5.0.0",
|
||||
"@types/jasmine-ajax": "^3.3.1",
|
||||
"@types/jasminewd2": "^2.0.8",
|
||||
"@types/node": "^16.11.7",
|
||||
"@types/selenium-webdriver": "3.0.7",
|
||||
"@types/selenium-webdriver4": "npm:@types/selenium-webdriver@4.1.17",
|
||||
"@types/selenium-webdriver4": "npm:@types/selenium-webdriver@4.1.18",
|
||||
"@types/semver": "^7.3.4",
|
||||
"@types/shelljs": "^0.8.6",
|
||||
"@types/systemjs": "6.13.3",
|
||||
@@ -127,7 +127,7 @@
|
||||
"karma-jasmine": "^5.0.0",
|
||||
"karma-requirejs": "^1.1.0",
|
||||
"karma-sourcemap-loader": "^0.4.0",
|
||||
"magic-string": "0.30.4",
|
||||
"magic-string": "0.30.5",
|
||||
"memo-decorator": "^2.0.1",
|
||||
"ngx-flamegraph": "0.0.12",
|
||||
"nodejs-websocket": "^1.7.2",
|
||||
@@ -139,7 +139,7 @@
|
||||
"rollup-plugin-sourcemaps": "^0.6.3",
|
||||
"rxjs": "^6.6.7",
|
||||
"selenium-webdriver": "3.5.0",
|
||||
"selenium-webdriver4": "npm:selenium-webdriver@4.13.0",
|
||||
"selenium-webdriver4": "npm:selenium-webdriver@4.14.0",
|
||||
"semver-dsl": "^1.0.1",
|
||||
"shelljs": "^0.8.5",
|
||||
"source-map": "0.7.4",
|
||||
@@ -206,6 +206,6 @@
|
||||
"resolutions": {
|
||||
"**/graceful-fs": "4.2.11",
|
||||
"**/https-proxy-agent": "7.0.2",
|
||||
"**/saucelabs": "7.2.2"
|
||||
"**/saucelabs": "7.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ export abstract class LocationStrategy {
|
||||
* with a base href value, so that the DI framework can supply the dependency anywhere in the app.
|
||||
*
|
||||
* ```typescript
|
||||
* import {Component, NgModule} from '@angular/core';
|
||||
* import {NgModule} from '@angular/core';
|
||||
* import {APP_BASE_HREF} from '@angular/common';
|
||||
*
|
||||
* @NgModule({
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "7.22.5",
|
||||
"@babel/core": "7.23.2",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14",
|
||||
"reflect-metadata": "^0.1.2",
|
||||
"chokidar": "^3.0.0",
|
||||
|
||||
@@ -65,7 +65,7 @@ in two ways:
|
||||
|
||||
For example, a directive's selector may be determined via an imported constant:
|
||||
|
||||
```typescript=
|
||||
```typescript
|
||||
import {Directive} from '@angular/core';
|
||||
import {DIR_SELECTOR} from './selectors';
|
||||
|
||||
@@ -138,7 +138,7 @@ never a reference from a component to its NgModule, or any of its directive or p
|
||||
|
||||
In code, this looks like:
|
||||
|
||||
```typescript=
|
||||
```typescript
|
||||
// dir.ts
|
||||
@Directive({selector: '[dir]'})
|
||||
export class Dir {}
|
||||
@@ -161,7 +161,7 @@ export class Mod {}
|
||||
Here, `Cmp` never directly imports or refers to `Dir`, but it _does_ consume the directive in its
|
||||
template. During emit, `Cmp` would receive a `directiveDefs` array:
|
||||
|
||||
```typescript=
|
||||
```typescript
|
||||
// cmp.js
|
||||
import * as i1 from './dir';
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ import {isPromise, isSubscribable} from './util/lang';
|
||||
* ```
|
||||
*
|
||||
* ### Example with standalone application
|
||||
*
|
||||
* ```
|
||||
* function initializeAppFactory(httpClient: HttpClient): () => Observable<any> {
|
||||
* return () => httpClient.get("https://someUrl.com/api/user")
|
||||
* .pipe(
|
||||
@@ -127,6 +127,7 @@ import {isPromise, isSubscribable} from './util/lang';
|
||||
* },
|
||||
* ],
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
|
||||
@@ -188,10 +188,10 @@ function createOrReusePlatformInjector(providers: StaticProvider[] = []): Inject
|
||||
// is already bootstrapped and no additional actions are required.
|
||||
if (_platformInjector) return _platformInjector;
|
||||
|
||||
publishDefaultGlobalUtils();
|
||||
// Otherwise, setup a new platform injector and run platform initializers.
|
||||
const injector = createPlatformInjector(providers);
|
||||
_platformInjector = injector;
|
||||
publishDefaultGlobalUtils();
|
||||
publishSignalConfiguration();
|
||||
runPlatformInitializers(injector);
|
||||
return injector;
|
||||
@@ -1283,7 +1283,7 @@ export function internalProvideZoneChangeDetection(ngZoneFactory: () => NgZone):
|
||||
* `BootstrapOptions` instead.
|
||||
*
|
||||
* @usageNotes
|
||||
* ```typescript=
|
||||
* ```typescript
|
||||
* bootstrapApplication(MyApp, {providers: [
|
||||
* provideZoneChangeDetection({eventCoalescing: true}),
|
||||
* ]});
|
||||
|
||||
@@ -28,7 +28,7 @@ import {catchInjectorError, convertToBitFlags, injectArgs, NG_TEMP_TOKEN_PATH, s
|
||||
import {INJECTOR} from './injector_token';
|
||||
import {getInheritedInjectableDef, getInjectableDef, InjectorType, ɵɵInjectableDeclaration} from './interface/defs';
|
||||
import {InjectFlags, InjectOptions} from './interface/injector';
|
||||
import {ClassProvider, ConstructorProvider, EnvironmentProviders, InternalEnvironmentProviders, isEnvironmentProviders, Provider, StaticClassProvider} from './interface/provider';
|
||||
import {ClassProvider, ConstructorProvider, EnvironmentProviders, InternalEnvironmentProviders, isEnvironmentProviders, Provider, StaticClassProvider, TypeProvider} from './interface/provider';
|
||||
import {INJECTOR_DEF_TYPES} from './internal_tokens';
|
||||
import {NullInjector} from './null_injector';
|
||||
import {isExistingProvider, isFactoryProvider, isTypeProvider, isValueProvider, SingleProvider} from './provider_collection';
|
||||
@@ -271,6 +271,13 @@ export class R3Injector extends EnvironmentInjector {
|
||||
if (def && this.injectableDefInScope(def)) {
|
||||
// Found an injectable def and it's scoped to this injector. Pretend as if it was here
|
||||
// all along.
|
||||
|
||||
if (ngDevMode) {
|
||||
runInInjectorProfilerContext(this, token as Type<T>, () => {
|
||||
emitProviderConfiguredEvent(token as TypeProvider);
|
||||
});
|
||||
}
|
||||
|
||||
record = makeRecord(injectableDefOrInjectorDefFactory(token), NOT_YET);
|
||||
} else {
|
||||
record = null;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import type {FactoryProvider} from '../../di';
|
||||
import {resolveForwardRef} from '../../di/forward_ref';
|
||||
import {InjectionToken} from '../../di/injection_token';
|
||||
import type {Injector} from '../../di/injector';
|
||||
@@ -86,7 +87,7 @@ export interface ProviderRecord {
|
||||
/**
|
||||
* DI token that this provider is configuring
|
||||
*/
|
||||
token: Type<unknown>;
|
||||
token: Type<unknown>|InjectionToken<unknown>;
|
||||
|
||||
/**
|
||||
* Determines if provider is configured as view provider.
|
||||
@@ -192,20 +193,39 @@ function injectorProfiler(event: InjectorProfilerEvent): void {
|
||||
* Emits an InjectorProfilerEventType.ProviderConfigured to the injector profiler. The data in the
|
||||
* emitted event includes the raw provider, as well as the token that provider is providing.
|
||||
*
|
||||
* @param provider A provider object
|
||||
* @param eventProvider A provider object
|
||||
*/
|
||||
export function emitProviderConfiguredEvent(
|
||||
provider: SingleProvider, isViewProvider: boolean = false): void {
|
||||
eventProvider: SingleProvider, isViewProvider: boolean = false): void {
|
||||
!ngDevMode && throwError('Injector profiler should never be called in production mode');
|
||||
|
||||
let token;
|
||||
// if the provider is a TypeProvider (typeof provider is function) then the token is the
|
||||
// provider itself
|
||||
if (typeof eventProvider === 'function') {
|
||||
token = eventProvider;
|
||||
}
|
||||
// if the provider is an injection token, then the token is the injection token.
|
||||
else if (eventProvider instanceof InjectionToken) {
|
||||
token = eventProvider;
|
||||
}
|
||||
// in all other cases we can access the token via the `provide` property of the provider
|
||||
else {
|
||||
token = resolveForwardRef(eventProvider.provide);
|
||||
}
|
||||
|
||||
let provider = eventProvider;
|
||||
// Injection tokens may define their own default provider which gets attached to the token itself
|
||||
// as `ɵprov`. In this case, we want to emit the provider that is attached to the token, not the
|
||||
// token itself.
|
||||
if (eventProvider instanceof InjectionToken) {
|
||||
provider = eventProvider.ɵprov as FactoryProvider || eventProvider;
|
||||
}
|
||||
|
||||
injectorProfiler({
|
||||
type: InjectorProfilerEventType.ProviderConfigured,
|
||||
context: getInjectorProfilerContext(),
|
||||
providerRecord: {
|
||||
token: typeof provider === 'function' ? provider : resolveForwardRef(provider.provide),
|
||||
provider,
|
||||
isViewProvider
|
||||
}
|
||||
providerRecord: {token, provider, isViewProvider}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -17,12 +17,6 @@ export interface ReactiveLViewConsumer extends ReactiveNode {
|
||||
lView: LView|null;
|
||||
}
|
||||
|
||||
export function setLViewForConsumer(node: ReactiveLViewConsumer, lView: LView): void {
|
||||
(typeof ngDevMode === 'undefined' || ngDevMode) &&
|
||||
assertEqual(node.lView, null, 'Consumer already associated with a view.');
|
||||
node.lView = lView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new template consumer pointing at the specified LView.
|
||||
* Sometimes, a previously created consumer may be reused, in order to save on allocations. In that
|
||||
|
||||
@@ -151,6 +151,12 @@ function getProviderImportsContainer(injector: Injector): Type<unknown>|null {
|
||||
return null;
|
||||
}
|
||||
|
||||
// In standalone applications, the root environment injector created by bootstrapApplication
|
||||
// may have no associated "instance".
|
||||
if (defTypeRef.instance === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return defTypeRef.instance.constructor;
|
||||
}
|
||||
|
||||
@@ -351,13 +357,29 @@ function walkProviderTreeToDiscoverImportPaths(
|
||||
* @returns an array of objects representing the providers of the given injector
|
||||
*/
|
||||
function getEnvironmentInjectorProviders(injector: EnvironmentInjector): ProviderRecord[] {
|
||||
const providerRecords = getFrameworkDIDebugData().resolverToProviders.get(injector) ?? [];
|
||||
|
||||
// platform injector has no provider imports container so can we skip trying to
|
||||
// find import paths
|
||||
if (isPlatformInjector(injector)) {
|
||||
return providerRecords;
|
||||
}
|
||||
|
||||
const providerImportsContainer = getProviderImportsContainer(injector);
|
||||
if (providerImportsContainer === null) {
|
||||
// There is a special case where the bootstrapped component does not
|
||||
// import any NgModules. In this case the environment injector connected to
|
||||
// that component is the root injector, which does not have a provider imports
|
||||
// container (and thus no concept of module import paths). Therefore we simply
|
||||
// return the provider records as is.
|
||||
if (isRootInjector(injector)) {
|
||||
return providerRecords;
|
||||
}
|
||||
|
||||
throwError('Could not determine where injector providers were configured.');
|
||||
}
|
||||
|
||||
const providerToPath = getProviderImportPaths(providerImportsContainer);
|
||||
const providerRecords = getFrameworkDIDebugData().resolverToProviders.get(injector) ?? [];
|
||||
|
||||
return providerRecords.map(providerRecord => {
|
||||
let importPath = providerToPath.get(providerRecord.provider) ?? [providerImportsContainer];
|
||||
@@ -374,6 +396,14 @@ function getEnvironmentInjectorProviders(injector: EnvironmentInjector): Provide
|
||||
});
|
||||
}
|
||||
|
||||
function isPlatformInjector(injector: Injector) {
|
||||
return injector instanceof R3Injector && injector.scopes.has('platform');
|
||||
}
|
||||
|
||||
function isRootInjector(injector: Injector) {
|
||||
return injector instanceof R3Injector && injector.scopes.has('root');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the providers configured on an injector.
|
||||
*
|
||||
|
||||
@@ -71,44 +71,30 @@ describe('change detection', () => {
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<button (click)="noop()">Trigger change detection</button>
|
||||
<div>{{increment('componentView')}}</div>
|
||||
<ng-template #vm="vm" viewManipulation>{{increment('embeddedView')}}</ng-template>
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
class App {
|
||||
increment(counter: 'componentView'|'embeddedView') {
|
||||
counters[counter]++;
|
||||
}
|
||||
noop() {}
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [App, ViewManipulation]});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
const vm: ViewManipulation = fixture.debugElement.childNodes[2].references['vm'];
|
||||
const button = fixture.nativeElement.querySelector('button');
|
||||
const vm: ViewManipulation = fixture.debugElement.childNodes[1].references['vm'];
|
||||
const viewRef = vm.insertIntoVcRef();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(counters).toEqual({componentView: 1, embeddedView: 1});
|
||||
|
||||
button.click();
|
||||
fixture.detectChanges();
|
||||
expect(counters).toEqual({componentView: 2, embeddedView: 2});
|
||||
|
||||
viewRef.detach();
|
||||
button.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(counters).toEqual({componentView: 3, embeddedView: 2});
|
||||
expect(counters).toEqual({componentView: 2, embeddedView: 0});
|
||||
|
||||
// Re-attach the view to ensure that the process can be reversed.
|
||||
viewRef.reattach();
|
||||
button.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(counters).toEqual({componentView: 4, embeddedView: 3});
|
||||
expect(counters).toEqual({componentView: 4, embeddedView: 2});
|
||||
});
|
||||
|
||||
it('should not detect changes in child component views while they are detached', () => {
|
||||
|
||||
@@ -209,6 +209,83 @@ describe('setProfiler', () => {
|
||||
expect(((myServiceProviderConfiguredEvent!.providerRecord)?.provider as ClassProvider).multi)
|
||||
.toBeTrue();
|
||||
});
|
||||
|
||||
it('should emit correct DI events when service providers are configured with providedIn', () => {
|
||||
@Injectable({providedIn: 'root'})
|
||||
class RootService {
|
||||
}
|
||||
|
||||
@Injectable({providedIn: 'platform'})
|
||||
class PlatformService {
|
||||
}
|
||||
|
||||
const providedInRootInjectionToken = new InjectionToken(
|
||||
'providedInRootInjectionToken', {providedIn: 'root', factory: () => 'hello world'});
|
||||
|
||||
const providedInPlatformToken = new InjectionToken(
|
||||
'providedInPlatformToken', {providedIn: 'platform', factory: () => 'hello world'});
|
||||
|
||||
@Component({
|
||||
selector: 'my-comp',
|
||||
template: 'hello world',
|
||||
})
|
||||
class MyComponent {
|
||||
rootService = inject(RootService);
|
||||
platformService = inject(PlatformService);
|
||||
fromRoot = inject(providedInRootInjectionToken);
|
||||
fromPlatform = inject(providedInPlatformToken);
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [MyComponent]});
|
||||
TestBed.createComponent(MyComponent);
|
||||
|
||||
// MyService should have been configured
|
||||
const rootServiceProviderConfiguredEvent = searchForProfilerEvent<ProviderConfiguredEvent>(
|
||||
providerConfiguredEvents, (event) => event.providerRecord.token === RootService);
|
||||
|
||||
expect(rootServiceProviderConfiguredEvent).toBeTruthy();
|
||||
expect(rootServiceProviderConfiguredEvent!.context).toBeTruthy();
|
||||
expect(rootServiceProviderConfiguredEvent!.context!.injector).toBeInstanceOf(R3Injector);
|
||||
expect((rootServiceProviderConfiguredEvent!.context!.injector as R3Injector).scopes.has('root'))
|
||||
.toBeTrue();
|
||||
|
||||
const platformServiceProviderConfiguredEvent = searchForProfilerEvent<ProviderConfiguredEvent>(
|
||||
providerConfiguredEvents, (event) => event.providerRecord.token === PlatformService);
|
||||
expect(platformServiceProviderConfiguredEvent).toBeTruthy();
|
||||
expect(platformServiceProviderConfiguredEvent!.context).toBeTruthy();
|
||||
expect(platformServiceProviderConfiguredEvent!.context!.injector).toBeInstanceOf(R3Injector);
|
||||
expect((platformServiceProviderConfiguredEvent!.context!.injector as R3Injector)
|
||||
.scopes.has('platform'))
|
||||
.toBeTrue();
|
||||
|
||||
const providedInRootInjectionTokenProviderConfiguredEvent =
|
||||
searchForProfilerEvent<ProviderConfiguredEvent>(
|
||||
providerConfiguredEvents,
|
||||
(event) => event.providerRecord.token === providedInRootInjectionToken);
|
||||
expect(providedInRootInjectionTokenProviderConfiguredEvent).toBeTruthy();
|
||||
expect(providedInRootInjectionTokenProviderConfiguredEvent!.context).toBeTruthy();
|
||||
expect(providedInRootInjectionTokenProviderConfiguredEvent!.context!.injector)
|
||||
.toBeInstanceOf(R3Injector);
|
||||
expect((providedInRootInjectionTokenProviderConfiguredEvent!.context!.injector as R3Injector)
|
||||
.scopes.has('root'))
|
||||
.toBeTrue();
|
||||
expect(providedInRootInjectionTokenProviderConfiguredEvent!.providerRecord.token)
|
||||
.toBe(providedInRootInjectionToken);
|
||||
|
||||
const providedInPlatformTokenProviderConfiguredEvent =
|
||||
searchForProfilerEvent<ProviderConfiguredEvent>(
|
||||
providerConfiguredEvents,
|
||||
(event) => event.providerRecord.token === providedInPlatformToken);
|
||||
expect(providedInPlatformTokenProviderConfiguredEvent).toBeTruthy();
|
||||
expect(providedInPlatformTokenProviderConfiguredEvent!.context).toBeTruthy();
|
||||
expect(providedInPlatformTokenProviderConfiguredEvent!.context!.injector)
|
||||
.toBeInstanceOf(R3Injector);
|
||||
expect((providedInPlatformTokenProviderConfiguredEvent!.context!.injector as R3Injector)
|
||||
.scopes.has('platform'))
|
||||
.toBeTrue();
|
||||
expect(providedInPlatformTokenProviderConfiguredEvent!.providerRecord.token)
|
||||
.toBe(providedInPlatformToken);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getInjectorProviders', () => {
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"./fesm2022/init.mjs"
|
||||
],
|
||||
"dependencies": {
|
||||
"@babel/core": "7.22.5",
|
||||
"@babel/core": "7.23.2",
|
||||
"fast-glob": "3.3.0",
|
||||
"yargs": "^17.2.1"
|
||||
},
|
||||
|
||||
@@ -85,8 +85,11 @@ export interface RouterConfigOptions {
|
||||
|
||||
/**
|
||||
* Defines how the router merges parameters, data, and resolved data from parent to child
|
||||
* routes. By default ('emptyOnly'), inherits parent parameters only for
|
||||
* path-less or component-less routes.
|
||||
* routes.
|
||||
*
|
||||
* By default ('emptyOnly'), a route inherits the parent route's parameters when the route itself
|
||||
* has an empty path (meaning its configured with path: '') or when the parent route doesn't have
|
||||
* any component set.
|
||||
*
|
||||
* Set to 'always' to enable unconditional inheritance of parent parameters.
|
||||
*
|
||||
|
||||
@@ -155,6 +155,10 @@ export class RouterTestingHarness {
|
||||
}
|
||||
return activatedComponent as T;
|
||||
} else {
|
||||
if (requiredRoutedComponentType !== undefined) {
|
||||
throw new Error(`Unexpected routed component type. Expected ${
|
||||
requiredRoutedComponentType.name} but the navigation did not activate any component.`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,20 @@ describe('navigateForTest', () => {
|
||||
await expectAsync(harness.navigateByUrl('/123', OtherCmp)).toBeRejected();
|
||||
});
|
||||
|
||||
it('throws an error if navigation fails but expected a component instance', async () => {
|
||||
@Component({standalone: true, template: ''})
|
||||
class TestCmp {
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
provideRouter([{path: '**', canActivate: [() => false], component: TestCmp}]),
|
||||
]
|
||||
});
|
||||
const harness = await RouterTestingHarness.create();
|
||||
await expectAsync(harness.navigateByUrl('/123', TestCmp)).toBeRejected();
|
||||
});
|
||||
|
||||
it('waits for redirects using router.navigate', async () => {
|
||||
@Component({standalone: true, template: 'test'})
|
||||
class TestCmp {
|
||||
|
||||
Reference in New Issue
Block a user