Compare commits
68 Commits
10.0.0-rc.
...
8.0.0-rc.3
Author | SHA1 | Date | |
---|---|---|---|
b8cbcbcf49 | |||
1ed45bd783 | |||
82fd1920b1 | |||
f6d7271ec7 | |||
c1f3faf1df | |||
97202278f9 | |||
132f01c5ca | |||
6a987f1b9c | |||
548b003ed3 | |||
48dc41de01 | |||
817c2b49bc | |||
fed07c735c | |||
390cac6874 | |||
8eb0b8bd40 | |||
d7283c6085 | |||
3fe3a84a4b | |||
28e4187bd6 | |||
7cbc69c890 | |||
1dc134bc6b | |||
6a61d37f95 | |||
8d2e92bcfe | |||
5038f5c909 | |||
6eeca70043 | |||
9f68c35fa9 | |||
21418ea109 | |||
02d8b4ed3c | |||
6748392edc | |||
d9fd301157 | |||
71c5d80ce7 | |||
9798229fde | |||
4b2fcfd5dc | |||
b4d291aa7a | |||
b0ecafdc2f | |||
6816bb62d7 | |||
4b05b8cea0 | |||
a0728aedf7 | |||
ea96f6112a | |||
b706800ea8 | |||
c6f95b1d70 | |||
d896126604 | |||
a20da5ddcc | |||
18878600ba | |||
d7e10f3f7e | |||
4d044ea5b2 | |||
e2d1e0cd98 | |||
4e056580bb | |||
e4c2e6a904 | |||
a50989832d | |||
525307b6a3 | |||
a3ab76b216 | |||
f2265d4b46 | |||
d3ac709b99 | |||
908d43a5bb | |||
71cdb0a08e | |||
c7fbbdfa99 | |||
10e4ab7712 | |||
5114c23c21 | |||
c3e585d7eb | |||
0776daec88 | |||
615e1a58b2 | |||
606758357e | |||
ba2a3595c6 | |||
a50bfe5054 | |||
c8983bc367 | |||
8d6d2c6704 | |||
6711f22e62 | |||
8dd9192fe3 | |||
870e0dab48 |
@ -269,7 +269,7 @@ jobs:
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
# Deploy angular.io to production (if necessary)
|
||||
- run: setPublicVar CI_STABLE_BRANCH "$(npm info @angular/core dist-tags.latest | sed -r 's/^\s*([0-9]+\.[0-9]+)\.[0-9]+.*$/\1.x/')"
|
||||
- run: setPublicVar_CI_STABLE_BRANCH
|
||||
- run: yarn --cwd aio deploy-production
|
||||
|
||||
test_aio_local:
|
||||
@ -292,11 +292,21 @@ jobs:
|
||||
|
||||
test_aio_local_ivy:
|
||||
<<: *job_defaults
|
||||
docker:
|
||||
# Needed because the AIO tests and the PWA score test depend on Chrome being available.
|
||||
- image: *browsers_docker_image
|
||||
steps:
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
# Build aio with Ivy (using local Angular packages)
|
||||
- run: yarn --cwd aio build-with-ivy --progress=false
|
||||
# Run PWA-score tests
|
||||
# (Run before unit and e2e tests, which destroy the `dist/` directory.)
|
||||
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
|
||||
# Run unit tests
|
||||
- run: yarn --cwd aio test --progress=false --watch=false
|
||||
# Run e2e tests
|
||||
- run: yarn --cwd aio e2e --configuration=ci
|
||||
|
||||
test_aio_tools:
|
||||
<<: *job_defaults
|
||||
@ -486,20 +496,43 @@ jobs:
|
||||
command: 'openssl aes-256-cbc -d -in .circleci/github_token -k "${KEY}" -out ~/.git_credentials'
|
||||
- run: ./scripts/ci/publish-build-artifacts.sh
|
||||
|
||||
aio_monitoring:
|
||||
aio_monitoring_stable:
|
||||
<<: *job_defaults
|
||||
docker:
|
||||
# This job needs Chrome to be globally installed because the tests run with Protractor
|
||||
# which does not load the browser through the Bazel webtesting rules.
|
||||
- image: *browsers_docker_image
|
||||
steps:
|
||||
- checkout
|
||||
- *post_checkout
|
||||
- *restore_cache
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
- run: setPublicVar_CI_STABLE_BRANCH
|
||||
- run:
|
||||
name: Check out `aio/` from the stable branch
|
||||
command: |
|
||||
git fetch origin $CI_STABLE_BRANCH
|
||||
git checkout --force origin/$CI_STABLE_BRANCH -- aio/
|
||||
- run:
|
||||
name: Run tests against https://angular.io/
|
||||
command: ./aio/scripts/test-production.sh https://angular.io/ $CI_AIO_MIN_PWA_SCORE
|
||||
- run:
|
||||
name: Notify caretaker about failure
|
||||
# `$SLACK_CARETAKER_WEBHOOK_URL` is a secret env var defined in CircleCI project settings.
|
||||
# The URL comes from https://angular-team.slack.com/apps/A0F7VRE7N-circleci.
|
||||
command: 'curl --request POST --header "Content-Type: application/json" --data "{\"text\":\":x: \`$CIRCLE_JOB\` job failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}" $SLACK_CARETAKER_WEBHOOK_URL'
|
||||
when: on_fail
|
||||
|
||||
aio_monitoring_next:
|
||||
<<: *job_defaults
|
||||
docker:
|
||||
# This job needs Chrome to be globally installed because the tests run with Protractor
|
||||
# which does not load the browser through the Bazel webtesting rules.
|
||||
- image: *browsers_docker_image
|
||||
steps:
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
- run:
|
||||
name: Run tests against the deployed apps
|
||||
command: ./aio/scripts/test-production.sh $CI_AIO_MIN_PWA_SCORE
|
||||
name: Run tests against https://next.angular.io/
|
||||
command: ./aio/scripts/test-production.sh https://next.angular.io/ $CI_AIO_MIN_PWA_SCORE
|
||||
- run:
|
||||
name: Notify caretaker about failure
|
||||
# `$SLACK_CARETAKER_WEBHOOK_URL` is a secret env var defined in CircleCI project settings.
|
||||
@ -689,19 +722,23 @@ workflows:
|
||||
cron: "0 * * * *"
|
||||
filters: *publish_branches_filter
|
||||
|
||||
# This job is currently disabled due to a version skew problem.
|
||||
# More info is available here: https://github.com/angular/angular/issues/30101
|
||||
# aio_monitoring:
|
||||
# jobs:
|
||||
# - aio_monitoring
|
||||
# triggers:
|
||||
# - schedule:
|
||||
# # Runs AIO monitoring job at 00:00AM every day.
|
||||
# cron: "0 0 * * *"
|
||||
# filters:
|
||||
# branches:
|
||||
# only:
|
||||
# - master
|
||||
aio_monitoring:
|
||||
jobs:
|
||||
- setup
|
||||
- aio_monitoring_stable:
|
||||
requires:
|
||||
- setup
|
||||
- aio_monitoring_next:
|
||||
requires:
|
||||
- setup
|
||||
triggers:
|
||||
- schedule:
|
||||
# Runs AIO monitoring jobs at 10:00AM every day.
|
||||
cron: "0 10 * * *"
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
# TODO:
|
||||
# - don't build the g3 branch
|
||||
|
@ -36,3 +36,38 @@ function setSecretVar() {
|
||||
# Restore original shell options.
|
||||
eval "$originalShellOptions";
|
||||
}
|
||||
|
||||
|
||||
# Create a function to set an environment variable, when called.
|
||||
#
|
||||
# Use this function for creating setter for public environment variables that require expensive or
|
||||
# time-consuming computaions and may not be needed. When needed, you can call this function to set
|
||||
# the environment variable (which will be available through `$BASH_ENV` from that point onwards).
|
||||
#
|
||||
# Arguments:
|
||||
# - `<name>`: The name of the environment variable. The generated setter function will be
|
||||
# `setPublicVar_<name>`.
|
||||
# - `<code>`: The code to run to compute the value for the variable. Since this code should be
|
||||
# executed lazily, it must be properly escaped. For example:
|
||||
# ```sh
|
||||
# # DO NOT do this:
|
||||
# createPublicVarSetter MY_VAR "$(whoami)"; # `whoami` will be evaluated eagerly
|
||||
#
|
||||
# # DO this isntead:
|
||||
# createPublicVarSetter MY_VAR "\$(whoami)"; # `whoami` will NOT be evaluated eagerly
|
||||
# ```
|
||||
#
|
||||
# Usage: `createPublicVarSetter <name> <code>`
|
||||
#
|
||||
# Example:
|
||||
# ```sh
|
||||
# createPublicVarSetter MY_VAR 'echo "FOO"';
|
||||
# echo $MY_VAR; # Not defined
|
||||
#
|
||||
# setPublicVar_MY_VAR;
|
||||
# source $BASH_ENV;
|
||||
# echo $MY_VAR; # FOO
|
||||
# ```
|
||||
function createPublicVarSetter() {
|
||||
echo "setPublicVar_$1() { setPublicVar $1 \"$2\"; }" >> $BASH_ENV;
|
||||
}
|
||||
|
@ -34,6 +34,13 @@ setPublicVar CI_REPO_NAME "$CIRCLE_PROJECT_REPONAME";
|
||||
setPublicVar CI_REPO_OWNER "$CIRCLE_PROJECT_USERNAME";
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Define "lazy" PUBLIC environment variables for CircleCI.
|
||||
# (I.e. functions to set an environment variable when called.)
|
||||
####################################################################################################
|
||||
createPublicVarSetter CI_STABLE_BRANCH "\$(npm info @angular/core dist-tags.latest | sed -r 's/^\\s*([0-9]+\\.[0-9]+)\\.[0-9]+.*$/\\1.x/')";
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Define SECRET environment variables for CircleCI.
|
||||
####################################################################################################
|
||||
|
@ -20,5 +20,7 @@ steps:
|
||||
# Add Bazel CI config
|
||||
- copy .codefresh\bazel.rc %ProgramData%\bazel.bazelrc
|
||||
# Run tests
|
||||
- yarn bazel test //tools/ts-api-guardian:all
|
||||
- yarn bazel test //tools/ts-api-guardian:all //packages/language-service/test
|
||||
- yarn test-ivy-aot //packages/animations/test //packages/common/test //packages/forms/test //packages/http/test //packages/platform-browser/test //packages/platform-browser-dynamic/test //packages/router/test
|
||||
- yarn bazel test //tools/public_api_guard/...
|
||||
- yarn bazel test //packages/compiler-cli/integrationtest:integrationtest //packages/compiler-cli/test/compliance:compliance
|
||||
|
3
.gitattributes
vendored
3
.gitattributes
vendored
@ -5,5 +5,8 @@
|
||||
*.js eol=lf
|
||||
*.ts eol=lf
|
||||
|
||||
# API guardian patch must always use LF for tests to work
|
||||
*.patch eol=lf
|
||||
|
||||
# Must keep Windows line ending to be parsed correctly
|
||||
scripts/windows/packages.txt eol=crlf
|
||||
|
36
CHANGELOG.md
36
CHANGELOG.md
@ -1,3 +1,39 @@
|
||||
<a name="8.0.0-rc.3"></a>
|
||||
# [8.0.0-rc.3](https://github.com/angular/angular/compare/8.0.0-rc.2...8.0.0-rc.3) (2019-05-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bazel:** Bump ibazel to 0.10.1 for windows fixes ([#30196](https://github.com/angular/angular/issues/30196)) ([9f68c35](https://github.com/angular/angular/commit/9f68c35))
|
||||
* **compiler-cli:** log ngcc skipping messages as debug instead of info ([#30232](https://github.com/angular/angular/issues/30232)) ([548b003](https://github.com/angular/angular/commit/548b003))
|
||||
* **core:** fix interpolate identifier in AOT ([#30243](https://github.com/angular/angular/issues/30243)) ([3fe3a84](https://github.com/angular/angular/commit/3fe3a84))
|
||||
* **router:** ensure `history.state` is set in `eager` update mode ([#30154](https://github.com/angular/angular/issues/30154)) ([9720227](https://github.com/angular/angular/commit/9720227))
|
||||
* **router:** fix a problem with router not responding to back button ([#30160](https://github.com/angular/angular/issues/30160)) ([132f01c](https://github.com/angular/angular/commit/132f01c))
|
||||
|
||||
|
||||
|
||||
<a name="8.0.0-rc.2"></a>
|
||||
# [8.0.0-rc.2](https://github.com/angular/angular/compare/8.0.0-rc.1...8.0.0-rc.2) (2019-04-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **language-service:** Remove tsserverlibrary from rollup globals ([#30123](https://github.com/angular/angular/issues/30123)) ([b706800](https://github.com/angular/angular/commit/b706800))
|
||||
* disable injectable-pipe migration ([#30180](https://github.com/angular/angular/issues/30180)) ([4b2fcfd](https://github.com/angular/angular/commit/4b2fcfd))
|
||||
|
||||
|
||||
|
||||
<a name="8.0.0-rc.1"></a>
|
||||
# [8.0.0-rc.1](https://github.com/angular/angular/compare/8.0.0-rc.0...8.0.0-rc.1) (2019-04-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bazel:** Exclude common/upgrade* in metadata.tsconfig.json ([#30133](https://github.com/angular/angular/issues/30133)) ([6711f22](https://github.com/angular/angular/commit/6711f22))
|
||||
* **bazel:** update peerDep ranges ([#30155](https://github.com/angular/angular/issues/30155)) ([6067583](https://github.com/angular/angular/commit/6067583))
|
||||
|
||||
|
||||
|
||||
<a name="8.0.0-rc.0"></a>
|
||||
# [8.0.0-rc.0](https://github.com/angular/angular/compare/8.0.0-beta.14...8.0.0-rc.0) (2019-04-25)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<h1 class="no-toc">CLI Command Reference</h1>
|
||||
# CLI Overview and Command Reference
|
||||
|
||||
The Angular CLI is a command-line interface tool that you use to initialize, develop, scaffold, and maintain Angular applications. You can use the tool directly in a command shell, or indirectly through an interactive UI such as [Angular Console](https://angularconsole.com).
|
||||
|
||||
|
@ -41,7 +41,6 @@
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": false,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
|
@ -149,8 +149,8 @@ Learn more: See the [Template Syntax guide](guide/template-syntax "Template Synt
|
||||
{@a components}
|
||||
## Components
|
||||
|
||||
*Components* are the building blocks of Angular apps.
|
||||
You've already been working with the product list component.
|
||||
*Components* define areas of responsibility in your UI that let you reuse these sets of UI functionality.
|
||||
You've already built one with the product list component.
|
||||
|
||||
A component is comprised of three things:
|
||||
* **A component class,** which handles data and functionality. In the previous section, the product data and the `share()` method were defined for you in the component class.
|
||||
|
@ -87,6 +87,8 @@ If that form will need additional customization by the user, it might work best
|
||||
However, if the forms will always be the same and not need much customization by developers, then you could create a dynamic component that takes the configuration and generates the form.
|
||||
In general, the more complex the customization, the more useful the schematic approach.
|
||||
|
||||
{@a integrating-with-the-cli}
|
||||
|
||||
## Integrating with the CLI
|
||||
|
||||
A library can include [schematics](guide/glossary#schematic) that allow it to integrate with the Angular CLI.
|
||||
|
@ -223,9 +223,7 @@ const routes: Routes = [{
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
||||
**v8 update**: When you update to version 8, the [`ng update`](cli/update) command performs the transformation automatically. Prior to version 7, the `import()` syntax works in JIT mode (with view engine).
|
||||
|
||||
**Ivy:** If you are using Ivy, you must update your lazy routes to the new dynamic import syntax. See the [Ivy guide](guide/ivy) for more information.
|
||||
**v8 update**: When you update to version 8, the [`ng update`](cli/update) command performs the transformation automatically. Prior to version 7, the `import()` syntax only works in JIT mode (with view engine).
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -8,9 +8,9 @@ This glossary lists the most prominent terms
|
||||
and a few less familiar ones with unusual or
|
||||
unexpected definitions.
|
||||
|
||||
[A](guide/glossary#A) [B](guide/glossary#B) [C](guide/glossary#C) [D](guide/glossary#D) [E](guide/glossary#E) [F](guide/glossary#F) [G](guide/glossary#G) [H](guide/glossary#H) [I](guide/glossary#I)
|
||||
[J](guide/glossary#J) [K](guide/glossary#K) [L](guide/glossary#L) [M](guide/glossary#M) [N](guide/glossary#N) [O](guide/glossary#O) [P](guide/glossary#P) [Q](guide/glossary#Q) [R](guide/glossary#R)
|
||||
[S](guide/glossary#S) [T](guide/glossary#T) [U](guide/glossary#U) [V](guide/glossary#V) [W](guide/glossary#W) [X](guide/glossary#X) [Y](guide/glossary#Y) [Z](guide/glossary#Z)
|
||||
[A](#A) [B](#B) [C](#C) [D](#D) [E](#E) [F](#F) [G](#G) [H](#H) [I](#I)
|
||||
[J](#J) [K](#K) [L](#L) [M](#M) [N](#N) [O](#O) [P](#P) [Q](#Q) [R](#R)
|
||||
[S](#S) [T](#T) [U](#U) [V](#V) [W](#W) [X](#X) [Y](#Y) [Z](#Z)
|
||||
|
||||
|
||||
{@a A}
|
||||
@ -22,7 +22,7 @@ unexpected definitions.
|
||||
The Angular ahead-of-time (AOT) compiler converts Angular HTML and TypeScript code
|
||||
into efficient JavaScript code during the build phase, before the browser downloads
|
||||
and runs that code.
|
||||
This is the best compilation mode for production environments, with decreased load time and increased performance compared to [just-in-time (JIT) compilation](guide/glossary#jit).
|
||||
This is the best compilation mode for production environments, with decreased load time and increased performance compared to [just-in-time (JIT) compilation](#jit).
|
||||
|
||||
By compiling your application using the `ngc` command-line tool, you can bootstrap directly to a module factory, so you don't need to include the Angular compiler in your JavaScript bundle.
|
||||
|
||||
@ -30,7 +30,7 @@ By compiling your application using the `ngc` command-line tool, you can bootstr
|
||||
|
||||
## Angular element
|
||||
|
||||
An Angular [component](guide/glossary#component) packaged as a [custom element](guide/glossary#custom-element).
|
||||
An Angular [component](#component) packaged as a [custom element](#custom-element).
|
||||
|
||||
Learn more in [Angular Elements Overview](guide/elements).
|
||||
|
||||
@ -38,7 +38,7 @@ Learn more in [Angular Elements Overview](guide/elements).
|
||||
|
||||
## annotation
|
||||
|
||||
A structure that provides metadata for a class. See [decorator](guide/glossary#decorator).
|
||||
A structure that provides metadata for a class. See [decorator](#decorator).
|
||||
|
||||
{@a app-shell}
|
||||
|
||||
@ -53,6 +53,19 @@ You can use the Angular CLI to [generate](cli/generate#appshell) an app shell.
|
||||
This can improve the user experience by quickly launching a static rendered page (a skeleton common to all pages) while the browser downloads the full client version and switches to it automatically after the code loads.
|
||||
|
||||
See also [Service Worker and PWA](guide/service-worker-intro).
|
||||
{@a architect}
|
||||
|
||||
## Architect
|
||||
|
||||
The tool that the CLI uses to perform complex tasks such as compilation and test running, according to a provided configuration.
|
||||
Architect is a shell that runs a [builder](#builder) (defined in an [npm package](#npm-package)) with a given [target configuration](#target).
|
||||
|
||||
In the [workspace configuration file](guide/workspace-config#project-tool-configuration-options), an "architect" section provides configuration options for Architect builders.
|
||||
|
||||
For example, a built-in builder for linting is defined in the package `@angular-devkit/build_angular:tslint`, which uses the [TSLint](https://palantir.github.io/tslint/) tool to perform linting, with a configuration specified in a `tslint.json` file.
|
||||
|
||||
Use the [CLI command `ng run`](cli/run) to invoke a builder by specifying a [target configuration](#target) associated with that builder.
|
||||
Integrators can add builders to enable tools and workflows to run through the Angular CLI. For example, a custom builder can replace the third-party tools used by the built-in implementations for CLI commands such as `ng build` or `ng test`.
|
||||
|
||||
{@a attribute-directive}
|
||||
|
||||
@ -62,7 +75,7 @@ See also [Service Worker and PWA](guide/service-worker-intro).
|
||||
|
||||
## attribute directives
|
||||
|
||||
A category of [directive](guide/glossary#directive) that can listen to and modify the behavior of
|
||||
A category of [directive](#directive) that can listen to and modify the behavior of
|
||||
other HTML elements, attributes, properties, and components. They are usually represented
|
||||
as HTML attributes, hence the name.
|
||||
|
||||
@ -76,11 +89,11 @@ Learn more in [Attribute Directives](guide/attribute-directives).
|
||||
## binding
|
||||
|
||||
Generally, the practice of setting a variable or property to a data value.
|
||||
Within Angular, typically refers to [data binding](guide/glossary#data-binding),
|
||||
Within Angular, typically refers to [data binding](#data-binding),
|
||||
which coordinates DOM object properties with data object properties.
|
||||
|
||||
Sometimes refers to a [dependency-injection](guide/glossary#dependency-injection) binding
|
||||
between a [token](guide/glossary#token) and a dependency [provider](guide/glossary#provider).
|
||||
Sometimes refers to a [dependency-injection](#dependency-injection) binding
|
||||
between a [token](#token) and a dependency [provider](#provider).
|
||||
|
||||
{@a bootstrap}
|
||||
|
||||
@ -88,12 +101,24 @@ between a [token](guide/glossary#token) and a dependency [provider](guide/glossa
|
||||
|
||||
A way to initialize and launch an app or system.
|
||||
|
||||
In Angular, an app's root NgModule (`AppModule`) has a `bootstrap` property that identifies the app's top-level [components](guide/glossary#component).
|
||||
In Angular, an app's root NgModule (`AppModule`) has a `bootstrap` property that identifies the app's top-level [components](#component).
|
||||
During the bootstrap process, Angular creates and inserts these components into the `index.html` host web page.
|
||||
You can bootstrap multiple apps in the same `index.html`. Each app contains its own components.
|
||||
|
||||
Learn more in [Bootstrapping](guide/bootstrapping).
|
||||
|
||||
{@a builder}
|
||||
|
||||
## builder
|
||||
|
||||
A function that uses the [Architect](#architect) API to perform a complex process such as "build" or "test".
|
||||
The builder code is defined in an [npm package](#npm-package).
|
||||
|
||||
For example, [BrowserBuilder](https://github.com/angular/angular-cli/tree/master/packages/angular_devkit/build_angular/src/browser) runs a [webpack](https://webpack.js.org/) build for a browser target and [KarmaBuilder](https://github.com/angular/angular-cli/tree/master/packages/angular_devkit/build_angular/src/karma) starts the Karma server and runs a webpack build for unit tests.
|
||||
|
||||
The [CLI command `ng run`](cli/run) invokes a builder with a specific [target configuration](#target).
|
||||
The [workspace configuration](guide/workspace-config) file, `angular.json`, contains default configurations for built-in builders.
|
||||
|
||||
{@a C}
|
||||
|
||||
{@a case-conventions}
|
||||
@ -123,7 +148,7 @@ Upper snake case uses words in all capital letters connected with underscores. F
|
||||
|
||||
## class decorator
|
||||
|
||||
A [decorator](guide/glossary#decorator) that appears immediately before a class definition, which declares the class to be of the given type, and provides metadata suitable to the type.
|
||||
A [decorator](#decorator) that appears immediately before a class definition, which declares the class to be of the given type, and provides metadata suitable to the type.
|
||||
|
||||
The following decorators can declare Angular class types:
|
||||
* `@Component()`
|
||||
@ -137,7 +162,7 @@ The following decorators can declare Angular class types:
|
||||
|
||||
## class field decorator
|
||||
|
||||
A [decorator](guide/glossary#decorator) statement immediately before a field in a class definition that declares the type of that field. Some examples are `@Input` and `@Output`.
|
||||
A [decorator](#decorator) statement immediately before a field in a class definition that declares the type of that field. Some examples are `@Input` and `@Output`.
|
||||
|
||||
{@a collection}
|
||||
|
||||
@ -149,7 +174,7 @@ In Angular, a set of related [schematics](#schematic) collected in an [npm packa
|
||||
|
||||
## command-line interface (CLI)
|
||||
|
||||
The [Angular CLI](cli) is a command-line tool for managing the Angular development cycle. Use it to create the initial filesystem scaffolding for a [workspace](guide/glossary#workspace) or [project](guide/glossary#project), and to run [schematics](guide/glossary#schematic) that add and modify code for initial generic versions of various elements. The CLI supports all stages of the development cycle, including building, testing, bundling, and deployment.
|
||||
The [Angular CLI](cli) is a command-line tool for managing the Angular development cycle. Use it to create the initial filesystem scaffolding for a [workspace](#workspace) or [project](#project), and to run [schematics](#schematic) that add and modify code for initial generic versions of various elements. The CLI supports all stages of the development cycle, including building, testing, bundling, and deployment.
|
||||
|
||||
* To begin using the CLI for a new project, see [Getting Started](guide/quickstart).
|
||||
* To learn more about the full capabilities of the CLI, see the [CLI command reference](cli).
|
||||
@ -160,14 +185,19 @@ See also [Schematics CLI](#schematics-cli).
|
||||
|
||||
## component
|
||||
|
||||
A class with the `@Component()` [decorator](guide/glossary#decorator) that associates it with a companion [template](guide/glossary#template). Together, the component and template define a [view](guide/glossary#view).
|
||||
A component is a special type of [directive](guide/glossary#directive).
|
||||
A class with the `@Component()` [decorator](#decorator) that associates it with a companion [template](#template). Together, the component and template define a [view](#view).
|
||||
A component is a special type of [directive](#directive).
|
||||
The `@Component()` decorator extends the `@Directive()` decorator with template-oriented features.
|
||||
|
||||
An Angular component class is responsible for exposing data and handling most of the view's display and user-interaction logic through [data binding](guide/glossary#data-binding).
|
||||
An Angular component class is responsible for exposing data and handling most of the view's display and user-interaction logic through [data binding](#data-binding).
|
||||
|
||||
Read more about components, templates, and views in [Architecture Overview](guide/architecture).
|
||||
|
||||
## configuration
|
||||
|
||||
See [workspace configuration](#cli-config)
|
||||
|
||||
|
||||
{@a custom-element}
|
||||
|
||||
## custom element
|
||||
@ -178,7 +208,9 @@ The custom element feature extends HTML by allowing you to define a tag whose co
|
||||
|
||||
You can use the API to transform an Angular component so that it can be registered with the browser and used in any HTML that you add directly to the DOM within an Angular app. The custom element tag inserts the component's view, with change-detection and data-binding functionality, into content that would otherwise be displayed without Angular processing.
|
||||
|
||||
See also [dynamic component loading](guide/glossary#dynamic-components).
|
||||
See [Angular element](#angular-element).
|
||||
|
||||
See also [dynamic component loading](#dynamic-components).
|
||||
|
||||
|
||||
{@a D}
|
||||
@ -210,8 +242,8 @@ Read about the following forms of binding in [Template Syntax](guide/template-sy
|
||||
|
||||
## declarable
|
||||
|
||||
A class type that you can add to the `declarations` list of an [NgModule](guide/glossary#ngmodule).
|
||||
You can declare [components](guide/glossary#component), [directives](guide/glossary#directive), and [pipes](guide/glossary#pipe).
|
||||
A class type that you can add to the `declarations` list of an [NgModule](#ngmodule).
|
||||
You can declare [components](#component), [directives](#directive), and [pipes](#pipe).
|
||||
|
||||
Don't declare the following:
|
||||
* A class that's already declared in another NgModule
|
||||
@ -233,7 +265,7 @@ TypeScript adds support for decorators.
|
||||
Angular defines decorators that attach metadata to classes or properties
|
||||
so that it knows what those classes or properties mean and how they should work.
|
||||
|
||||
See [class decorator](guide/glossary#class-decorator), [class field decorator](guide/glossary#class-field-decorator).
|
||||
See [class decorator](#class-decorator), [class field decorator](#class-field-decorator).
|
||||
|
||||
{@a di}
|
||||
|
||||
@ -244,7 +276,7 @@ See [class decorator](guide/glossary#class-decorator), [class field decorator](g
|
||||
A design pattern and mechanism for creating and delivering some parts of an application (dependencies) to other parts of an application that require them.
|
||||
|
||||
In Angular, dependencies are typically services, but they also can be values, such as strings or functions.
|
||||
An [injector](guide/glossary#injector) for an app (created automatically during bootstrap) instantiates dependencies when needed, using a configured [provider](guide/glossary#provider) of the service or value.
|
||||
An [injector](#injector) for an app (created automatically during bootstrap) instantiates dependencies when needed, using a configured [provider](#provider) of the service or value.
|
||||
|
||||
Learn more in [Dependency Injection in Angular](guide/dependency-injection).
|
||||
|
||||
@ -252,7 +284,7 @@ Learn more in [Dependency Injection in Angular](guide/dependency-injection).
|
||||
|
||||
## DI token
|
||||
|
||||
A lookup token associated with a dependency [provider](guide/glossary#provider), for use with the [dependency injection](guide/glossary#di) system.
|
||||
A lookup token associated with a dependency [provider](#provider), for use with the [dependency injection](#di) system.
|
||||
|
||||
|
||||
{@a directive}
|
||||
@ -260,16 +292,16 @@ A lookup token associated with a dependency [provider](guide/glossary#provider),
|
||||
|
||||
## directive
|
||||
|
||||
A class that can modify the structure of the DOM or modify attributes in the DOM and component data model. A directive class definition is immediately preceded by a `@Directive()` [decorator](guide/glossary#decorator) that supplies metadata.
|
||||
A class that can modify the structure of the DOM or modify attributes in the DOM and component data model. A directive class definition is immediately preceded by a `@Directive()` [decorator](#decorator) that supplies metadata.
|
||||
|
||||
A directive class is usually associated with an HTML element or attribute, and that element or attribute is often referred to as the directive itself. When Angular finds a directive in an HTML [template](guide/glossary#template), it creates the matching directive class instance and gives the instance control over that portion of the browser DOM.
|
||||
A directive class is usually associated with an HTML element or attribute, and that element or attribute is often referred to as the directive itself. When Angular finds a directive in an HTML [template](#template), it creates the matching directive class instance and gives the instance control over that portion of the browser DOM.
|
||||
|
||||
There are three categories of directive:
|
||||
* [Components](guide/glossary#component) use `@Component()` (an extension of `@Directive()`) to associate a template with a class.
|
||||
* [Components](#component) use `@Component()` (an extension of `@Directive()`) to associate a template with a class.
|
||||
|
||||
* [Attribute directives](guide/glossary#attribute-directive) modify behavior and appearance of page elements.
|
||||
* [Attribute directives](#attribute-directive) modify behavior and appearance of page elements.
|
||||
|
||||
* [Structural directives](guide/glossary#structural-directive) modify the structure of the DOM.
|
||||
* [Structural directives](#structural-directive) modify the structure of the DOM.
|
||||
|
||||
Angular supplies a number of built-in directives that begin with the `ng` prefix.
|
||||
You can also create new directives to implement your own functionality.
|
||||
@ -288,7 +320,7 @@ Angular extends TypeScript with domain-specific languages for a number of domain
|
||||
|
||||
A technique for adding a component to the DOM at run time. Requires that you exclude the component from compilation and then connect it to Angular's change-detection and event-handling framework when you add it to the DOM.
|
||||
|
||||
See also [custom element](guide/glossary#custom-element), which provides an easier path with the same result.
|
||||
See also [custom element](#custom-element), which provides an easier path with the same result.
|
||||
|
||||
|
||||
{@a E}
|
||||
@ -299,7 +331,7 @@ See also [custom element](guide/glossary#custom-element), which provides an easi
|
||||
|
||||
NgModules or components that are loaded on launch are called eager-loaded, to distinguish them from those
|
||||
that are loaded at run time (lazy-loaded).
|
||||
See [lazy loading](guide/glossary#lazy-load).
|
||||
See [lazy loading](#lazy-load).
|
||||
|
||||
|
||||
{@a ecma}
|
||||
@ -308,7 +340,7 @@ See [lazy loading](guide/glossary#lazy-load).
|
||||
|
||||
The [official JavaScript language specification](https://en.wikipedia.org/wiki/ECMAScript).
|
||||
|
||||
Not all browsers support the latest ECMAScript standard, but you can use a [transpiler](guide/glossary#transpile) (like [TypeScript](guide/glossary#typescript)) to write code using the latest features, which will then be transpiled to code that runs on versions that are supported by browsers.
|
||||
Not all browsers support the latest ECMAScript standard, but you can use a [transpiler](#transpile) (like [TypeScript](#typescript)) to write code using the latest features, which will then be transpiled to code that runs on versions that are supported by browsers.
|
||||
|
||||
To learn more, see [Browser Support](guide/browser-support).
|
||||
|
||||
@ -324,16 +356,16 @@ without reference to the native element.
|
||||
The documentation generally refers to *elements* (`ElementRef` instances), as distinct from *DOM elements*
|
||||
(which can be accessed directly if necessary).
|
||||
|
||||
Compare to [custom element](guide/glossary#custom-element).
|
||||
Compare to [custom element](#custom-element).
|
||||
|
||||
{@a entry-point}
|
||||
|
||||
## entry point
|
||||
|
||||
A JavaScript symbol that makes parts of an [npm package](guide/npm-packages) available for import by other code.
|
||||
The Angular [scoped packages](guide/glossary#scoped-package) each have an entry point named `index`.
|
||||
The Angular [scoped packages](#scoped-package) each have an entry point named `index`.
|
||||
|
||||
Within Angular, use [NgModules](guide/glossary#ngmodule) to make public parts available for import by other NgModules.
|
||||
Within Angular, use [NgModules](#ngmodule) to make public parts available for import by other NgModules.
|
||||
|
||||
|
||||
{@a F}
|
||||
@ -350,7 +382,7 @@ Read more forms in the [Introduction to forms in Angular](guide/forms-overview).
|
||||
|
||||
## form model
|
||||
|
||||
The "source of truth" for the value and validation status of a form input element at a given point in time. When using [reactive forms](guide/glossary#reactive-forms), the form model is created explicitly in the component class. When using [template-driven forms](guide/glossary#template-driven-forms), the form model is implicitly created by directives.
|
||||
The "source of truth" for the value and validation status of a form input element at a given point in time. When using [reactive forms](#reactive-forms), the form model is created explicitly in the component class. When using [template-driven forms](#template-driven-forms), the form model is implicitly created by directives.
|
||||
|
||||
Learn more about reactive and template-driven forms in the [Introduction to forms in Angular](guide/forms-overview).
|
||||
|
||||
@ -375,22 +407,22 @@ To learn more, see [Form Validation](guide/form-validation).
|
||||
|
||||
## immutability
|
||||
|
||||
The ability to alter the state of a value after its creation. [Reactive forms](guide/glossary#reactive-forms) perform immutable changes in that
|
||||
each change to the data model produces a new data model rather than modifying the existing one. [Template-driven forms](guide/glossary#template-driven-forms) perform mutable changes with `NgModel` and [two-way data binding](guide/glossary#data-binding) to modify the existing data model in place.
|
||||
The ability to alter the state of a value after its creation. [Reactive forms](#reactive-forms) perform immutable changes in that
|
||||
each change to the data model produces a new data model rather than modifying the existing one. [Template-driven forms](#template-driven-forms) perform mutable changes with `NgModel` and [two-way data binding](#data-binding) to modify the existing data model in place.
|
||||
|
||||
{@a injectable}
|
||||
|
||||
## injectable
|
||||
|
||||
An Angular class or other definition that provides a dependency using the [dependency injection](guide/glossary#di) mechanism. An injectable [service](guide/glossary#service) class must be marked by the `@Injectable()` [decorator](guide/glossary#decorator). Other items, such as constant values, can also be injectable.
|
||||
An Angular class or other definition that provides a dependency using the [dependency injection](#di) mechanism. An injectable [service](#service) class must be marked by the `@Injectable()` [decorator](#decorator). Other items, such as constant values, can also be injectable.
|
||||
|
||||
{@a injector}
|
||||
|
||||
## injector
|
||||
|
||||
An object in the Angular [dependency-injection](guide/glossary#dependency-injection) system
|
||||
An object in the Angular [dependency-injection](#dependency-injection) system
|
||||
that can find a named dependency in its cache or create a dependency
|
||||
using a configured [provider](guide/glossary#provider).
|
||||
using a configured [provider](#provider).
|
||||
Injectors are created for NgModules automatically as part of the bootstrap process
|
||||
and are inherited through the component hierarchy.
|
||||
|
||||
@ -406,10 +438,10 @@ Learn more about the injector hierarchy in [Hierarchical Dependency Injectors](g
|
||||
|
||||
## input
|
||||
|
||||
When defining a [directive](guide/glossary#directive), the `@Input()` decorator on a directive property
|
||||
When defining a [directive](#directive), the `@Input()` decorator on a directive property
|
||||
makes that property available as a *target* of a [property binding](guide/template-syntax#property-binding).
|
||||
Data values flow into an input property from the data source identified
|
||||
in the [template expression](guide/glossary#template-expression) to the right of the equal sign.
|
||||
in the [template expression](#template-expression) to the right of the equal sign.
|
||||
|
||||
To learn more, see [input and output properties](guide/template-syntax#inputs-outputs).
|
||||
|
||||
@ -417,7 +449,7 @@ To learn more, see [input and output properties](guide/template-syntax#inputs-ou
|
||||
|
||||
## interpolation
|
||||
|
||||
A form of property [data binding](guide/glossary#data-binding) in which a [template expression](guide/glossary#template-expression) between double-curly braces renders as text.
|
||||
A form of property [data binding](#data-binding) in which a [template expression](#template-expression) between double-curly braces renders as text.
|
||||
That text can be concatenated with neighboring text before it is assigned to an element property
|
||||
or displayed between element tags, as in this example.
|
||||
|
||||
@ -436,7 +468,7 @@ Read more about [interpolation](guide/template-syntax#interpolation) in [Templat
|
||||
|
||||
## JavaScript
|
||||
|
||||
See [ECMAScript](guide/glossary#ecma), [TypeScript](guide/glossary#typescript).
|
||||
See [ECMAScript](#ecma), [TypeScript](#typescript).
|
||||
|
||||
|
||||
{@a jit}
|
||||
@ -451,7 +483,7 @@ JIT compilation is the default (as opposed to AOT compilation) when you run Angu
|
||||
JIT mode is strongly discouraged for production use
|
||||
because it results in large application payloads that hinder the bootstrap performance.
|
||||
|
||||
Compare to [ahead-of-time (AOT) compilation](guide/glossary#aot).
|
||||
Compare to [ahead-of-time (AOT) compilation](#aot).
|
||||
|
||||
|
||||
{@a K}
|
||||
@ -464,21 +496,22 @@ Compare to [ahead-of-time (AOT) compilation](guide/glossary#aot).
|
||||
## lazy loading
|
||||
|
||||
A process that speeds up application load time by splitting the application into multiple bundles and loading them on demand.
|
||||
For example, dependencies can be lazy loaded as needed—as opposed to [eager-loaded](guide/glossary#eager-loading) modules that are required by the root module and are thus loaded on launch.
|
||||
For example, dependencies can be lazy loaded as needed—as opposed to [eager-loaded](#eager-loading) modules that are required by the root module and are thus loaded on launch.
|
||||
|
||||
The [router](guide/glossary#router) makes use of lazy loading to load child views only when the parent view is activated.
|
||||
The [router](#router) makes use of lazy loading to load child views only when the parent view is activated.
|
||||
Similarly, you can build custom elements that can be loaded into an Angular app when needed.
|
||||
|
||||
{@a library}
|
||||
|
||||
## library
|
||||
|
||||
In Angular, a [project](guide/glossary#project) that provides functionality that can be included in other Angular apps.
|
||||
In Angular, a [project](#project) that provides functionality that can be included in other Angular apps.
|
||||
A library isn't a complete Angular app and can't run independently.
|
||||
(To add re-usable Angular functionality to non-Angular web apps, you can use Angular [custom elements](#angular-element).)
|
||||
|
||||
* Library developers can use the [Angular CLI](guide/glossary#cli) to `generate` scaffolding for a new library in an existing [workspace](guide/glossary#workspace), and can publish a library as an `npm` package.
|
||||
* Library developers can use the [Angular CLI](#cli) to `generate` scaffolding for a new library in an existing [workspace](#workspace), and can publish a library as an `npm` package.
|
||||
|
||||
* Application developers can use the [Angular CLI](guide/glossary#cli) to `add` a published library for use with an application in the same [workspace](guide/glossary#workspace).
|
||||
* Application developers can use the [Angular CLI](#cli) to `add` a published library for use with an application in the same [workspace](#workspace).
|
||||
|
||||
See also [schematic](#schematic).
|
||||
|
||||
@ -486,14 +519,14 @@ See also [schematic](#schematic).
|
||||
|
||||
## lifecycle hook
|
||||
|
||||
An interface that allows you to tap into the lifecycle of [directives](guide/glossary#directive) and [components](guide/glossary#component) as they are created, updated, and destroyed.
|
||||
An interface that allows you to tap into the lifecycle of [directives](#directive) and [components](#component) as they are created, updated, and destroyed.
|
||||
|
||||
Each interface has a single hook method whose name is the interface name prefixed with `ng`.
|
||||
For example, the `OnInit` interface has a hook method named `ngOnInit`.
|
||||
|
||||
Angular calls these hook methods in the following order:
|
||||
|
||||
* `ngOnChanges`: When an [input](guide/glossary#input)/[output](guide/glossary#output) binding value changes.
|
||||
* `ngOnChanges`: When an [input](#input)/[output](#output) binding value changes.
|
||||
* `ngOnInit`: After the first `ngOnChanges`.
|
||||
* `ngDoCheck`: Developer's custom change detection.
|
||||
* `ngAfterContentInit`: After component content initialized.
|
||||
@ -517,7 +550,7 @@ In JavaScript (ECMAScript), each file is a module and all objects defined in the
|
||||
|
||||
Angular ships as a collection of JavaScript modules (also called libraries). Each Angular library name begins with the `@angular` prefix. Install Angular libraries with the [npm package manager](https://docs.npmjs.com/getting-started/what-is-npm) and import parts of them with JavaScript `import` declarations.
|
||||
|
||||
Compare to [NgModule](guide/glossary#ngmodule).
|
||||
Compare to [NgModule](#ngmodule).
|
||||
|
||||
|
||||
{@a N}
|
||||
@ -526,12 +559,12 @@ Compare to [NgModule](guide/glossary#ngmodule).
|
||||
|
||||
## NgModule
|
||||
|
||||
A class definition preceded by the `@NgModule()` [decorator](guide/glossary#decorator), which declares and serves as a manifest for a block of code dedicated to an application domain, a workflow, or a closely related set of capabilities.
|
||||
A class definition preceded by the `@NgModule()` [decorator](#decorator), which declares and serves as a manifest for a block of code dedicated to an application domain, a workflow, or a closely related set of capabilities.
|
||||
|
||||
Like a [JavaScript module](guide/glossary#module), an NgModule can export functionality for use by other NgModules and import public functionality from other NgModules.
|
||||
The metadata for an NgModule class collects components, directives, and pipes that the application uses along with the list of imports and exports. See also [declarable](guide/glossary#declarable).
|
||||
Like a [JavaScript module](#module), an NgModule can export functionality for use by other NgModules and import public functionality from other NgModules.
|
||||
The metadata for an NgModule class collects components, directives, and pipes that the application uses along with the list of imports and exports. See also [declarable](#declarable).
|
||||
|
||||
NgModules are typically named after the file in which the exported thing is defined. For example, the Angular [DatePipe](api/common/DatePipe) class belongs to a feature module named `date_pipe` in the file `date_pipe.ts`. You import them from an Angular [scoped package](guide/glossary#scoped-package) such as `@angular/core`.
|
||||
NgModules are typically named after the file in which the exported thing is defined. For example, the Angular [DatePipe](api/common/DatePipe) class belongs to a feature module named `date_pipe` in the file `date_pipe.ts`. You import them from an Angular [scoped package](#scoped-package) such as `@angular/core`.
|
||||
|
||||
Every Angular application has a root module. By convention, the class is called `AppModule` and resides in a file named `app.module.ts`.
|
||||
|
||||
@ -551,7 +584,7 @@ Learn more about how Angular uses [Npm Packages](guide/npm-packages).
|
||||
|
||||
## observable
|
||||
|
||||
A producer of multiple values, which it pushes to [subscribers](guide/glossary#subscriber). Used for asynchronous event handling throughout Angular. You execute an observable by subscribing to it with its `subscribe()` method, passing callbacks for notifications of new values, errors, or completion.
|
||||
A producer of multiple values, which it pushes to [subscribers](#subscriber). Used for asynchronous event handling throughout Angular. You execute an observable by subscribing to it with its `subscribe()` method, passing callbacks for notifications of new values, errors, or completion.
|
||||
|
||||
Observables can deliver single or multiple values of any type to subscribers, either synchronously (as a function delivers a value to its caller) or on a schedule. A subscriber receives notification of new values as they are produced and notification of either normal completion or error completion.
|
||||
|
||||
@ -564,16 +597,16 @@ To learn more, see [Observables](guide/observables).
|
||||
|
||||
## observer
|
||||
|
||||
An object passed to the `subscribe()` method for an [observable](guide/glossary#observable). The object defines the callbacks for the [subscriber](guide/glossary#subscriber).
|
||||
An object passed to the `subscribe()` method for an [observable](#observable). The object defines the callbacks for the [subscriber](#subscriber).
|
||||
|
||||
{@a output}
|
||||
|
||||
## output
|
||||
|
||||
When defining a [directive](guide/glossary#directive), the `@Output{}` decorator on a directive property
|
||||
When defining a [directive](#directive), the `@Output{}` decorator on a directive property
|
||||
makes that property available as a *target* of [event binding](guide/template-syntax#event-binding).
|
||||
Events stream *out* of this property to the receiver identified
|
||||
in the [template expression](guide/glossary#template-expression) to the right of the equal sign.
|
||||
in the [template expression](#template-expression) to the right of the equal sign.
|
||||
|
||||
To learn more, see [Input and Output Properties](guide/template-syntax#inputs-outputs).
|
||||
|
||||
@ -584,7 +617,7 @@ To learn more, see [Input and Output Properties](guide/template-syntax#inputs-ou
|
||||
|
||||
## pipe
|
||||
|
||||
A class which is preceded by the `@Pipe{}` decorator and which defines a function that transforms input values to output values for display in a [view](guide/glossary#view). Angular defines various pipes, and you can define new pipes.
|
||||
A class which is preceded by the `@Pipe{}` decorator and which defines a function that transforms input values to output values for display in a [view](#view). Angular defines various pipes, and you can define new pipes.
|
||||
|
||||
To learn more, see [Pipes](guide/pipes).
|
||||
|
||||
@ -599,22 +632,26 @@ See [Browser Support](guide/browser-support) for polyfills that support particul
|
||||
|
||||
## project
|
||||
|
||||
In Angular, a folder within a [workspace](guide/glossary#workspace) that contains an Angular app or [library](guide/glossary#library).
|
||||
A workspace can contain multiple projects.
|
||||
All apps in a workspace can use libraries in the same workspace.
|
||||
In the Angular CLI, a standalone application or [library](#library) that can be created or modified by a CLI command.
|
||||
|
||||
A project, as generated by the [`ng new`](cli/new), contains the set of source files, resources, and configuration files that you need to develop and test the application using the CLI. Projects can also be created with the `ng generate application` and `ng generate library` commands.
|
||||
|
||||
For more information, see [Project File Structure](guide/file-structure).
|
||||
|
||||
The [`angular.json`](guide/workspace-config) file configures all projects in a [workspace](#workspace).
|
||||
|
||||
{@a provider}
|
||||
|
||||
## provider
|
||||
|
||||
An object that implements one of the [`Provider`](api/core/Provider) interfaces. A provider object defines how to obtain an injectable dependency associated with a [DI token](guide/glossary#token).
|
||||
An [injector](guide/glossary#injector) uses the provider to create a new instance of a dependency
|
||||
An object that implements one of the [`Provider`](api/core/Provider) interfaces. A provider object defines how to obtain an injectable dependency associated with a [DI token](#token).
|
||||
An [injector](#injector) uses the provider to create a new instance of a dependency
|
||||
for a class that requires it.
|
||||
|
||||
Angular registers its own providers with every injector, for services that Angular defines.
|
||||
You can register your own providers for services that your app needs.
|
||||
|
||||
See also [service](guide/glossary#service), [dependency injection](guide/glossary#di).
|
||||
See also [service](#service), [dependency injection](#di).
|
||||
|
||||
Learn more in [Dependency Injection](guide/dependency-injection).
|
||||
|
||||
@ -628,7 +665,7 @@ Learn more in [Dependency Injection](guide/dependency-injection).
|
||||
## reactive forms
|
||||
|
||||
A framework for building Angular forms through code in a component.
|
||||
The alternative is a [template-driven form](guide/glossary#template-driven-forms).
|
||||
The alternative is a [template-driven form](#template-driven-forms).
|
||||
|
||||
When using reactive forms:
|
||||
|
||||
@ -645,11 +682,11 @@ The alternative is a template-driven form. For an introduction and comparison of
|
||||
|
||||
## router
|
||||
|
||||
A tool that configures and implements navigation among states and [views](guide/glossary#view) within an Angular app.
|
||||
A tool that configures and implements navigation among states and [views](#view) within an Angular app.
|
||||
|
||||
The `Router` module is an [NgModule](guide/glossary#ngmodule) that provides the necessary service providers and directives for navigating through application views. A [routing component](guide/glossary#routing-component) is one that imports the `Router` module and whose template contains a `RouterOutlet` element where it can display views produced by the router.
|
||||
The `Router` module is an [NgModule](#ngmodule) that provides the necessary service providers and directives for navigating through application views. A [routing component](#routing-component) is one that imports the `Router` module and whose template contains a `RouterOutlet` element where it can display views produced by the router.
|
||||
|
||||
The router defines navigation among views on a single page, as opposed to navigation among pages. It interprets URL-like links to determine which views to create or destroy, and which components to load or unload. It allows you to take advantage of [lazy loading](guide/glossary#lazy-load) in your Angular apps.
|
||||
The router defines navigation among views on a single page, as opposed to navigation among pages. It interprets URL-like links to determine which views to create or destroy, and which components to load or unload. It allows you to take advantage of [lazy loading](#lazy-load) in your Angular apps.
|
||||
|
||||
To learn more, see [Routing and Navigation](guide/router).
|
||||
|
||||
@ -657,20 +694,21 @@ To learn more, see [Routing and Navigation](guide/router).
|
||||
|
||||
## router outlet
|
||||
|
||||
A [directive](guide/glossary#directive) that acts as a placeholder in a routing component's template. Angular dynamically renders the template based on the current router state.
|
||||
A [directive](#directive) that acts as a placeholder in a routing component's template. Angular dynamically renders the template based on the current router state.
|
||||
|
||||
{@a router-component}
|
||||
|
||||
## routing component
|
||||
|
||||
An Angular [component](guide/glossary#component) with a `RouterOutlet` directive in its template that displays views based on router navigations.
|
||||
An Angular [component](#component) with a `RouterOutlet` directive in its template that displays views based on router navigations.
|
||||
|
||||
For more information, see [Routing and Navigation](guide/router).
|
||||
|
||||
{@a rule}
|
||||
|
||||
In [schematics](#schematic), a function that operates on a [file tree](#file-tree) to create, delete, or modify files in a specific manner, and returns a new `Tree` object.
|
||||
## rule
|
||||
|
||||
In [schematics](#schematic), a function that operates on a [file tree](#file-tree) to create, delete, or modify files in a specific manner.
|
||||
|
||||
{@a S}
|
||||
|
||||
@ -680,13 +718,15 @@ In [schematics](#schematic), a function that operates on a [file tree](#file-tre
|
||||
|
||||
A scaffolding library that defines how to generate or transform a programming project by creating, modifying, refactoring, or moving files and code.
|
||||
A schematic defines [rules](#rule) that operate on a virtual file system called a [tree](#file-tree).
|
||||
The [Angular CLI](guide/glossary#cli) uses schematics to generate and modify [Angular projects](guide/glossary#project) and parts of projects.
|
||||
|
||||
The [Angular CLI](#cli) uses schematics to generate and modify [Angular projects](#project) and parts of projects.
|
||||
|
||||
* Angular provides a set of schematics for use with the CLI. See the [Angular CLI command reference](cli). The [`ng add`](cli/add) command runs schematics as part of adding a library to your project. The [`ng generate`](cli/generate) command runs schematics to create apps, libraries, and Angular code constructs.
|
||||
|
||||
* [Library](#library) developers can use the [Schematics CLI](#schematics-cli) to create schematics that enable the Angular CLI to add and update their published libraries, and to generate artifacts the library defines.
|
||||
* [Library](#library) developers can create schematics that enable the Angular CLI to add and update their published libraries, and to generate artifacts the library defines.
|
||||
Add these schematics to the npm package that you use to publish and share your library.
|
||||
|
||||
For more information, see [devkit documentation](https://www.npmjs.com/package/@angular-devkit/schematics).
|
||||
For more information, see [Schematics](guide/schematics) and [Integrating Libraries with the CLI](guide/creating-libraries#integrating-with-the-cli).
|
||||
|
||||
{@a schematics-cli}
|
||||
|
||||
@ -699,7 +739,7 @@ Using Node 6.9 or above, install the Schematics CLI globally:
|
||||
npm install -g @angular-devkit/schematics-cli
|
||||
</code-example>
|
||||
|
||||
This installs the `schematics` executable, which you can use to create a new project, add a new schematic to an existing project, or extend an existing schematic.
|
||||
This installs the `schematics` executable, which you can use to create a new schematics [collection](#collection) with an initial named schematic. The collection folder is a workspace for schematics. You can also use the `schematics` command to add a new schematic to an existing collection, or extend an existing schematic.
|
||||
|
||||
{@a scoped-package}
|
||||
|
||||
@ -724,19 +764,19 @@ It can also pre-generate pages as HTML files that you serve later.
|
||||
This technique can improve performance on mobile and low-powered devices and improve the user experience by showing a static first page quickly while the client-side app is loading.
|
||||
The static version can also make your app more visible to web crawlers.
|
||||
|
||||
You can easily prepare an app for server-side rendering by using the [CLI](guide/glossary#cli) to run the [Angular Universal](#universal) tool, using the `@nguniversal/express-engine` [schematic](#schematic).
|
||||
You can easily prepare an app for server-side rendering by using the [CLI](#cli) to run the [Angular Universal](#universal) tool, using the `@nguniversal/express-engine` [schematic](#schematic).
|
||||
|
||||
|
||||
{@a service}
|
||||
|
||||
## service
|
||||
|
||||
In Angular, a class with the [@Injectable()](guide/glossary#injectable) decorator that encapsulates non-UI logic and code that can be reused across an application.
|
||||
In Angular, a class with the [@Injectable()](#injectable) decorator that encapsulates non-UI logic and code that can be reused across an application.
|
||||
Angular distinguishes components from services to increase modularity and reusability.
|
||||
|
||||
The `@Injectable()` metadata allows the service class to be used with the [dependency injection](guide/glossary#di) mechanism.
|
||||
The injectable class is instantiated by a [provider](guide/glossary#provider).
|
||||
[Injectors](guide/glossary#injector) maintain lists of providers and use them to provide service instances when they are required by components or other services.
|
||||
The `@Injectable()` metadata allows the service class to be used with the [dependency injection](#di) mechanism.
|
||||
The injectable class is instantiated by a [provider](#provider).
|
||||
[Injectors](#injector) maintain lists of providers and use them to provide service instances when they are required by components or other services.
|
||||
|
||||
To learn more, see [Introduction to Services and Dependency Injection](guide/architecture-services).
|
||||
|
||||
@ -745,7 +785,7 @@ To learn more, see [Introduction to Services and Dependency Injection](guide/arc
|
||||
|
||||
## structural directives
|
||||
|
||||
A category of [directive](guide/glossary#directive) that is responsible for shaping HTML layout by modifying the DOM&mdashthat is, adding, removing, or manipulating elements and their children.
|
||||
A category of [directive](#directive) that is responsible for shaping HTML layout by modifying the DOM&mdashthat is, adding, removing, or manipulating elements and their children.
|
||||
|
||||
To learn more, see [Structural Directives](guide/structural-directives).
|
||||
|
||||
@ -753,42 +793,57 @@ To learn more, see [Structural Directives](guide/structural-directives).
|
||||
|
||||
## subscriber
|
||||
|
||||
A function that defines how to obtain or generate values or messages to be published. This function is executed when a consumer calls the `subscribe()` method of an [observable](guide/glossary#observable).
|
||||
A function that defines how to obtain or generate values or messages to be published. This function is executed when a consumer calls the `subscribe()` method of an [observable](#observable).
|
||||
|
||||
The act of subscribing to an observable triggers its execution, associates callbacks with it, and creates a `Subscription` object that lets you unsubscribe.
|
||||
|
||||
The `subscribe()` method takes a JavaScript object (called an [observer](guide/glossary#observer)) with up to three callbacks, one for each type of notification that an observable can deliver:
|
||||
The `subscribe()` method takes a JavaScript object (called an [observer](#observer)) with up to three callbacks, one for each type of notification that an observable can deliver:
|
||||
|
||||
* The `next` notification sends a value such as a number, a string, or an object.
|
||||
* The `error` notification sends a JavaScript Error or exception.
|
||||
* The `complete` notification doesn't send a value, but the handler is called when the call completes. Scheduled values can continue to be returned after the call completes.
|
||||
|
||||
{@a T}
|
||||
|
||||
{@a target}
|
||||
|
||||
## target
|
||||
|
||||
A buildable or runnable subset of a [project](#project), configured as an object in the [workspace configuration file](guide/workspace-config#project-tool-configuration-options), and executed by an [Architect](#architect) [builder](#builder).
|
||||
|
||||
In the `angular.json` file, each project has an "architect" section that contains targets which configure builders. Some of these targets correspond to [CLI commands](#cli), such as `build`, `serve`, `test`, and `lint`.
|
||||
|
||||
For example, the Architect builder invoked by the `ng build` command to compile a project uses a particular build tool, and has a default configuration whose values can be overridden on the command line. The `build` target also defines an alternate configuration for a "production" build, that can be invoked with the `--prod` flag on the `build` command.
|
||||
|
||||
The Architect tool provides a set of builders. The [`ng new` command](cli/new) provides a set of targets for the initial application project. The [`ng generate application`](cli/generate#application) and [`ng generate library`](cli/generate#library) commands provide a set of targets for each new [project](#project). These targets, their options and configurations, can be customized to meet the needs of your project. For example, you may want to add a "staging" or "testing" configuration to a project's "build" target.
|
||||
|
||||
You can also define a custom builder, and add a target to the project configuration that uses your custom builder. You can then run the target using the [`ng run`](cli/run) CLI command.
|
||||
|
||||
{@a template}
|
||||
|
||||
## template
|
||||
|
||||
Code associated with a component that defines how to render the component's [view](guide/glossary#view).
|
||||
Code associated with a component that defines how to render the component's [view](#view).
|
||||
|
||||
A template combines straight HTML with Angular [data-binding](guide/glossary#data-binding) syntax, [directives](guide/glossary#directive),
|
||||
and [template expressions](guide/glossary#template-expression) (logical constructs).
|
||||
A template combines straight HTML with Angular [data-binding](#data-binding) syntax, [directives](#directive),
|
||||
and [template expressions](#template-expression) (logical constructs).
|
||||
The Angular elements insert or calculate values that modify the HTML elements before the page is displayed.
|
||||
|
||||
A template is associated with a [component](guide/glossary#component) class through the `@Component()` [decorator](guide/glossary#decorator). The HTML can be provided inline, as the value of the `template` property, or in a separate HTML file linked through the `templateUrl` property.
|
||||
A template is associated with a [component](#component) class through the `@Component()` [decorator](#decorator). The HTML can be provided inline, as the value of the `template` property, or in a separate HTML file linked through the `templateUrl` property.
|
||||
|
||||
Additional templates, represented by `TemplateRef` objects, can define alternative or *embedded* views, which can be referenced from multiple components.
|
||||
|
||||
{@a template-drive-forms}
|
||||
{@a template-driven-forms}
|
||||
|
||||
## template-driven forms
|
||||
|
||||
A format for building Angular forms using HTML forms and input elements in the view.
|
||||
The alternative format uses the [reactive forms](guide/glossary#reactive-forms) framework.
|
||||
The alternative format uses the [reactive forms](#reactive-forms) framework.
|
||||
|
||||
When using template-driven forms:
|
||||
|
||||
* The "source of truth" is the template. The validation is defined using attributes on the individual input elements.
|
||||
* [Two-way binding](guide/glossary#data-binding) with `ngModel` keeps the component model synchronized with the user's entry into the input elements.
|
||||
* [Two-way binding](#data-binding) with `ngModel` keeps the component model synchronized with the user's entry into the input elements.
|
||||
* Behind the scenes, Angular creates a new control for each input element, provided you have set up a `name` attribute and two-way binding for each input.
|
||||
* The associated Angular directives are prefixed with `ng` such as `ngForm`, `ngModel`, and `ngModelGroup`.
|
||||
|
||||
@ -798,7 +853,7 @@ The alternative is a reactive form. For an introduction and comparison of both f
|
||||
|
||||
## template expression
|
||||
|
||||
A TypeScript-like syntax that Angular evaluates within a [data binding](guide/glossary#data-binding).
|
||||
A TypeScript-like syntax that Angular evaluates within a [data binding](#data-binding).
|
||||
|
||||
Read about how to write template expressions in [Template expressions](guide/template-syntax#template-expressions).
|
||||
|
||||
@ -806,7 +861,7 @@ Read about how to write template expressions in [Template expressions](guide/te
|
||||
|
||||
## token
|
||||
|
||||
An opaque identifier used for efficient table lookup. In Angular, a [DI token](guide/glossary#di-token) is used to find [providers](guide/glossary#provider) of dependencies in the [dependency injection](guide/glossary#di) system.
|
||||
An opaque identifier used for efficient table lookup. In Angular, a [DI token](#di-token) is used to find [providers](#provider) of dependencies in the [dependency injection](#di) system.
|
||||
|
||||
{@a transpile}
|
||||
|
||||
@ -853,18 +908,18 @@ To learn more, see [Angular Universal: server-side rendering](guide/universal).
|
||||
## view
|
||||
|
||||
The smallest grouping of display elements that can be created and destroyed together.
|
||||
Angular renders a view under the control of one or more [directives](guide/glossary#directive),
|
||||
especially [component](guide/glossary#component) directives and their companion [templates](guide/glossary#template).
|
||||
Angular renders a view under the control of one or more [directives](#directive),
|
||||
especially [component](#component) directives and their companion [templates](#template).
|
||||
|
||||
A view is specifically represented by a `ViewRef` instance associated with the component.
|
||||
A view that belongs to a component is called a *host view*.
|
||||
Views are typically collected into [view hierarchies](guide/glossary#view-tree).
|
||||
Views are typically collected into [view hierarchies](#view-tree).
|
||||
|
||||
Properties of elements in a view can change dynamically, in response to user actions;
|
||||
the structure (number and order) of elements in a view can't.
|
||||
You can change the structure of elements by inserting, moving, or removing nested views within their view containers.
|
||||
|
||||
View hierarchies can be loaded and unloaded dynamically as the user navigates through the application, typically under the control of a [router](guide/glossary#router).
|
||||
View hierarchies can be loaded and unloaded dynamically as the user navigates through the application, typically under the control of a [router](#router).
|
||||
|
||||
{@a view-tree}
|
||||
|
||||
@ -879,16 +934,35 @@ The view hierarchy doesn't imply a component hierarchy. Views that are embedded
|
||||
|
||||
## web component
|
||||
|
||||
See [custom element](guide/glossary#custom-element).
|
||||
See [custom element](#custom-element).
|
||||
|
||||
{@a workspace}
|
||||
|
||||
## workspace
|
||||
|
||||
In Angular, a folder that contains [projects](guide/glossary#project) (that is, apps and libraries).
|
||||
The [CLI](guide/glossary#cli) `ng new` command creates a workspace to contain projects.
|
||||
A collection of Angular [projects](#project) (that is, applications and libraries) powered by the [Angular CLI] (#cli) that are typically co-located in a single source-control repository (such as [git](https://git-scm.com/)).
|
||||
|
||||
The [CLI](#cli) [`ng new` command](cli/new) creates a file system directory (the "workspace root").
|
||||
In the workspace root, it also creates the workspace [configuration file](#configuration) (`angular.json`) and, by default, an initial application project with the same name.
|
||||
|
||||
Commands that create or operate on apps and libraries (such as `add` and `generate`) must be executed from within a workspace folder.
|
||||
|
||||
For more information, see [Workspace Configuration](guide/workspace-config).
|
||||
|
||||
{@a cli-config}
|
||||
|
||||
{@a config}
|
||||
|
||||
## workspace configuration
|
||||
|
||||
A file named `angular.json` at the root level of an Angular [workspace](#workspace) provides workspace-wide and project-specific configuration defaults for build and development tools that are provided by or integrated with the [Angular CLI](#cli).
|
||||
|
||||
For more information, see [Workspace Configuration](guide/workspace-config).
|
||||
|
||||
Additional project-specific configuration files are used by tools, such as `package.json` for the [npm package manager](#npm-package), `tsconfig.json` for [TypeScript transpilation](#transpile), and `tslint.json` for [TSLint](https://palantir.github.io/tslint/).
|
||||
|
||||
For more information, see [Workspace and Project File Structure](guide/file-structure).
|
||||
|
||||
{@a X}
|
||||
|
||||
|
||||
@ -902,7 +976,7 @@ Commands that create or operate on apps and libraries (such as `add` and `genera
|
||||
|
||||
An execution context for a set of asynchronous tasks. Useful for debugging, profiling, and testing apps that include asynchronous operations such as event processing, promises, and calls to remote servers.
|
||||
|
||||
An Angular app runs in a zone where it can respond to asynchronous events by checking for data changes and updating the information it displays by resolving [data bindings](guide/glossary#data-binding).
|
||||
An Angular app runs in a zone where it can respond to asynchronous events by checking for data changes and updating the information it displays by resolving [data bindings](#data-binding).
|
||||
|
||||
A zone client can take action before and after an async operation completes.
|
||||
|
||||
|
@ -15,6 +15,9 @@ For the final sample app with two lazy loaded modules that this page describes,
|
||||
|
||||
## High level view
|
||||
|
||||
By default, NgModules are eagerly loaded, which means that as soon as the app loads, so do all the NgModules, whether or not they are immediately necessary. For large apps with lots of routes, consider lazy loading—a design pattern that loads NgModules as needed. Lazy loading helps keep initial
|
||||
bundle sizes smaller, which in turn helps decrease load times.
|
||||
|
||||
There are three main steps to setting up a lazy loaded feature module:
|
||||
|
||||
1. Create the feature module.
|
||||
@ -67,9 +70,6 @@ ng generate component customers/customer-list
|
||||
This creates a folder inside of `customers` called `customer-list`
|
||||
with the four files that make up the component.
|
||||
|
||||
<!-- For more information
|
||||
about components, see [Components](). -->
|
||||
|
||||
Just like with the routing module, the CLI imports the
|
||||
`CustomerListComponent` into the `CustomersModule`.
|
||||
|
||||
@ -217,7 +217,7 @@ knows that the route list is only responsible for providing additional routes an
|
||||
|
||||
`forRoot()` contains injector configuration which is global; such as configuring the Router. `forChild()` has no injector configuration, only directives such as `RouterOutlet` and `RouterLink`.
|
||||
|
||||
For more information, see the [`forRoot()` deep dive](guide/singleton-services#forRoot) section of the [Singleton Services](guide/singleton-services) guide.
|
||||
For more information, see the [`forRoot()` pattern](guide/singleton-services#forRoot) section of the [Singleton Services](guide/singleton-services) guide.
|
||||
|
||||
<hr>
|
||||
|
||||
|
@ -89,7 +89,7 @@ Package name | Description
|
||||
|
||||
Many browsers lack native support for some features in the latest HTML standards,
|
||||
features that Angular requires.
|
||||
[_Polyfills_](https://en.wikipedia.org/wiki/Polyfill) can emulate the missing features.
|
||||
[_Polyfills_](https://en.wikipedia.org/wiki/Polyfill_(programming)) can emulate the missing features.
|
||||
The [Browser Support](guide/browser-support) guide explains which browsers need polyfills and
|
||||
how you can add them.
|
||||
|
||||
|
@ -2261,7 +2261,7 @@ For the `@routeAnimation` transitions to key off states, you'll need to provide
|
||||
|
||||
</code-example>
|
||||
|
||||
The `@routeAnimation` property is bound to the `getAnimationData` with the provided `routerOutlet` reference, so you'll need to define that function in the `AppComponent`. The `getAnimationData` function returns the animation property from the `data` provided through the `ActivatedRoute`. The `animation` property matches the `transition` names you used in the `slideDownAnimation` defined in `animations.ts`.
|
||||
The `@routeAnimation` property is bound to the `getAnimationData` with the provided `routerOutlet` reference, so you'll need to define that function in the `AppComponent`. The `getAnimationData` function returns the animation property from the `data` provided through the `ActivatedRoute`. The `animation` property matches the `transition` names you used in the `slideInAnimation` defined in `animations.ts`.
|
||||
|
||||
<code-example path="router/src/app/app.component.2.ts" linenums="false" header="src/app/app.component.ts (router outlet)" region="function-binding">
|
||||
|
||||
@ -2677,7 +2677,7 @@ display the `Crisis Center Home` and `Crisis Detail` route components.
|
||||
|
||||
The `Crisis Detail` route is a child of the `Crisis List`. The router [reuses components](#reuse)
|
||||
by default, so the `Crisis Detail` component will be re-used as you select different crises.
|
||||
In contrast, back in the `Hero Detail` route, the component was recreated each time you selected a different hero.
|
||||
In contrast, back in the `Hero Detail` route, [the component was recreated](#snapshot-the-no-observable-alternative) each time you selected a different hero from the list of heroes.
|
||||
|
||||
At the top level, paths that begin with `/` refer to the root of the application.
|
||||
But child routes *extend* the path of the parent route.
|
||||
|
@ -157,7 +157,7 @@ export class <%= classify(name) %>Service {
|
||||
|
||||
</code-example>
|
||||
|
||||
* The `classify` and `dasherize` methods are utility functions you schematic will use to transform your source template and filename.
|
||||
* The `classify` and `dasherize` methods are utility functions that your schematic will use to transform your source template and filename.
|
||||
|
||||
* The `name` is provided as a property from your factory function. It is the same `name` you defined in the schema.
|
||||
|
||||
|
@ -25,7 +25,7 @@ There are two ways to make a service a singleton in Angular:
|
||||
Beginning with Angular 6.0, the preferred way to create a singleton service is to set `providedIn` to `root` on the service's `@Injectable()` decorator. This tells Angular
|
||||
to provide the service in the application root.
|
||||
|
||||
<code-example path="providers/src/app/user.service.0.ts" header="src/app/user.service.0.ts" linenums="false"> </code-example>
|
||||
<code-example path="providers/src/app/user.service.0.ts" header="src/app/user.service.ts" linenums="false"> </code-example>
|
||||
|
||||
For more detailed information on services, see the [Services](tutorial/toh-pt4) chapter of the
|
||||
[Tour of Heroes tutorial](tutorial).
|
||||
|
@ -179,7 +179,7 @@ Some additional options (listed below) can only be set through the configuration
|
||||
|
||||
## Project asset configuration
|
||||
|
||||
Each `build` target configuration can include as `assets` array that lists files or folders you want to copy as-is when building your project.
|
||||
Each `build` target configuration can include an `assets` array that lists files or folders you want to copy as-is when building your project.
|
||||
By default, the `src/assets/` folder and `src/favicon.ico` are copied over.
|
||||
|
||||
<code-example format="." language="json" linenums="false">
|
||||
|
@ -490,6 +490,12 @@
|
||||
"rev": true,
|
||||
"title": "Carbon Components Angular",
|
||||
"url": "https://angular.carbondesignsystem.com/"
|
||||
},
|
||||
"jigsaw": {
|
||||
"desc": "Jigsaw provides a set of web components based on Angular. It is supporting the development of all applications of Big Data Product of ZTE (http://www.zte.com.cn).",
|
||||
"rev": true,
|
||||
"title": "Awade Jigsaw (Chinese)",
|
||||
"url": "http://rdk.zte.com.cn/components"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,9 +54,9 @@
|
||||
{"type": 301, "source": "/**/api/common/SelectControlValueAccessor-*", "destination": "/api/forms/SelectControlValueAccessor"},
|
||||
{"type": 301, "source": "/**/api/common/NgModel", "destination": "/api/forms/NgModel"},
|
||||
|
||||
// APIs under `http` package is deprecated and new APIs are available under `common/http` package
|
||||
{"type": 301, "source": "/api/http/:rest*", "destination": "/guide/deprecation#http"},
|
||||
{"type": 301, "source": "/api/http", "destination": "/guide/deprecation#http"},
|
||||
// `@angular/http` package was removed, and new `HttpClient` APIs are available under `@angular/common/http` package
|
||||
{"type": 301, "source": "/api/http/:rest*", "destination": "/guide/deprecations#http"},
|
||||
{"type": 301, "source": "/api/http", "destination": "/guide/deprecations#http"},
|
||||
|
||||
// Animations moves, renames and removals
|
||||
{"type": 301, "source": "/api/animate/:rest*", "destination": "/api/animations/:rest*"},
|
||||
|
@ -76,28 +76,28 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^8.0.0-beta.14",
|
||||
"@angular/cdk": "8.0.0-beta.2",
|
||||
"@angular/common": "^8.0.0-beta.14",
|
||||
"@angular/core": "^8.0.0-beta.14",
|
||||
"@angular/elements": "^8.0.0-beta.14",
|
||||
"@angular/forms": "^8.0.0-beta.14",
|
||||
"@angular/material": "8.0.0-beta.2",
|
||||
"@angular/platform-browser": "^8.0.0-beta.14",
|
||||
"@angular/platform-browser-dynamic": "^8.0.0-beta.14",
|
||||
"@angular/router": "^8.0.0-beta.14",
|
||||
"@angular/service-worker": "^8.0.0-beta.14",
|
||||
"@angular/animations": "^8.0.0-rc.2",
|
||||
"@angular/cdk": "8.0.0-rc.0",
|
||||
"@angular/common": "^8.0.0-rc.2",
|
||||
"@angular/core": "^8.0.0-rc.2",
|
||||
"@angular/elements": "^8.0.0-rc.2",
|
||||
"@angular/forms": "^8.0.0-rc.2",
|
||||
"@angular/material": "8.0.0-rc.0",
|
||||
"@angular/platform-browser": "^8.0.0-rc.2",
|
||||
"@angular/platform-browser-dynamic": "^8.0.0-rc.2",
|
||||
"@angular/router": "^8.0.0-rc.2",
|
||||
"@angular/service-worker": "^8.0.0-rc.2",
|
||||
"@types/lunr": "^2.3.2",
|
||||
"@webcomponents/custom-elements": "^1.2.0",
|
||||
"rxjs": "^6.5.1",
|
||||
"zone.js": "^0.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "0.800.0-beta.18",
|
||||
"@angular/cli": "8.0.0-beta.18",
|
||||
"@angular/compiler": "^8.0.0-beta.14",
|
||||
"@angular/compiler-cli": "^8.0.0-beta.14",
|
||||
"@angular/language-service": "^8.0.0-beta.14",
|
||||
"@angular-devkit/build-angular": "0.800.0-rc.2",
|
||||
"@angular/cli": "8.0.0-rc.2",
|
||||
"@angular/compiler": "^8.0.0-rc.2",
|
||||
"@angular/compiler-cli": "^8.0.0-rc.2",
|
||||
"@angular/language-service": "^8.0.0-rc.2",
|
||||
"@types/jasmine": "^2.5.52",
|
||||
"@types/jasminewd2": "^2.0.4",
|
||||
"@types/node": "~6.0.60",
|
||||
|
@ -4,10 +4,10 @@
|
||||
"uncompressed": {
|
||||
"runtime-es5": 2980,
|
||||
"runtime-es2015": 2986,
|
||||
"main-es5": 501356,
|
||||
"main-es2015": 440336,
|
||||
"main-es5": 504760,
|
||||
"main-es2015": 443497,
|
||||
"polyfills-es5": 128751,
|
||||
"polyfills-es2015": 59557
|
||||
"polyfills-es2015": 53147
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ function _main() {
|
||||
const oldTsConfigStr = readFileSync(tsConfigPath, 'utf8');
|
||||
const oldTsConfigObj = parse(oldTsConfigStr);
|
||||
const newTsConfigObj = extend(true, oldTsConfigObj, NG_COMPILER_OPTS);
|
||||
const newTsConfigStr = JSON.stringify(newTsConfigObj, null, 2);
|
||||
const newTsConfigStr = `${JSON.stringify(newTsConfigObj, null, 2)}\n`;
|
||||
console.log(`\nNew config: ${newTsConfigStr}`);
|
||||
writeFileSync(tsConfigPath, newTsConfigStr);
|
||||
|
||||
|
@ -6,11 +6,8 @@ set +x -eu -o pipefail
|
||||
readonly aioDir="$(realpath $thisDir/..)"
|
||||
|
||||
readonly protractorConf="$aioDir/tests/deployment/e2e/protractor.conf.js"
|
||||
readonly minPwaScore="$1"
|
||||
readonly urls=(
|
||||
"https://angular.io/"
|
||||
"https://next.angular.io/"
|
||||
)
|
||||
readonly targetUrl="$1"
|
||||
readonly minPwaScore="$2"
|
||||
|
||||
cd "$aioDir"
|
||||
|
||||
@ -19,16 +16,14 @@ set +x -eu -o pipefail
|
||||
yarn install --frozen-lockfile --non-interactive
|
||||
yarn update-webdriver
|
||||
|
||||
# Run checks for all URLs.
|
||||
for url in "${urls[@]}"; do
|
||||
echo -e "\nChecking '$url'...\n-----"
|
||||
# Run checks for target URL.
|
||||
echo -e "\nChecking '$targetUrl'...\n-----"
|
||||
|
||||
# Run basic e2e and deployment config tests.
|
||||
yarn protractor "$protractorConf" --baseUrl "$url"
|
||||
# Run basic e2e and deployment config tests.
|
||||
yarn protractor "$protractorConf" --baseUrl "$targetUrl"
|
||||
|
||||
# Run PWA-score tests.
|
||||
yarn test-pwa-score "$url" "$minPwaScore"
|
||||
done
|
||||
# Run PWA-score tests.
|
||||
yarn test-pwa-score "$targetUrl" "$minPwaScore"
|
||||
|
||||
echo -e "\nAll checks passed!"
|
||||
)
|
||||
|
@ -23,10 +23,10 @@ describe('CodeExampleComponent', () => {
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(HostComponent);
|
||||
fixture.detectChanges();
|
||||
|
||||
hostComponent = fixture.componentInstance;
|
||||
codeExampleComponent = hostComponent.codeExampleComponent;
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should be able to capture the code snippet provided in content', () => {
|
||||
|
@ -23,10 +23,10 @@ describe('CodeTabsComponent', () => {
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(HostComponent);
|
||||
fixture.detectChanges();
|
||||
|
||||
hostComponent = fixture.componentInstance;
|
||||
codeTabsComponent = hostComponent.codeTabsComponent;
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should get correct tab info', () => {
|
||||
|
@ -63,178 +63,182 @@ describe('TocComponent', () => {
|
||||
expect(tocComponent.type).toEqual('None');
|
||||
});
|
||||
|
||||
it('should not display anything when no h2 or h3 TocItems', () => {
|
||||
tocService.tocList.next([tocItem('H1', 'h1')]);
|
||||
fixture.detectChanges();
|
||||
expect(tocComponentDe.children.length).toEqual(0);
|
||||
});
|
||||
describe('(once the lifecycle hooks have run)', () => {
|
||||
beforeEach(() => fixture.detectChanges());
|
||||
|
||||
it('should update when the TocItems are updated', () => {
|
||||
tocService.tocList.next([tocItem('Heading A')]);
|
||||
fixture.detectChanges();
|
||||
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(1);
|
||||
|
||||
tocService.tocList.next([tocItem('Heading A'), tocItem('Heading B'), tocItem('Heading C')]);
|
||||
fixture.detectChanges();
|
||||
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(3);
|
||||
});
|
||||
|
||||
it('should only display H2 and H3 TocItems', () => {
|
||||
tocService.tocList.next([tocItem('Heading A', 'h1'), tocItem('Heading B'), tocItem('Heading C', 'h3')]);
|
||||
fixture.detectChanges();
|
||||
|
||||
const tocItems = tocComponentDe.queryAll(By.css('li'));
|
||||
const textContents = tocItems.map(item => item.nativeNode.textContent.trim());
|
||||
|
||||
expect(tocItems.length).toBe(2);
|
||||
expect(textContents.find(text => text === 'Heading A')).toBeFalsy();
|
||||
expect(textContents.find(text => text === 'Heading B')).toBeTruthy();
|
||||
expect(textContents.find(text => text === 'Heading C')).toBeTruthy();
|
||||
expect(setPage().tocH1Heading).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should stop listening for TocItems once destroyed', () => {
|
||||
tocService.tocList.next([tocItem('Heading A')]);
|
||||
fixture.detectChanges();
|
||||
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(1);
|
||||
|
||||
tocComponent.ngOnDestroy();
|
||||
tocService.tocList.next([tocItem('Heading A', 'h1'), tocItem('Heading B'), tocItem('Heading C')]);
|
||||
fixture.detectChanges();
|
||||
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(1);
|
||||
});
|
||||
|
||||
describe('when fewer than `maxPrimary` TocItems', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
tocService.tocList.next([tocItem('Heading A'), tocItem('Heading B'), tocItem('Heading C'), tocItem('Heading D')]);
|
||||
it('should not display anything when no h2 or h3 TocItems', () => {
|
||||
tocService.tocList.next([tocItem('H1', 'h1')]);
|
||||
fixture.detectChanges();
|
||||
page = setPage();
|
||||
expect(tocComponentDe.children.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should have four displayed items', () => {
|
||||
expect(page.listItems.length).toEqual(4);
|
||||
});
|
||||
|
||||
it('should not have secondary items', () => {
|
||||
expect(tocComponent.type).toEqual('EmbeddedSimple');
|
||||
const aSecond = page.listItems.find(item => item.classes.secondary);
|
||||
expect(aSecond).toBeFalsy('should not find a secondary');
|
||||
});
|
||||
|
||||
it('should not display expando buttons', () => {
|
||||
expect(page.tocHeadingButtonEmbedded).toBeFalsy('top expand/collapse button');
|
||||
expect(page.tocMoreButton).toBeFalsy('bottom more button');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when many TocItems', () => {
|
||||
let scrollToTopSpy: jasmine.Spy;
|
||||
|
||||
beforeEach(() => {
|
||||
it('should update when the TocItems are updated', () => {
|
||||
tocService.tocList.next([tocItem('Heading A')]);
|
||||
fixture.detectChanges();
|
||||
page = setPage();
|
||||
scrollToTopSpy = TestBed.get(ScrollService).scrollToTop;
|
||||
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(1);
|
||||
|
||||
tocService.tocList.next([tocItem('Heading A'), tocItem('Heading B'), tocItem('Heading C')]);
|
||||
fixture.detectChanges();
|
||||
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(3);
|
||||
});
|
||||
|
||||
it('should have more than 4 displayed items', () => {
|
||||
expect(page.listItems.length).toBeGreaterThan(4);
|
||||
it('should only display H2 and H3 TocItems', () => {
|
||||
tocService.tocList.next([tocItem('Heading A', 'h1'), tocItem('Heading B'), tocItem('Heading C', 'h3')]);
|
||||
fixture.detectChanges();
|
||||
|
||||
const tocItems = tocComponentDe.queryAll(By.css('li'));
|
||||
const textContents = tocItems.map(item => item.nativeNode.textContent.trim());
|
||||
|
||||
expect(tocItems.length).toBe(2);
|
||||
expect(textContents.find(text => text === 'Heading A')).toBeFalsy();
|
||||
expect(textContents.find(text => text === 'Heading B')).toBeTruthy();
|
||||
expect(textContents.find(text => text === 'Heading C')).toBeTruthy();
|
||||
expect(setPage().tocH1Heading).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should not display the h1 item', () => {
|
||||
expect(page.listItems.find(item => item.classes.h1)).toBeFalsy('should not find h1 item');
|
||||
it('should stop listening for TocItems once destroyed', () => {
|
||||
tocService.tocList.next([tocItem('Heading A')]);
|
||||
fixture.detectChanges();
|
||||
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(1);
|
||||
|
||||
tocComponent.ngOnDestroy();
|
||||
tocService.tocList.next([tocItem('Heading A', 'h1'), tocItem('Heading B'), tocItem('Heading C')]);
|
||||
fixture.detectChanges();
|
||||
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(1);
|
||||
});
|
||||
|
||||
it('should be in "collapsed" (not expanded) state at the start', () => {
|
||||
expect(tocComponent.isCollapsed).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should have "collapsed" class at the start', () => {
|
||||
expect(tocComponentDe.children[0].classes.collapsed).toEqual(true);
|
||||
});
|
||||
|
||||
it('should display expando buttons', () => {
|
||||
expect(page.tocHeadingButtonEmbedded).toBeTruthy('top expand/collapse button');
|
||||
expect(page.tocMoreButton).toBeTruthy('bottom more button');
|
||||
});
|
||||
|
||||
it('should have secondary items', () => {
|
||||
expect(tocComponent.type).toEqual('EmbeddedExpandable');
|
||||
});
|
||||
|
||||
// CSS will hide items with the secondary class when collapsed
|
||||
it('should have secondary item with a secondary class', () => {
|
||||
const aSecondary = page.listItems.find(item => item.classes.secondary);
|
||||
expect(aSecondary).toBeTruthy('should find a secondary');
|
||||
});
|
||||
|
||||
describe('after click tocHeading button', () => {
|
||||
describe('when fewer than `maxPrimary` TocItems', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
page.tocHeadingButtonEmbedded.nativeElement.click();
|
||||
tocService.tocList.next([tocItem('Heading A'), tocItem('Heading B'), tocItem('Heading C'), tocItem('Heading D')]);
|
||||
fixture.detectChanges();
|
||||
page = setPage();
|
||||
});
|
||||
|
||||
it('should not be "collapsed"', () => {
|
||||
expect(tocComponent.isCollapsed).toEqual(false);
|
||||
it('should have four displayed items', () => {
|
||||
expect(page.listItems.length).toEqual(4);
|
||||
});
|
||||
|
||||
it('should not have "collapsed" class', () => {
|
||||
expect(tocComponentDe.children[0].classes.collapsed).toBeFalsy();
|
||||
it('should not have secondary items', () => {
|
||||
expect(tocComponent.type).toEqual('EmbeddedSimple');
|
||||
const aSecond = page.listItems.find(item => item.classes.secondary);
|
||||
expect(aSecond).toBeFalsy('should not find a secondary');
|
||||
});
|
||||
|
||||
it('should not scroll', () => {
|
||||
expect(scrollToTopSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should be "collapsed" after clicking again', () => {
|
||||
page.tocHeadingButtonEmbedded.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
expect(tocComponent.isCollapsed).toEqual(true);
|
||||
});
|
||||
|
||||
it('should not scroll after clicking again', () => {
|
||||
page.tocHeadingButtonEmbedded.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
expect(scrollToTopSpy).not.toHaveBeenCalled();
|
||||
it('should not display expando buttons', () => {
|
||||
expect(page.tocHeadingButtonEmbedded).toBeFalsy('top expand/collapse button');
|
||||
expect(page.tocMoreButton).toBeFalsy('bottom more button');
|
||||
});
|
||||
});
|
||||
|
||||
describe('after click tocMore button', () => {
|
||||
describe('when many TocItems', () => {
|
||||
let scrollToTopSpy: jasmine.Spy;
|
||||
|
||||
beforeEach(() => {
|
||||
page.tocMoreButton.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
page = setPage();
|
||||
scrollToTopSpy = TestBed.get(ScrollService).scrollToTop;
|
||||
});
|
||||
|
||||
it('should not be "collapsed"', () => {
|
||||
expect(tocComponent.isCollapsed).toEqual(false);
|
||||
it('should have more than 4 displayed items', () => {
|
||||
expect(page.listItems.length).toBeGreaterThan(4);
|
||||
});
|
||||
|
||||
it('should not have "collapsed" class', () => {
|
||||
expect(tocComponentDe.children[0].classes.collapsed).toBeFalsy();
|
||||
it('should not display the h1 item', () => {
|
||||
expect(page.listItems.find(item => item.classes.h1)).toBeFalsy('should not find h1 item');
|
||||
});
|
||||
|
||||
it('should not scroll', () => {
|
||||
expect(scrollToTopSpy).not.toHaveBeenCalled();
|
||||
it('should be in "collapsed" (not expanded) state at the start', () => {
|
||||
expect(tocComponent.isCollapsed).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should be "collapsed" after clicking again', () => {
|
||||
page.tocMoreButton.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
expect(tocComponent.isCollapsed).toEqual(true);
|
||||
it('should have "collapsed" class at the start', () => {
|
||||
expect(tocComponentDe.children[0].classes.collapsed).toEqual(true);
|
||||
});
|
||||
|
||||
it('should be "collapsed" after clicking tocHeadingButton', () => {
|
||||
page.tocMoreButton.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
expect(tocComponent.isCollapsed).toEqual(true);
|
||||
it('should display expando buttons', () => {
|
||||
expect(page.tocHeadingButtonEmbedded).toBeTruthy('top expand/collapse button');
|
||||
expect(page.tocMoreButton).toBeTruthy('bottom more button');
|
||||
});
|
||||
|
||||
it('should scroll after clicking again', () => {
|
||||
page.tocMoreButton.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
expect(scrollToTopSpy).toHaveBeenCalled();
|
||||
it('should have secondary items', () => {
|
||||
expect(tocComponent.type).toEqual('EmbeddedExpandable');
|
||||
});
|
||||
|
||||
// CSS will hide items with the secondary class when collapsed
|
||||
it('should have secondary item with a secondary class', () => {
|
||||
const aSecondary = page.listItems.find(item => item.classes.secondary);
|
||||
expect(aSecondary).toBeTruthy('should find a secondary');
|
||||
});
|
||||
|
||||
describe('after click tocHeading button', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
page.tocHeadingButtonEmbedded.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should not be "collapsed"', () => {
|
||||
expect(tocComponent.isCollapsed).toEqual(false);
|
||||
});
|
||||
|
||||
it('should not have "collapsed" class', () => {
|
||||
expect(tocComponentDe.children[0].classes.collapsed).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should not scroll', () => {
|
||||
expect(scrollToTopSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should be "collapsed" after clicking again', () => {
|
||||
page.tocHeadingButtonEmbedded.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
expect(tocComponent.isCollapsed).toEqual(true);
|
||||
});
|
||||
|
||||
it('should not scroll after clicking again', () => {
|
||||
page.tocHeadingButtonEmbedded.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
expect(scrollToTopSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('after click tocMore button', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
page.tocMoreButton.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should not be "collapsed"', () => {
|
||||
expect(tocComponent.isCollapsed).toEqual(false);
|
||||
});
|
||||
|
||||
it('should not have "collapsed" class', () => {
|
||||
expect(tocComponentDe.children[0].classes.collapsed).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should not scroll', () => {
|
||||
expect(scrollToTopSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should be "collapsed" after clicking again', () => {
|
||||
page.tocMoreButton.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
expect(tocComponent.isCollapsed).toEqual(true);
|
||||
});
|
||||
|
||||
it('should be "collapsed" after clicking tocHeadingButton', () => {
|
||||
page.tocMoreButton.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
expect(tocComponent.isCollapsed).toEqual(true);
|
||||
});
|
||||
|
||||
it('should scroll after clicking again', () => {
|
||||
page.tocMoreButton.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
expect(scrollToTopSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -38,7 +38,7 @@ describe('SearchBoxComponent', () => {
|
||||
it('should get the current search query from the location service',
|
||||
fakeAsync(inject([LocationService], (location: MockLocationService) => {
|
||||
location.search.and.returnValue({ search: 'initial search' });
|
||||
component.ngOnInit();
|
||||
component.ngAfterViewInit();
|
||||
expect(location.search).toHaveBeenCalled();
|
||||
tick(300);
|
||||
expect(host.searchHandler).toHaveBeenCalledWith('initial search');
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, OnInit, ViewChild, ElementRef, EventEmitter, Output } from '@angular/core';
|
||||
import { AfterViewInit, Component, ViewChild, ElementRef, EventEmitter, Output } from '@angular/core';
|
||||
import { LocationService } from 'app/shared/location.service';
|
||||
import { Subject } from 'rxjs';
|
||||
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
|
||||
@ -24,7 +24,7 @@ import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
|
||||
(focus)="doFocus()"
|
||||
(click)="doSearch()">`
|
||||
})
|
||||
export class SearchBoxComponent implements OnInit {
|
||||
export class SearchBoxComponent implements AfterViewInit {
|
||||
|
||||
private searchDebounce = 300;
|
||||
private searchSubject = new Subject<string>();
|
||||
@ -40,7 +40,7 @@ export class SearchBoxComponent implements OnInit {
|
||||
/**
|
||||
* When we first show this search box we trigger a search if there is a search query in the URL
|
||||
*/
|
||||
ngOnInit() {
|
||||
ngAfterViewInit() {
|
||||
const query = this.locationService.search()['search'];
|
||||
if (query) {
|
||||
this.query = query;
|
||||
|
@ -22,11 +22,11 @@
|
||||
/api/core/testing/index/TestBed-class.html /api/core/testing/TestBed
|
||||
/api/core/testing/inject-function /api/core/testing/inject
|
||||
/api/core/testing/inject-function.html /api/core/testing/inject
|
||||
/api/http/Headers-class /guide/deprecation#http
|
||||
/api/http/Headers-class.html /guide/deprecation#http
|
||||
/api/http/HTTP_PROVIDERS-let /guide/deprecation#http
|
||||
/api/http/testing/index/MockBackend-class /guide/deprecation#http
|
||||
/api/http/testing/index/MockBackend-class.html /guide/deprecation#http
|
||||
/api/http/Headers-class /guide/deprecations#http
|
||||
/api/http/Headers-class.html /guide/deprecations#http
|
||||
/api/http/HTTP_PROVIDERS-let /guide/deprecations#http
|
||||
/api/http/testing/index/MockBackend-class /guide/deprecations#http
|
||||
/api/http/testing/index/MockBackend-class.html /guide/deprecations#http
|
||||
/api/platform-browser-dynamic/testing/index/platformBrowserDynamicTesting-let.html /api/platform-browser-dynamic/testing/platformBrowserDynamicTesting
|
||||
/api/platform-browser/AnimationDriver /api/animations/browser/AnimationDriver
|
||||
/api/router/Route-class /api/router/Route
|
||||
@ -95,15 +95,15 @@
|
||||
/docs/js/latest/api/forms/index/FormBuilder-class.html /api/forms/FormBuilder
|
||||
/docs/js/latest/api/forms/index/NG_VALIDATORS-let /api/forms/NG_VALIDATORS
|
||||
/docs/js/latest/api/forms/index/Validator-interface.html /api/forms/Validator
|
||||
/docs/js/latest/api/http/ConnectionBackend-class /guide/deprecation#http
|
||||
/docs/js/latest/api/http/index/Http-class.html /guide/deprecation#http
|
||||
/docs/js/latest/api/http/index/Jsonp-class.html /guide/deprecation#http
|
||||
/docs/js/latest/api/http/index/ResponseOptions-class.html /guide/deprecation#http
|
||||
/docs/js/latest/api/http/index/URLSearchParams-class /guide/deprecation#http
|
||||
/docs/js/latest/api/http/index/XHRConnection-class /guide/deprecation#http
|
||||
/docs/js/latest/api/http/index/XHRConnection-class.html /guide/deprecation#http
|
||||
/docs/js/latest/api/http/testing/index/MockConnection-class.html /guide/deprecation#http
|
||||
/docs/js/latest/api/http/testing/MockBackend-class /guide/deprecation#http
|
||||
/docs/js/latest/api/http/ConnectionBackend-class /guide/deprecations#http
|
||||
/docs/js/latest/api/http/index/Http-class.html /guide/deprecations#http
|
||||
/docs/js/latest/api/http/index/Jsonp-class.html /guide/deprecations#http
|
||||
/docs/js/latest/api/http/index/ResponseOptions-class.html /guide/deprecations#http
|
||||
/docs/js/latest/api/http/index/URLSearchParams-class /guide/deprecations#http
|
||||
/docs/js/latest/api/http/index/XHRConnection-class /guide/deprecations#http
|
||||
/docs/js/latest/api/http/index/XHRConnection-class.html /guide/deprecations#http
|
||||
/docs/js/latest/api/http/testing/index/MockConnection-class.html /guide/deprecations#http
|
||||
/docs/js/latest/api/http/testing/MockBackend-class /guide/deprecations#http
|
||||
/docs/js/latest/api/platform-browser-dynamic/index/platformBrowserDynamic-let.html /api/platform-browser-dynamic/platformBrowserDynamic
|
||||
/docs/js/latest/api/platform-browser-dynamic/testing/index/BrowserDynamicTestingModule-class.html /api/platform-browser-dynamic/testing/BrowserDynamicTestingModule
|
||||
/docs/js/latest/api/platform-browser/animations/index/BrowserAnimationsModule-class /api/platform-browser/animations/BrowserAnimationsModule
|
||||
@ -165,9 +165,9 @@
|
||||
/docs/ts/latest/api/core/testing/index/fakeAsync-function.html /api/core/testing/fakeAsync
|
||||
/docs/ts/latest/api/core/testing/index/TestComponentRenderer-class.html /api/core/testing/TestComponentRenderer
|
||||
/docs/ts/latest/api/core/testing/index/tick-function.html /api/core/testing/tick
|
||||
/docs/ts/latest/api/http/Connection-class.html /guide/deprecation#http
|
||||
/docs/ts/latest/api/http/testing/index/MockBackend-class.html /guide/deprecation#http
|
||||
/docs/ts/latest/api/http/testing/index/MockConnection-class.html /guide/deprecation#http
|
||||
/docs/ts/latest/api/http/Connection-class.html /guide/deprecations#http
|
||||
/docs/ts/latest/api/http/testing/index/MockBackend-class.html /guide/deprecations#http
|
||||
/docs/ts/latest/api/http/testing/index/MockConnection-class.html /guide/deprecations#http
|
||||
/docs/ts/latest/api/platform-browser-dynamic/index/workerAppDynamicPlatform-let.html /api/platform-browser-dynamic/workerAppDynamicPlatform
|
||||
/docs/ts/latest/api/testing/fakeAsync-function.html /api/core/testing/fakeAsync
|
||||
/docs/ts/latest/cookbook/ts-to-js.html https://v2.angular.io/docs/ts/latest/cookbook/ts-to-js.html
|
||||
|
@ -239,7 +239,9 @@ describe('site App', function() {
|
||||
/* tslint:disable:max-line-length */
|
||||
expect(page.ghLinks.get(0).getAttribute('href'))
|
||||
.toMatch(/https:\/\/github\.com\/angular\/angular\/edit\/master\/aio\/content\/guide\/http\.md\?message=docs%3A%20describe%20your%20change\.\.\./);
|
||||
});
|
||||
// TODO(gkalpak): This test often times out with Ivy (because loading `guide/http` takes a lot of time).
|
||||
// Remove the timeout once the performance issues have been fixed.
|
||||
}, 60000);
|
||||
|
||||
it('should not be present on top level pages', () => {
|
||||
page.navigateTo('features');
|
||||
|
@ -73,7 +73,6 @@
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unnecessary-initializer": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
|
@ -48,7 +48,6 @@
|
||||
"no-unused-expression": true,
|
||||
"no-unused-variable": true,
|
||||
"no-unreachable": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
|
@ -41,7 +41,6 @@
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
|
329
aio/yarn.lock
329
aio/yarn.lock
@ -2,24 +2,24 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@angular-devkit/architect@0.800.0-beta.18":
|
||||
version "0.800.0-beta.18"
|
||||
resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.800.0-beta.18.tgz#fdf23d3854d4ca62b2e201efd2b267f800eba8d8"
|
||||
integrity sha512-No7RpK98O+S1zSC0omO66yBKqUnM2Vt1l4tXDC43BGSMijL5JN/uSHpMSObUpmmMC1qxCeN5OXRU7QhZW+DxqA==
|
||||
"@angular-devkit/architect@0.800.0-rc.2":
|
||||
version "0.800.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.800.0-rc.2.tgz#4096016fa6df93acbf02be648554631939aa87c0"
|
||||
integrity sha512-JU/x3UvUW+uVuF0tNkVTRtAvGfbKDXLFI3lm7i40qmts5z1zeQlPjrz+DRTe7msevoVu7DMQTJ7vlbyHUjZOFw==
|
||||
dependencies:
|
||||
"@angular-devkit/core" "8.0.0-beta.18"
|
||||
"@angular-devkit/core" "8.0.0-rc.2"
|
||||
rxjs "6.4.0"
|
||||
|
||||
"@angular-devkit/build-angular@0.800.0-beta.18":
|
||||
version "0.800.0-beta.18"
|
||||
resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.800.0-beta.18.tgz#3ce37929cb9462fc43f532b1186c8a0e3005fcb1"
|
||||
integrity sha512-bEzgBI8kWpdapKU0xMONHYtzfCDMZVwfwetTK9nRCk2c4CEa0k6I9r6UTgPpqGU1pf2wHgrSd+QdpwbOORNufw==
|
||||
"@angular-devkit/build-angular@0.800.0-rc.2":
|
||||
version "0.800.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.800.0-rc.2.tgz#df78a27a58813bc442629f8500e1f3d4fd72c519"
|
||||
integrity sha512-E6P3CO4IUEyCezrBuNwMZ+H/Rg+0R/FH3/TyWiivY5D3bLGvRFJbQE5ZQkVWbd1i1woxvHdqkjgco9hpOko2XQ==
|
||||
dependencies:
|
||||
"@angular-devkit/architect" "0.800.0-beta.18"
|
||||
"@angular-devkit/build-optimizer" "0.800.0-beta.18"
|
||||
"@angular-devkit/build-webpack" "0.800.0-beta.18"
|
||||
"@angular-devkit/core" "8.0.0-beta.18"
|
||||
"@ngtools/webpack" "8.0.0-beta.18"
|
||||
"@angular-devkit/architect" "0.800.0-rc.2"
|
||||
"@angular-devkit/build-optimizer" "0.800.0-rc.2"
|
||||
"@angular-devkit/build-webpack" "0.800.0-rc.2"
|
||||
"@angular-devkit/core" "8.0.0-rc.2"
|
||||
"@ngtools/webpack" "8.0.0-rc.2"
|
||||
ajv "6.10.0"
|
||||
autoprefixer "9.5.1"
|
||||
browserslist "4.5.5"
|
||||
@ -38,7 +38,7 @@
|
||||
loader-utils "1.2.3"
|
||||
mini-css-extract-plugin "0.6.0"
|
||||
minimatch "3.0.4"
|
||||
open "6.1.0"
|
||||
open "6.2.0"
|
||||
parse5 "4.0.0"
|
||||
postcss "7.0.14"
|
||||
postcss-import "12.0.1"
|
||||
@ -65,30 +65,30 @@
|
||||
webpack-subresource-integrity "1.1.0-rc.6"
|
||||
worker-plugin "3.1.0"
|
||||
|
||||
"@angular-devkit/build-optimizer@0.800.0-beta.18":
|
||||
version "0.800.0-beta.18"
|
||||
resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.800.0-beta.18.tgz#4e8e8ae1c2e14146633217605315b51e3f9eeee6"
|
||||
integrity sha512-x5oh7GUjYLvrOvh4uNM6aDtNFv7hafo9ru11ee7sgXwHIYdcVmp6ew19Sjj3nAr0Sh1rAUf7QoNZVO/txxnBRA==
|
||||
"@angular-devkit/build-optimizer@0.800.0-rc.2":
|
||||
version "0.800.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.800.0-rc.2.tgz#d56cdc127699ad25eb817caf97336d239600f5cb"
|
||||
integrity sha512-YKTFlAfD4JZk1h4lZDA4HVPPIq1JB5Dxg/Icn2GvcuUws6wVcXUflMTIpBgIMF2j07fMIYPqSAcSBd+UsBJBvA==
|
||||
dependencies:
|
||||
loader-utils "1.2.3"
|
||||
source-map "0.5.6"
|
||||
typescript "3.4.4"
|
||||
webpack-sources "1.3.0"
|
||||
|
||||
"@angular-devkit/build-webpack@0.800.0-beta.18":
|
||||
version "0.800.0-beta.18"
|
||||
resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.800.0-beta.18.tgz#f343d759bdd09a907c77fc6a0515416c30291e88"
|
||||
integrity sha512-pSPyW1D7yEZXxCRb42qXmwEO8vHLeDgbRUXiTtMh0Yf86Zb5Ku7xH+pK7suOhJXEZKv2UWBfQXWWP9SrBX/4rg==
|
||||
"@angular-devkit/build-webpack@0.800.0-rc.2":
|
||||
version "0.800.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.800.0-rc.2.tgz#c08218f54381157744a3166c0d94b1db180ba063"
|
||||
integrity sha512-t+/5WqgcsvgPIFGE48I+UWJPDpkQ6E+dKH6RuXec94VBJEv1pC9FJdoi6s/CqEzzPiZsWxJzrWI4dpPAn1eWuA==
|
||||
dependencies:
|
||||
"@angular-devkit/architect" "0.800.0-beta.18"
|
||||
"@angular-devkit/core" "8.0.0-beta.18"
|
||||
"@angular-devkit/architect" "0.800.0-rc.2"
|
||||
"@angular-devkit/core" "8.0.0-rc.2"
|
||||
rxjs "6.4.0"
|
||||
webpack-merge "4.2.1"
|
||||
|
||||
"@angular-devkit/core@8.0.0-beta.18":
|
||||
version "8.0.0-beta.18"
|
||||
resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-8.0.0-beta.18.tgz#dfaa0786af0a7466467b8a9cd1fe745418690df0"
|
||||
integrity sha512-+kQd0m6HgGTn7JM9GWzrJgjI/PPOa0K+t+a6YZS4n/MdZSzhId556Df5/UnrgsBghSDjyVwu7+owijvNwQlj2w==
|
||||
"@angular-devkit/core@8.0.0-rc.2":
|
||||
version "8.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-8.0.0-rc.2.tgz#e596a44da215713cdef5405f1477e70626e5d68c"
|
||||
integrity sha512-hfkQ1QaA0ZIquTNQYJiK0OhdSzdxWY1SJr20JwSBHezAvhN4sJHRBRN9RxGLWdL1d4Z4rUB4KEIvx0cMMk6Ueg==
|
||||
dependencies:
|
||||
ajv "6.10.0"
|
||||
fast-json-stable-stringify "2.0.0"
|
||||
@ -96,63 +96,63 @@
|
||||
rxjs "6.4.0"
|
||||
source-map "0.7.3"
|
||||
|
||||
"@angular-devkit/schematics@8.0.0-beta.18":
|
||||
version "8.0.0-beta.18"
|
||||
resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-8.0.0-beta.18.tgz#97dece6eaddd331516a94da985f33add21b76f5c"
|
||||
integrity sha512-F2pkiNe/rMOdcnKm/4s/lvM/8guwtrj5nEk0klyesDZLaZt94XEtasq0XrBxHju+7PmM6IwaDA6o5qsQ/6IAKg==
|
||||
"@angular-devkit/schematics@8.0.0-rc.2":
|
||||
version "8.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-8.0.0-rc.2.tgz#f4490b1277cdba9622227b178128c76f54e7eca1"
|
||||
integrity sha512-VuXCRE/PmQWMHaaBbbOq7f2M6/DeKnYUyqG2xpBJaSP+rX7j08gd6RGzkn6V81C6jxt0Q3WkXnQfj5ZQuFnF5w==
|
||||
dependencies:
|
||||
"@angular-devkit/core" "8.0.0-beta.18"
|
||||
"@angular-devkit/core" "8.0.0-rc.2"
|
||||
rxjs "6.4.0"
|
||||
|
||||
"@angular/animations@^8.0.0-beta.14":
|
||||
version "8.0.0-beta.14"
|
||||
resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-8.0.0-beta.14.tgz#50259f6f3c97101183216e8311b8c0875c4356c3"
|
||||
integrity sha512-ihYHQXEbjzemjJxJV4p2XAWOD9H4r8HpfNekxxelgj2RyZhrMQStzL+PEKxHHlGn167HuZz5YEoW4MXGflTtsA==
|
||||
"@angular/animations@^8.0.0-rc.2":
|
||||
version "8.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-8.0.0-rc.2.tgz#aef2683aba35498fe26253bf8f461a1658864e49"
|
||||
integrity sha512-XTT7Eif6Km6MSbLr6qlCmx8vjRgx/Hp5Hv1WnnPtRFt8XeidYGGYIq2si3CxQ2xBjEO3OpNbPqtYvZKH1yuBdA==
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
"@angular/cdk@8.0.0-beta.2":
|
||||
version "8.0.0-beta.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular/cdk/-/cdk-8.0.0-beta.2.tgz#27544be4a99b0d56bdbf9f206b2f8e290de82f61"
|
||||
integrity sha512-/ze014/AGp9nAI6kK7w6TQnz533PRvjJOpEULaBclNRHSNGZElncOGPfnD6V/Zr/CKY5zFbwLHQEqVUP4ObTwg==
|
||||
"@angular/cdk@8.0.0-rc.0":
|
||||
version "8.0.0-rc.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular/cdk/-/cdk-8.0.0-rc.0.tgz#64731574ddcf6912b079e03efab95464ce17acee"
|
||||
integrity sha512-fa0AFR/v4t4rVFUwqpfRnzRhzyoReYcssjR6fQ4WMMxbhRHNZSJaPxvnykMOZsh7oQy0d6Dy4kENO6nXZptR9g==
|
||||
dependencies:
|
||||
tslib "^1.7.1"
|
||||
optionalDependencies:
|
||||
parse5 "^5.0.0"
|
||||
|
||||
"@angular/cli@8.0.0-beta.18":
|
||||
version "8.0.0-beta.18"
|
||||
resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-8.0.0-beta.18.tgz#454a3d230c280fea7ec02c97eae8bd56a9a17dd9"
|
||||
integrity sha512-uNuTCN75w9m2uLq3Vk2e+FfiSa19AHeGOrrwtLdPJLr5GU1Jum2wl9Mn9W4eyiSSiZNKN+IWWa6wkLV0/SybQw==
|
||||
"@angular/cli@8.0.0-rc.2":
|
||||
version "8.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-8.0.0-rc.2.tgz#fda3c42c3682a53168be67c0624db04144c0aa9c"
|
||||
integrity sha512-Aj5JJKa6JxNU3U9InvveIhU8gg6ZA1UvvKHHzX87FsUQhHzm7XIfwC5JrYGDE4c9ErIE40J3we7Hcsv2AjzkTw==
|
||||
dependencies:
|
||||
"@angular-devkit/architect" "0.800.0-beta.18"
|
||||
"@angular-devkit/core" "8.0.0-beta.18"
|
||||
"@angular-devkit/schematics" "8.0.0-beta.18"
|
||||
"@schematics/angular" "8.0.0-beta.18"
|
||||
"@schematics/update" "0.800.0-beta.18"
|
||||
"@angular-devkit/architect" "0.800.0-rc.2"
|
||||
"@angular-devkit/core" "8.0.0-rc.2"
|
||||
"@angular-devkit/schematics" "8.0.0-rc.2"
|
||||
"@schematics/angular" "8.0.0-rc.2"
|
||||
"@schematics/update" "0.800.0-rc.2"
|
||||
"@yarnpkg/lockfile" "1.1.0"
|
||||
debug "^4.1.1"
|
||||
ini "1.3.5"
|
||||
inquirer "6.3.1"
|
||||
npm-package-arg "6.1.0"
|
||||
open "6.1.0"
|
||||
open "6.2.0"
|
||||
pacote "9.5.0"
|
||||
semver "6.0.0"
|
||||
symbol-observable "1.2.0"
|
||||
universal-analytics "^0.4.20"
|
||||
uuid "^3.3.2"
|
||||
|
||||
"@angular/common@^8.0.0-beta.14":
|
||||
version "8.0.0-beta.14"
|
||||
resolved "https://registry.yarnpkg.com/@angular/common/-/common-8.0.0-beta.14.tgz#a27efe0b3e38e38f0e481a2a3f8cad026823b39d"
|
||||
integrity sha512-4mBGXb+VyakX+YqAAfDsYrlKmjDcyD0BjmWi1u7aTJgf5QmEvFD4QLXzHoWEsmBFnTgoFHXMtXogF04GXy3kuA==
|
||||
"@angular/common@^8.0.0-rc.2":
|
||||
version "8.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular/common/-/common-8.0.0-rc.2.tgz#77b2da22cb11bf2039799d56ec2fb7c4f51a1374"
|
||||
integrity sha512-/MUZhebMAkAwV8jkimBONN2eOQ2/5qO54ZvPypyy2tEHk69JRNLFjREaR+VU8yGlS/1MU6jTYxyfRW2c8ggLzA==
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
"@angular/compiler-cli@^8.0.0-beta.14":
|
||||
version "8.0.0-beta.14"
|
||||
resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-8.0.0-beta.14.tgz#61aa5947d3427afd0043fdba079a8cc616d29201"
|
||||
integrity sha512-Q+B9bUDqVOT3OZdUsOFJeQWSmVKUdUoaU5ptq6UQFALCa/0skQrcL/KOFpej3fk3ZRVTkQ+vWQ1nMzv+tm8Byw==
|
||||
"@angular/compiler-cli@^8.0.0-rc.2":
|
||||
version "8.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-8.0.0-rc.2.tgz#a3ef74f3e4ea448ccf1387c18c32fc664b67b2e1"
|
||||
integrity sha512-lLhedaTQ08/i4aysCPpTYbAP0/8T5/EHE79FByp/7XxqRuQxcXkFJujQT1Q/KReKa0gA9JEYD4I1eBJpNYyMLQ==
|
||||
dependencies:
|
||||
canonical-path "1.0.0"
|
||||
chokidar "^2.1.1"
|
||||
@ -164,73 +164,73 @@
|
||||
shelljs "^0.8.1"
|
||||
source-map "^0.6.1"
|
||||
tslib "^1.9.0"
|
||||
yargs "9.0.1"
|
||||
yargs "13.1.0"
|
||||
|
||||
"@angular/compiler@^8.0.0-beta.14":
|
||||
version "8.0.0-beta.14"
|
||||
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-8.0.0-beta.14.tgz#dc01066a060ea9fbd9696a015f481279aa23c2b0"
|
||||
integrity sha512-Copy2bMf8EL9WcHwz1rHeMY6CqWhOZmvGRBSVwI149awbTxc31h3+01TG2I5FlgIm+vc70PUldp7EumqFiCCDA==
|
||||
"@angular/compiler@^8.0.0-rc.2":
|
||||
version "8.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-8.0.0-rc.2.tgz#8395c20d2d7e93c6941a45b039e03ae7a6277797"
|
||||
integrity sha512-/NR0EN6wjit2mfgOhWirOjKp+s7lO1QSKhzK3TjYCda1L7Pijo29s3BGMWUSPCRno8zNH5o7Q0mWCC55MBGB4w==
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
"@angular/core@^8.0.0-beta.14":
|
||||
version "8.0.0-beta.14"
|
||||
resolved "https://registry.yarnpkg.com/@angular/core/-/core-8.0.0-beta.14.tgz#d3e75291ac390a1a29bf037bfd292586a90aea8b"
|
||||
integrity sha512-7gltt13BTUFgGHpOBUmvxr/PUcqY8n6177NpYgEJRBFLZl2FtErG+7BfYBCt23StAi+K6ZafP+IX2m1evOtX8g==
|
||||
"@angular/core@^8.0.0-rc.2":
|
||||
version "8.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular/core/-/core-8.0.0-rc.2.tgz#800fd49bbc176f7ee064375b726503c5e6c8387c"
|
||||
integrity sha512-ImXzoQk8U3IiL75dJWnO/aIGfaExgiqDc6GJYgQ8PvB7ZUkdUOj/a+jd6asMvE52VZJkof5XShhdonTScPcdUA==
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
"@angular/elements@^8.0.0-beta.14":
|
||||
version "8.0.0-beta.14"
|
||||
resolved "https://registry.yarnpkg.com/@angular/elements/-/elements-8.0.0-beta.14.tgz#951a9c79c475a26a86bc83c7e21769863b6611f0"
|
||||
integrity sha512-oY6hv7cN0zOElABrO7lEiz+/xVPF5+97r/RA/x2vIVWyei7J7VIWQxAvHX+osrndIwAgXtBlyx0U0EXfp+BshA==
|
||||
"@angular/elements@^8.0.0-rc.2":
|
||||
version "8.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular/elements/-/elements-8.0.0-rc.2.tgz#84ca2aadff66bfcd3c8042492a0c6b87a6a749fa"
|
||||
integrity sha512-7KVPDSGXo33WD+ZQHjmvSXyBa6az6MHIQo3I+wRKUB9pBZNqMa2Dcb7FQp7fq3tQTEpOW6fO52ozxAZ/ybozxA==
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
"@angular/forms@^8.0.0-beta.14":
|
||||
version "8.0.0-beta.14"
|
||||
resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-8.0.0-beta.14.tgz#db0958d9f1bd8d22aef1605c66704d9247837f31"
|
||||
integrity sha512-40GN2X+ycaUyq1/VX8jQcQqnuDojp2A7OBtfGguTsz2viKlIFY89GvErqPzGcbUwoKE2e00pNDEK2NWwLqLmpg==
|
||||
"@angular/forms@^8.0.0-rc.2":
|
||||
version "8.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-8.0.0-rc.2.tgz#f4db4653470b74cd55508aa83da761309a1d341d"
|
||||
integrity sha512-rjjGNVaxwOayuZCpsG8V13RK/h7S6v5ItzG6Ai1agO/em4/riNhEP3+BvxM4Rs1v4AfGOd+LhOeLt5qptj0JKA==
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
"@angular/language-service@^8.0.0-beta.14":
|
||||
version "8.0.0-beta.14"
|
||||
resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-8.0.0-beta.14.tgz#cf293951d518889cdaedc433306d0699d078a364"
|
||||
integrity sha512-FNPYEDEUlgF7dejL6spCtLs/7+nMq7mAAMvtI1hPDldAhLMkfygrGlxtDrREG+6ekYDBJVpHy7Sik/e9Hn/Szw==
|
||||
"@angular/language-service@^8.0.0-rc.2":
|
||||
version "8.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-8.0.0-rc.2.tgz#5b8fd13b7cd9e7cc1c097f92749f05e72b1c7e47"
|
||||
integrity sha512-PXsntGd053iiM9lJPo7jmjhd5dp6AxugEC4WDTXimZ3vK2Hzv53CnKuVTUGcTWjwazbKAEyG0jiUl4VXptwTAA==
|
||||
|
||||
"@angular/material@8.0.0-beta.2":
|
||||
version "8.0.0-beta.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular/material/-/material-8.0.0-beta.2.tgz#91abce0ef64b655ecec4ff3895ab02c485906071"
|
||||
integrity sha512-3816IV/IVg1juj6jlEbXmWepl97JsLwVO0aHRGpTg8FAdilK5w36eUiXCqKecvDnNAHpwDFavAwrAlToxUQBvw==
|
||||
"@angular/material@8.0.0-rc.0":
|
||||
version "8.0.0-rc.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular/material/-/material-8.0.0-rc.0.tgz#c5170f9617abba3176e991a1e197e1efa0bff95a"
|
||||
integrity sha512-8J+oPHxcoDJnZUE+j5eYDR5FS/zN7RHljK2FtjiG2wsGGRiomnMLQBoFCQL55P1sgqWz3l4vKgi5GuwA65pADQ==
|
||||
dependencies:
|
||||
tslib "^1.7.1"
|
||||
|
||||
"@angular/platform-browser-dynamic@^8.0.0-beta.14":
|
||||
version "8.0.0-beta.14"
|
||||
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-8.0.0-beta.14.tgz#ef2463033f7383500aaa55627fbd487c5c377033"
|
||||
integrity sha512-NWcOey/bzstnbVzNvBpryEAamWNAQobUkP4i3mSnKvWAyhs1GO7IPOsTwzOOPVvQBTOq0GFdYJjDoB4DIo3/ZA==
|
||||
"@angular/platform-browser-dynamic@^8.0.0-rc.2":
|
||||
version "8.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-8.0.0-rc.2.tgz#86e8e227f19aa9c6ef4439623ce6cf7f2b0cd3b1"
|
||||
integrity sha512-c4QXgAikQx25AOnNiQUOe/yNJunR95rfTJ5yApcNU76eeCMG9KLFNGGQTg+PmcxZ6UMcw9zp2Tck9vjSb2BZYg==
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
"@angular/platform-browser@^8.0.0-beta.14":
|
||||
version "8.0.0-beta.14"
|
||||
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-8.0.0-beta.14.tgz#9023453d850243fbc7c6452c26e100fd1d505617"
|
||||
integrity sha512-nOo8wZU1PToNgb1BdKVWVmJqX4l30YWOzMCJ1S41LMImf0k+PXgKYUCQ5OzFBJNTH0x8JvANTvsBiqJyNN+QkQ==
|
||||
"@angular/platform-browser@^8.0.0-rc.2":
|
||||
version "8.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-8.0.0-rc.2.tgz#b40fa05fd32422be499ab3986bc3031374f7c5bc"
|
||||
integrity sha512-ErzIDckIqic9rmqMFk4scRX+lo7AWifOP+IOCot1KGPdQ7+CP/h/neJ9fiIzYTSDYUm5xk5i+2aW+2SWRJYQdA==
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
"@angular/router@^8.0.0-beta.14":
|
||||
version "8.0.0-beta.14"
|
||||
resolved "https://registry.yarnpkg.com/@angular/router/-/router-8.0.0-beta.14.tgz#62e4be7b085cce764e00c608eb910886767cd61e"
|
||||
integrity sha512-QGIvWPd4ngxWzEwzAqEk7M54CGmmYGRxs/+V8Zohau580XL5lK6tuPvN+slO1dWe3+YuFt6U02zzs9mRGlLnYw==
|
||||
"@angular/router@^8.0.0-rc.2":
|
||||
version "8.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular/router/-/router-8.0.0-rc.2.tgz#e0e4636f56fc08760863486f45f203bb9b00543e"
|
||||
integrity sha512-7NnRdEykm0FJf/SHjUWz3cgGDtW5KM2gKm8it8V8azr3vIiMRYyqhDqCKkhutjt7C+yKNotB5M7Da9uYf0n/xQ==
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
"@angular/service-worker@^8.0.0-beta.14":
|
||||
version "8.0.0-beta.14"
|
||||
resolved "https://registry.yarnpkg.com/@angular/service-worker/-/service-worker-8.0.0-beta.14.tgz#7fdac405d2f6757cbaeb2abdb35b513f69e0bdf2"
|
||||
integrity sha512-dQGdpjj97bVp0AvLHI4wpbQCEeWSoPssnKf24oXaJHLM0UuWQgumlBzKU4/gWBpQ+lQoW+txELp4qoY4YH/Yig==
|
||||
"@angular/service-worker@^8.0.0-rc.2":
|
||||
version "8.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular/service-worker/-/service-worker-8.0.0-rc.2.tgz#e73374fe4ccd8c15790f007832a5e60576ed85d9"
|
||||
integrity sha512-uudl7+P9Xov9naoW7Ruv0rvvp+jYWe3P3OOpRul8X6tTYarKnorj3F44Y5GoNO5Xxjp0psPSD558rXrrIBt98w==
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
@ -316,40 +316,32 @@
|
||||
through2 "^2.0.0"
|
||||
xdg-basedir "^3.0.0"
|
||||
|
||||
"@ngtools/webpack@8.0.0-beta.18":
|
||||
version "8.0.0-beta.18"
|
||||
resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-8.0.0-beta.18.tgz#64ebc3823aad7cf80e1afe0e91e06bc281a4448c"
|
||||
integrity sha512-9c7ovJqVq6EpxQx4WYiR1OI6AhG3/RC+dyzvNE3uKEL7WGT6fG/4dKCxr7CA/wYjuogz5Q2Z5n2dLunOTTt5PQ==
|
||||
"@ngtools/webpack@8.0.0-rc.2":
|
||||
version "8.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-8.0.0-rc.2.tgz#d8321a89b2c14fcb627d3d5e326b4125b283f08c"
|
||||
integrity sha512-0pXtkvbwp53z+BgQwBllyIHjMM082phkM8hFwlEHCbYeWkSRBqDld7HgzXBEwpBe+4MKjtWF2xXbDp/4BdTjOQ==
|
||||
dependencies:
|
||||
"@angular-devkit/core" "8.0.0-beta.18"
|
||||
"@angular-devkit/core" "8.0.0-rc.2"
|
||||
enhanced-resolve "4.1.0"
|
||||
rxjs "6.4.0"
|
||||
tree-kill "1.2.1"
|
||||
webpack-sources "1.3.0"
|
||||
|
||||
"@phenomnomnominal/tsquery@3.0.0":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@phenomnomnominal/tsquery/-/tsquery-3.0.0.tgz#6f2f4dbf6304ff52b12cc7a5b979f20c3794a22a"
|
||||
integrity sha512-SW8lKitBHWJ9fAYkJ9kJivuctwNYCh3BUxLdH0+XiR1GPBiu+7qiZzh8p8jqlj1LgVC1TbvfNFroaEsmYlL8Iw==
|
||||
"@schematics/angular@8.0.0-rc.2":
|
||||
version "8.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-8.0.0-rc.2.tgz#94bc9bb68d75e07142a37f4881c287063d460df2"
|
||||
integrity sha512-sBIUz2xEBZJxXAiIsJEaTI7G8r1Mc0aI0tNnw0vQLF6sMSaVKJssN2gYg5dmceDXohJtcgdc3hN1xPL6ZpvsdA==
|
||||
dependencies:
|
||||
esquery "^1.0.1"
|
||||
"@angular-devkit/core" "8.0.0-rc.2"
|
||||
"@angular-devkit/schematics" "8.0.0-rc.2"
|
||||
|
||||
"@schematics/angular@8.0.0-beta.18":
|
||||
version "8.0.0-beta.18"
|
||||
resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-8.0.0-beta.18.tgz#5ad1c76d0279a6b0d286a52b27e4e61b62f348c3"
|
||||
integrity sha512-gmSlDX9ywU3Ce40jl71FpoJDGyYcH3olPnRQGUn8auF7Z/+XVuG2+9EkTrnGwOpuxlmIMLkrlSJjL/1bnJbtpw==
|
||||
"@schematics/update@0.800.0-rc.2":
|
||||
version "0.800.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.800.0-rc.2.tgz#4ea24343c32f47ee7c2f2404fb67a50331dc8b1a"
|
||||
integrity sha512-oWnxEoscVHfzz0mEvfqwe7hRw4fzsYOmnZEVVLAb62lZQdPQHitflBITI+ubrPmHSgILHoBAWqOYlkuEKVXVAg==
|
||||
dependencies:
|
||||
"@angular-devkit/core" "8.0.0-beta.18"
|
||||
"@angular-devkit/schematics" "8.0.0-beta.18"
|
||||
"@phenomnomnominal/tsquery" "3.0.0"
|
||||
|
||||
"@schematics/update@0.800.0-beta.18":
|
||||
version "0.800.0-beta.18"
|
||||
resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.800.0-beta.18.tgz#03becf819814b5498ff94a21330a95d0529c3f83"
|
||||
integrity sha512-U8yUgRapI64ABHbBQ0KIRKMAUd935n2bKcscechoocB9L/64uRgaBqBsNFXsTuepgGmPxPz0ZKq12h4ny1m+nA==
|
||||
dependencies:
|
||||
"@angular-devkit/core" "8.0.0-beta.18"
|
||||
"@angular-devkit/schematics" "8.0.0-beta.18"
|
||||
"@angular-devkit/core" "8.0.0-rc.2"
|
||||
"@angular-devkit/schematics" "8.0.0-rc.2"
|
||||
"@yarnpkg/lockfile" "1.1.0"
|
||||
ini "1.3.5"
|
||||
pacote "9.5.0"
|
||||
@ -3143,6 +3135,11 @@ elliptic@^6.0.0:
|
||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.1.1.tgz#c6cd0ec1b0642e2a3c67a1137efc5e796da4f88e"
|
||||
integrity sha1-xs0OwbBkLio8Z6ETfvxeeW2k+I4=
|
||||
|
||||
emoji-regex@^7.0.1:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
|
||||
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
|
||||
|
||||
emojis-list@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
|
||||
@ -3447,13 +3444,6 @@ esquery@^1.0.0:
|
||||
dependencies:
|
||||
estraverse "^4.0.0"
|
||||
|
||||
esquery@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708"
|
||||
integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==
|
||||
dependencies:
|
||||
estraverse "^4.0.0"
|
||||
|
||||
esrecurse@^4.1.0:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
|
||||
@ -4173,6 +4163,11 @@ get-caller-file@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
|
||||
integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
|
||||
|
||||
get-caller-file@^2.0.1:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
|
||||
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
|
||||
|
||||
get-stream@3.0.0, get-stream@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
|
||||
@ -7340,10 +7335,10 @@ onetime@^2.0.0:
|
||||
dependencies:
|
||||
mimic-fn "^1.0.0"
|
||||
|
||||
open@6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/open/-/open-6.1.0.tgz#0e7e671b883976a4e5251b5d1ca905ab6f4be78f"
|
||||
integrity sha512-Vqch7NFb/WsMujhqfq+B3u0xkssRjZlxh+NSsBSphpcgaFD7gfB0SUBfR91E9ygBlyNGNogXR2cUB8rRfoo2kQ==
|
||||
open@6.2.0:
|
||||
version "6.2.0"
|
||||
resolved "https://registry.yarnpkg.com/open/-/open-6.2.0.tgz#7cf92cb961b5d8498b071e64098bf5e27f57230c"
|
||||
integrity sha512-Vxf6HJkwrqmvh9UAID3MnMYXntbTxKLOSfOnO7LJdzPf3NE3KQYFNV0/Lcz2VAndbRFil58XVCyh8tiX11fiYw==
|
||||
dependencies:
|
||||
is-wsl "^1.1.0"
|
||||
|
||||
@ -7436,7 +7431,7 @@ os-locale@^2.0.0:
|
||||
lcid "^1.0.0"
|
||||
mem "^1.1.0"
|
||||
|
||||
os-locale@^3.0.0:
|
||||
os-locale@^3.0.0, os-locale@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a"
|
||||
integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==
|
||||
@ -8678,6 +8673,11 @@ require-main-filename@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
|
||||
integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
|
||||
|
||||
require-main-filename@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
|
||||
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
|
||||
|
||||
require-uncached@^1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3"
|
||||
@ -9654,6 +9654,15 @@ string-width@^1.0.1, string-width@^1.0.2:
|
||||
is-fullwidth-code-point "^2.0.0"
|
||||
strip-ansi "^4.0.0"
|
||||
|
||||
string-width@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
|
||||
integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
|
||||
dependencies:
|
||||
emoji-regex "^7.0.1"
|
||||
is-fullwidth-code-point "^2.0.0"
|
||||
strip-ansi "^5.1.0"
|
||||
|
||||
string.prototype.padend@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz#f3aaef7c1719f170c5eab1c32bf780d96e21f2f0"
|
||||
@ -11197,6 +11206,14 @@ yargs-parser@^11.1.1:
|
||||
camelcase "^5.0.0"
|
||||
decamelize "^1.2.0"
|
||||
|
||||
yargs-parser@^13.0.0:
|
||||
version "13.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.0.0.tgz#3fc44f3e76a8bdb1cc3602e860108602e5ccde8b"
|
||||
integrity sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==
|
||||
dependencies:
|
||||
camelcase "^5.0.0"
|
||||
decamelize "^1.2.0"
|
||||
|
||||
yargs-parser@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a"
|
||||
@ -11245,6 +11262,23 @@ yargs@12.0.5:
|
||||
y18n "^3.2.1 || ^4.0.0"
|
||||
yargs-parser "^11.1.1"
|
||||
|
||||
yargs@13.1.0:
|
||||
version "13.1.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.1.0.tgz#b2729ce4bfc0c584939719514099d8a916ad2301"
|
||||
integrity sha512-1UhJbXfzHiPqkfXNHYhiz79qM/kZqjTE8yGlEjZa85Q+3+OwcV6NRkV7XOV1W2Eom2bzILeUn55pQYffjVOLAg==
|
||||
dependencies:
|
||||
cliui "^4.0.0"
|
||||
find-up "^3.0.0"
|
||||
get-caller-file "^2.0.1"
|
||||
os-locale "^3.1.0"
|
||||
require-directory "^2.1.1"
|
||||
require-main-filename "^2.0.0"
|
||||
set-blocking "^2.0.0"
|
||||
string-width "^3.0.0"
|
||||
which-module "^2.0.0"
|
||||
y18n "^4.0.0"
|
||||
yargs-parser "^13.0.0"
|
||||
|
||||
yargs@3.32.0, yargs@^3.32.0:
|
||||
version "3.32.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995"
|
||||
@ -11257,25 +11291,6 @@ yargs@3.32.0, yargs@^3.32.0:
|
||||
window-size "^0.1.4"
|
||||
y18n "^3.2.0"
|
||||
|
||||
yargs@9.0.1:
|
||||
version "9.0.1"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c"
|
||||
integrity sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=
|
||||
dependencies:
|
||||
camelcase "^4.1.0"
|
||||
cliui "^3.2.0"
|
||||
decamelize "^1.1.1"
|
||||
get-caller-file "^1.0.1"
|
||||
os-locale "^2.0.0"
|
||||
read-pkg-up "^2.0.0"
|
||||
require-directory "^2.1.1"
|
||||
require-main-filename "^1.0.1"
|
||||
set-blocking "^2.0.0"
|
||||
string-width "^2.0.0"
|
||||
which-module "^2.0.0"
|
||||
y18n "^3.2.1"
|
||||
yargs-parser "^7.0.0"
|
||||
|
||||
yargs@^7.0.2:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8"
|
||||
|
@ -3,7 +3,7 @@
|
||||
"master": {
|
||||
"uncompressed": {
|
||||
"runtime": 1497,
|
||||
"main": 167065,
|
||||
"main": 164945,
|
||||
"polyfills": 43626
|
||||
}
|
||||
}
|
||||
@ -12,7 +12,7 @@
|
||||
"master": {
|
||||
"uncompressed": {
|
||||
"runtime": 1440,
|
||||
"main": 30932,
|
||||
"main": 14487,
|
||||
"polyfills": 43567
|
||||
}
|
||||
}
|
||||
@ -21,7 +21,7 @@
|
||||
"master": {
|
||||
"uncompressed": {
|
||||
"runtime": 1440,
|
||||
"main": 157393,
|
||||
"main": 149205,
|
||||
"polyfills": 43567
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ function installLocalPackages() {
|
||||
readonly pwd=$(pwd)
|
||||
readonly packages=(
|
||||
animations common compiler core forms platform-browser
|
||||
platform-browser-dynamic router bazel compiler-cli language-service upgrade
|
||||
platform-browser-dynamic router bazel compiler-cli language-service
|
||||
)
|
||||
local local_packages=()
|
||||
for package in "${packages[@]}"; do
|
||||
|
@ -23,6 +23,7 @@
|
||||
"node_modules/@angular/core/schematics/**",
|
||||
"node_modules/@angular/compiler-cli/**",
|
||||
"node_modules/@angular/**/testing/**",
|
||||
"node_modules/@angular/common/upgrade*",
|
||||
"node_modules/@angular/router/upgrade*"
|
||||
]
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
"@angular/platform-browser": "packages-dist:platform-browser",
|
||||
"@angular/platform-browser-dynamic": "packages-dist:platform-browser-dynamic",
|
||||
"@angular/router": "packages-dist:router",
|
||||
"@angular/upgrade": "packages-dist:upgrade",
|
||||
"reflect-metadata": "0.1.12",
|
||||
"rxjs": "6.4.0",
|
||||
"tslib": "1.9.3",
|
||||
@ -31,4 +30,4 @@
|
||||
"postinstall": "ngc -p ./angular-metadata.tsconfig.json",
|
||||
"//": "TODO(gregmagolan): figure out how to keep dependencies here up to date with the root package.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
"zone.js": "file:../../node_modules/zone.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^0.800.0-beta.11",
|
||||
"@angular-devkit/build-angular": "0.800.0-beta.15",
|
||||
"@angular/cli": "file:../../node_modules/@angular/cli",
|
||||
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
|
||||
"@angular/language-service": "file:../../dist/packages-dist/language-service",
|
||||
|
@ -73,7 +73,6 @@
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unnecessary-initializer": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
|
@ -28,7 +28,7 @@
|
||||
"zone.js": "file:../../node_modules/zone.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^0.800.0-beta.11",
|
||||
"@angular-devkit/build-angular": "0.800.0-beta.15",
|
||||
"@angular/cli": "file:../../node_modules/@angular/cli",
|
||||
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
|
||||
"@angular/language-service": "file:../../dist/packages-dist/language-service",
|
||||
|
@ -73,7 +73,6 @@
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unnecessary-initializer": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
|
@ -28,7 +28,7 @@
|
||||
"zone.js": "file:../../node_modules/zone.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^0.800.0-beta.11",
|
||||
"@angular-devkit/build-angular": "0.800.0-beta.15",
|
||||
"@angular/cli": "file:../../node_modules/@angular/cli",
|
||||
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
|
||||
"@angular/language-service": "file:../../dist/packages-dist/language-service",
|
||||
|
@ -73,7 +73,6 @@
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unnecessary-initializer": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
|
@ -63,7 +63,7 @@ if [[ $? != 0 ]]; then exit 1; fi
|
||||
|
||||
# Can it be safely run again (as a noop)?
|
||||
# And check that it logged skipping compilation as expected
|
||||
ivy-ngcc | grep 'Skipping'
|
||||
ivy-ngcc -l debug | grep 'Skipping'
|
||||
if [[ $? != 0 ]]; then exit 1; fi
|
||||
|
||||
# Check that running it with logging level error outputs nothing
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "angular-srcs",
|
||||
"version": "8.0.0-rc.0",
|
||||
"version": "8.0.0-rc.3",
|
||||
"private": true,
|
||||
"branchPattern": "2.0.*",
|
||||
"description": "Angular - a web framework for modern web apps",
|
||||
@ -107,7 +107,7 @@
|
||||
"tslint": "5.7.0",
|
||||
"typescript": "~3.4.2",
|
||||
"xhr2": "0.1.4",
|
||||
"yargs": "9.0.1",
|
||||
"yargs": "13.1.0",
|
||||
"zone.js": "^0.9.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
|
@ -34,11 +34,11 @@
|
||||
"@types/node": "6.0.84",
|
||||
"semver": "^5.6.0",
|
||||
"shelljs": "0.8.2",
|
||||
"tsickle": "0.34.3"
|
||||
"tsickle": "^0.35.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/compiler-cli": "0.0.0-PLACEHOLDER",
|
||||
"@bazel/typescript": "0.27.12",
|
||||
"@bazel/typescript": "0.*",
|
||||
"typescript": ">=3.4 <3.5"
|
||||
},
|
||||
"repository": {
|
||||
|
@ -202,7 +202,7 @@ export function compile({allDepsCompiledWithBazel = true, compilerOpts, tsHost,
|
||||
throw new Error(`Couldn't find bazel bin in the rootDirs: ${compilerOpts.rootDirs}`);
|
||||
}
|
||||
|
||||
const writtenExpectedOuts = [...expectedOuts];
|
||||
const writtenExpectedOuts = expectedOuts.map(p => p.replace(/\\/g, '/'));
|
||||
|
||||
const originalWriteFile = tsHost.writeFile.bind(tsHost);
|
||||
tsHost.writeFile =
|
||||
|
@ -20,6 +20,7 @@
|
||||
"node_modules/@angular/core/schematics/**",
|
||||
"node_modules/@angular/compiler-cli/**",
|
||||
"node_modules/@angular/**/testing/**",
|
||||
"node_modules/@angular/common/upgrade*",
|
||||
"node_modules/@angular/router/upgrade*"
|
||||
]
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ function addDevDependenciesToPackageJson(options: Schema) {
|
||||
const devDependencies: {[k: string]: string} = {
|
||||
'@angular/bazel': angularCoreVersion,
|
||||
'@bazel/bazel': '^0.24.0',
|
||||
'@bazel/ibazel': '^0.9.0',
|
||||
'@bazel/ibazel': '^0.10.1',
|
||||
'@bazel/karma': '0.27.12',
|
||||
'@bazel/typescript': '0.27.12',
|
||||
};
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
import {runOneBuild} from '@angular/bazel';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
@ -47,9 +46,7 @@ export function setup(
|
||||
const bazelBinPath = path.resolve(basePath, bazelBin);
|
||||
fs.mkdirSync(bazelBinPath);
|
||||
|
||||
const angularCorePath = path.resolve(runfilesPath, 'angular', 'packages', 'core');
|
||||
const ngFiles = listFilesRecursive(angularCorePath);
|
||||
|
||||
const angularCorePath = path.dirname(require.resolve('angular/packages/core'));
|
||||
const tsConfigJsonPath = path.resolve(basePath, tsconfig);
|
||||
|
||||
return {
|
||||
@ -107,7 +104,10 @@ export function setup(
|
||||
const files = [...compilationTargetSrc];
|
||||
|
||||
depPaths = depPaths.concat([angularCorePath]);
|
||||
pathMapping = pathMapping.concat([{moduleName: '@angular/core', path: angularCorePath}]);
|
||||
pathMapping = pathMapping.concat([
|
||||
{moduleName: '@angular/core', path: angularCorePath},
|
||||
{moduleName: 'angular/packages/core', path: angularCorePath}
|
||||
]);
|
||||
|
||||
for (const depPath of depPaths) {
|
||||
files.push(...listFilesRecursive(depPath).filter(f => f.endsWith('.d.ts')));
|
||||
@ -116,14 +116,12 @@ export function setup(
|
||||
const pathMappingObj = {};
|
||||
for (const mapping of pathMapping) {
|
||||
pathMappingObj[mapping.moduleName] = [mapping.path];
|
||||
pathMappingObj[path.join(mapping.moduleName, '*')] = [path.join(mapping.path, '*')];
|
||||
pathMappingObj[path.posix.join(mapping.moduleName, '*')] =
|
||||
[path.posix.join(mapping.path, '*')];
|
||||
}
|
||||
|
||||
const emptyTsConfig = ts.readConfigFile(
|
||||
path.resolve(
|
||||
runfilesPath, 'angular', 'packages', 'bazel', 'test', 'ngc-wrapped', 'empty',
|
||||
'empty_tsconfig.json'),
|
||||
read);
|
||||
require.resolve('angular/packages/bazel/test/ngc-wrapped/empty/empty_tsconfig.json'), read);
|
||||
|
||||
const tsconfig = createTsConfig({
|
||||
defaultTsConfig: emptyTsConfig.config,
|
||||
|
@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import * as path from 'path';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
||||
|
||||
@ -32,7 +31,6 @@ export function createTsConfig(options: TsConfigOptions) {
|
||||
const result = options.defaultTsConfig;
|
||||
|
||||
return {
|
||||
'extends': '../angular/packages/bazel/test/ngc-wrapped/empty/tsconfig',
|
||||
'compilerOptions': {
|
||||
...result.compilerOptions,
|
||||
'outDir': options.outDir,
|
||||
@ -71,7 +69,8 @@ export function createTsConfig(options: TsConfigOptions) {
|
||||
'tsickleExternsPath': '',
|
||||
// we don't copy the node_modules into our tmp dir, so we should look in
|
||||
// the original workspace directory for it
|
||||
'nodeModulesPrefix': '../npm/node_modules',
|
||||
'nodeModulesPrefix':
|
||||
path.join(require.resolve('npm/node_modules/typescript/package.json'), '../../'),
|
||||
},
|
||||
'files': options.files,
|
||||
'angularCompilerOptions': {
|
||||
|
@ -125,7 +125,7 @@ import {invalidPipeArgumentError} from './invalid_pipe_argument_error';
|
||||
* {{ dateObj | date }} // output is 'Jun 15, 2015'
|
||||
* {{ dateObj | date:'medium' }} // output is 'Jun 15, 2015, 9:43:11 PM'
|
||||
* {{ dateObj | date:'shortTime' }} // output is '9:43 PM'
|
||||
* {{ dateObj | date:'mmss' }} // output is '43:11'
|
||||
* {{ dateObj | date:'mm:ss' }} // output is '43:11'
|
||||
* ```
|
||||
*
|
||||
* ### Usage example
|
||||
|
@ -98,13 +98,8 @@ function symlinkNodeModules() {
|
||||
Object.keys(requiredNodeModules).forEach(importName => {
|
||||
const outputPath = path.join(tmpDir, 'node_modules', importName);
|
||||
const moduleDir = requiredNodeModules[importName];
|
||||
|
||||
findFilesWithinDirectory(moduleDir).forEach(filePath => {
|
||||
const outputFilePath = path.join(outputPath, path.relative(moduleDir, filePath));
|
||||
|
||||
shx.mkdir('-p', path.dirname(outputFilePath));
|
||||
fs.symlinkSync(filePath, outputFilePath);
|
||||
});
|
||||
shx.mkdir('-p', path.dirname(outputPath));
|
||||
fs.symlinkSync(moduleDir, outputPath, 'junction');
|
||||
});
|
||||
}
|
||||
|
||||
@ -162,5 +157,5 @@ function resolveNpmTreeArtifact(manifestPath, resolveFile = 'package.json') {
|
||||
|
||||
/** Finds all files within a specified directory. */
|
||||
function findFilesWithinDirectory(directoryPath) {
|
||||
return shx.find(directoryPath).filter(filePath => !fs.statSync(filePath).isDirectory());
|
||||
return shx.find(directoryPath).filter(filePath => !fs.lstatSync(filePath).isDirectory());
|
||||
}
|
||||
|
@ -33,7 +33,8 @@ export interface NgccOptions {
|
||||
/** The absolute path to the `node_modules` folder that contains the packages to process. */
|
||||
basePath: string;
|
||||
/**
|
||||
* The path, relative to `basePath` to the primary package to be processed.
|
||||
* The path to the primary package to be processed. If not absolute then it must be relative to
|
||||
* `basePath`.
|
||||
*
|
||||
* All its dependencies will need to be processed too.
|
||||
*/
|
||||
@ -86,7 +87,7 @@ export function mainNgcc({basePath, targetEntryPointPath,
|
||||
if (absoluteTargetEntryPointPath &&
|
||||
hasProcessedTargetEntryPoint(
|
||||
absoluteTargetEntryPointPath, propertiesToConsider, compileAllFormats)) {
|
||||
logger.info('The target entry-point has already been processed');
|
||||
logger.debug('The target entry-point has already been processed');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -130,7 +131,7 @@ export function mainNgcc({basePath, targetEntryPointPath,
|
||||
|
||||
if (hasBeenProcessed(entryPointPackageJson, property)) {
|
||||
compiledFormats.add(formatPath);
|
||||
logger.info(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
|
||||
logger.debug(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -152,7 +153,7 @@ export function mainNgcc({basePath, targetEntryPointPath,
|
||||
`Skipping ${entryPoint.name} : ${format} (no valid entry point file for this format).`);
|
||||
}
|
||||
} else if (!compileAllFormats) {
|
||||
logger.info(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
|
||||
logger.debug(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
|
||||
}
|
||||
|
||||
// Either this format was just compiled or its underlying format was compiled because of a
|
||||
|
@ -99,7 +99,7 @@ describe('ngcc main()', () => {
|
||||
basePath: '/node_modules',
|
||||
targetEntryPointPath: '@angular/common/http/testing', logger,
|
||||
});
|
||||
expect(logger.logs.info).toContain(['The target entry-point has already been processed']);
|
||||
expect(logger.logs.debug).toContain(['The target entry-point has already been processed']);
|
||||
});
|
||||
|
||||
it('should process the target if any `propertyToConsider` is not marked as processed', () => {
|
||||
@ -110,7 +110,7 @@ describe('ngcc main()', () => {
|
||||
targetEntryPointPath: '@angular/common/http/testing',
|
||||
propertiesToConsider: ['fesm2015', 'esm5', 'esm2015'], logger,
|
||||
});
|
||||
expect(logger.logs.info).not.toContain([
|
||||
expect(logger.logs.debug).not.toContain([
|
||||
'The target entry-point has already been processed'
|
||||
]);
|
||||
});
|
||||
@ -128,7 +128,7 @@ describe('ngcc main()', () => {
|
||||
compileAllFormats: false, logger,
|
||||
});
|
||||
|
||||
expect(logger.logs.info).not.toContain([
|
||||
expect(logger.logs.debug).not.toContain([
|
||||
'The target entry-point has already been processed'
|
||||
]);
|
||||
});
|
||||
@ -145,7 +145,7 @@ describe('ngcc main()', () => {
|
||||
compileAllFormats: false, logger,
|
||||
});
|
||||
|
||||
expect(logger.logs.info).toContain([
|
||||
expect(logger.logs.debug).toContain([
|
||||
'The target entry-point has already been processed'
|
||||
]);
|
||||
});
|
||||
|
@ -20,7 +20,7 @@
|
||||
"shelljs": "^0.8.1",
|
||||
"source-map": "^0.6.1",
|
||||
"tslib": "^1.9.0",
|
||||
"yargs": "9.0.1"
|
||||
"yargs": "13.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/compiler": "0.0.0-PLACEHOLDER",
|
||||
|
@ -470,7 +470,7 @@ describe('compiler compliance: bindings', () => {
|
||||
…
|
||||
if (rf & 2) {
|
||||
i0.ɵɵselect(0);
|
||||
i0.ɵɵpropertyInterpolateV("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h", ctx.eight, "i", ctx.nine, "j");
|
||||
i0.ɵɵpropertyInterpolateV("title", ["a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h", ctx.eight, "i", ctx.nine, "j"]);
|
||||
i0.ɵɵselect(1);
|
||||
i0.ɵɵpropertyInterpolate8("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h", ctx.eight, "i");
|
||||
i0.ɵɵselect(2);
|
||||
|
@ -122,20 +122,21 @@ export function setupBazelTo(tmpDirPath: string) {
|
||||
fs.mkdirSync(nodeModulesPath);
|
||||
fs.mkdirSync(angularDirectory);
|
||||
|
||||
getAngularPackagesFromRunfiles().forEach(
|
||||
({pkgPath, name}) => { fs.symlinkSync(pkgPath, path.join(angularDirectory, name), 'dir'); });
|
||||
getAngularPackagesFromRunfiles().forEach(({pkgPath, name}) => {
|
||||
fs.symlinkSync(pkgPath, path.join(angularDirectory, name), 'junction');
|
||||
});
|
||||
|
||||
// Link typescript
|
||||
const typeScriptSource = resolveNpmTreeArtifact('npm/node_modules/typescript');
|
||||
const typescriptDest = path.join(nodeModulesPath, 'typescript');
|
||||
fs.symlinkSync(typeScriptSource, typescriptDest, 'dir');
|
||||
fs.symlinkSync(typeScriptSource, typescriptDest, 'junction');
|
||||
|
||||
// Link "rxjs" if it has been set up as a runfile. "rxjs" is linked optionally because
|
||||
// not all compiler-cli tests need "rxjs" set up.
|
||||
try {
|
||||
const rxjsSource = resolveNpmTreeArtifact('rxjs', 'index.js');
|
||||
const rxjsDest = path.join(nodeModulesPath, 'rxjs');
|
||||
fs.symlinkSync(rxjsSource, rxjsDest, 'dir');
|
||||
fs.symlinkSync(rxjsSource, rxjsDest, 'junction');
|
||||
} catch (e) {
|
||||
if (e.code !== 'MODULE_NOT_FOUND') throw e;
|
||||
}
|
||||
|
@ -155,16 +155,12 @@ export function convertPropertyBinding(
|
||||
localResolver = new DefaultLocalResolver();
|
||||
}
|
||||
const currValExpr = createCurrValueExpr(bindingId);
|
||||
const stmts: o.Statement[] = [];
|
||||
const visitor =
|
||||
new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction);
|
||||
const outputExpr: o.Expression = expressionWithoutBuiltins.visit(visitor, _Mode.Expression);
|
||||
const stmts: o.Statement[] = getStatementsFromVisitor(visitor, bindingId);
|
||||
|
||||
if (visitor.temporaryCount) {
|
||||
for (let i = 0; i < visitor.temporaryCount; i++) {
|
||||
stmts.push(temporaryDeclaration(bindingId, i));
|
||||
}
|
||||
} else if (form == BindingForm.TrySimple) {
|
||||
if (visitor.temporaryCount === 0 && form == BindingForm.TrySimple) {
|
||||
return new ConvertPropertyBindingResult([], outputExpr);
|
||||
}
|
||||
|
||||
@ -172,6 +168,58 @@ export function convertPropertyBinding(
|
||||
return new ConvertPropertyBindingResult(stmts, currValExpr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given some expression, such as a binding or interpolation expression, and a context expression to
|
||||
* look values up on, visit each facet of the given expression resolving values from the context
|
||||
* expression such that a list of arguments can be derived from the found values that can be used as
|
||||
* arguments to an external update instruction.
|
||||
*
|
||||
* @param localResolver The resolver to use to look up expressions by name appropriately
|
||||
* @param contextVariableExpression The expression representing the context variable used to create
|
||||
* the final argument expressions
|
||||
* @param expressionWithArgumentsToExtract The expression to visit to figure out what values need to
|
||||
* be resolved and what arguments list to build.
|
||||
* @param bindingId A name prefix used to create temporary variable names if they're needed for the
|
||||
* arguments generated
|
||||
* @returns An array of expressions that can be passed as arguments to instruction expressions like
|
||||
* `o.importExpr(R3.propertyInterpolate).callFn(result)`
|
||||
*/
|
||||
export function convertUpdateArguments(
|
||||
localResolver: LocalResolver, contextVariableExpression: o.Expression,
|
||||
expressionWithArgumentsToExtract: cdAst.AST, bindingId: string) {
|
||||
const visitor =
|
||||
new _AstToIrVisitor(localResolver, contextVariableExpression, bindingId, undefined);
|
||||
const outputExpr: o.InvokeFunctionExpr =
|
||||
expressionWithArgumentsToExtract.visit(visitor, _Mode.Expression);
|
||||
|
||||
const stmts = getStatementsFromVisitor(visitor, bindingId);
|
||||
|
||||
// Removing the first argument, because it was a length for ViewEngine, not Ivy.
|
||||
let args = outputExpr.args.slice(1);
|
||||
if (expressionWithArgumentsToExtract instanceof cdAst.Interpolation) {
|
||||
// If we're dealing with an interpolation of 1 value with an empty prefix and suffix, reduce the
|
||||
// args returned to just the value, because we're going to pass it to a special instruction.
|
||||
const strings = expressionWithArgumentsToExtract.strings;
|
||||
if (args.length === 3 && strings[0] === '' && strings[1] === '') {
|
||||
// Single argument interpolate instructions.
|
||||
args = [args[1]];
|
||||
} else if (args.length >= 19) {
|
||||
// 19 or more arguments must be passed to the `interpolateV`-style instructions, which accept
|
||||
// an array of arguments
|
||||
args = [o.literalArr(args)];
|
||||
}
|
||||
}
|
||||
return {stmts, args};
|
||||
}
|
||||
|
||||
function getStatementsFromVisitor(visitor: _AstToIrVisitor, bindingId: string) {
|
||||
const stmts: o.Statement[] = [];
|
||||
for (let i = 0; i < visitor.temporaryCount; i++) {
|
||||
stmts.push(temporaryDeclaration(bindingId, i));
|
||||
}
|
||||
return stmts;
|
||||
}
|
||||
|
||||
function convertBuiltins(converterFactory: BuiltinConverterFactory, ast: cdAst.AST): cdAst.AST {
|
||||
const visitor = new _BuiltinAstConverter(converterFactory);
|
||||
return ast.visit(visitor);
|
||||
|
@ -92,7 +92,7 @@ export class Identifiers {
|
||||
name: 'ɵinlineInterpolate',
|
||||
moduleName: CORE,
|
||||
};
|
||||
static interpolate: o.ExternalReference = {name: 'ɵɵinterpolate', moduleName: CORE};
|
||||
static interpolate: o.ExternalReference = {name: 'ɵinterpolate', moduleName: CORE};
|
||||
static EMPTY_ARRAY: o.ExternalReference = {name: 'ɵEMPTY_ARRAY', moduleName: CORE};
|
||||
static EMPTY_MAP: o.ExternalReference = {name: 'ɵEMPTY_MAP', moduleName: CORE};
|
||||
static Renderer: o.ExternalReference = {name: 'Renderer', moduleName: CORE};
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {flatten, sanitizeIdentifier} from '../../compile_metadata';
|
||||
import {BindingForm, BuiltinFunctionCall, LocalResolver, convertActionBinding, convertPropertyBinding} from '../../compiler_util/expression_converter';
|
||||
import {BindingForm, BuiltinFunctionCall, LocalResolver, convertActionBinding, convertPropertyBinding, convertUpdateArguments} from '../../compiler_util/expression_converter';
|
||||
import {ConstantPool} from '../../constant_pool';
|
||||
import * as core from '../../core';
|
||||
import {AST, AstMemoryEfficientTransformer, BindingPipe, BindingType, FunctionCall, ImplicitReceiver, Interpolation, LiteralArray, LiteralMap, LiteralPrimitive, ParsedEventType, PropertyRead} from '../../expression_parser/ast';
|
||||
@ -750,23 +750,13 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
|
||||
if (inputType === BindingType.Property) {
|
||||
if (value instanceof Interpolation) {
|
||||
// Interpolated properties
|
||||
const {currValExpr} = convertPropertyBinding(
|
||||
this, implicit, value, this.bindingContext(), BindingForm.TrySimple);
|
||||
|
||||
let args: o.Expression[] = (currValExpr as any).args;
|
||||
args.shift(); // ViewEngine required a count, we don't need that.
|
||||
|
||||
// For interpolations like attr="{{foo}}", we don't need ["", foo, ""], just [foo].
|
||||
if (args.length === 3 && isEmptyStringExpression(args[0]) &&
|
||||
isEmptyStringExpression(args[2])) {
|
||||
args = [args[1]];
|
||||
}
|
||||
|
||||
this.updateInstruction(
|
||||
elementIndex, input.sourceSpan, propertyInterpolate(args.length), () => {
|
||||
return [o.literal(attrName), ...args, ...params];
|
||||
});
|
||||
elementIndex, input.sourceSpan, getPropertyInterpolationExpression(value),
|
||||
() =>
|
||||
[o.literal(attrName),
|
||||
...this.getUpdateInstructionArguments(o.variable(CONTEXT_NAME), value),
|
||||
...params]);
|
||||
|
||||
} else {
|
||||
// Bound, un-interpolated properties
|
||||
this.updateInstruction(elementIndex, input.sourceSpan, R3.property, () => {
|
||||
@ -1076,6 +1066,21 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
o.importExpr(R3.bind).callFn([valExpr]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of argument expressions to pass to an update instruction expression. Also updates
|
||||
* the temp variables state with temp variables that were identified as needing to be created
|
||||
* while visiting the arguments.
|
||||
* @param contextExpression The expression for the context variable used to create arguments
|
||||
* @param value The original expression we will be resolving an arguments list from.
|
||||
*/
|
||||
private getUpdateInstructionArguments(contextExpression: o.Expression, value: AST):
|
||||
o.Expression[] {
|
||||
const {args, stmts} =
|
||||
convertUpdateArguments(this, contextExpression, value, this.bindingContext());
|
||||
this._tempVariables.push(...stmts);
|
||||
return args;
|
||||
}
|
||||
|
||||
private matchDirectives(tagName: string, elOrTpl: t.Element|t.Template) {
|
||||
if (this.directiveMatcher) {
|
||||
const selector = createCssSelector(tagName, getAttrsForDirectiveMatching(elOrTpl));
|
||||
@ -1646,16 +1651,12 @@ function interpolate(args: o.Expression[]): o.Expression {
|
||||
return o.importExpr(R3.interpolationV).callFn([o.literalArr(args)]);
|
||||
}
|
||||
|
||||
function isEmptyStringExpression(exp: o.Expression) {
|
||||
return exp instanceof o.LiteralExpr && exp.value === '';
|
||||
}
|
||||
|
||||
function propertyInterpolate(argsLength: number) {
|
||||
if (argsLength % 2 !== 1) {
|
||||
error(`Invalid propertyInterpolate argument length ${argsLength}`);
|
||||
}
|
||||
|
||||
switch (argsLength) {
|
||||
/**
|
||||
* Gets the instruction to generate for an interpolated property
|
||||
* @param interpolation An Interpolation AST
|
||||
*/
|
||||
function getPropertyInterpolationExpression(interpolation: Interpolation) {
|
||||
switch (getInterpolationArgsLength(interpolation)) {
|
||||
case 1:
|
||||
return R3.propertyInterpolate;
|
||||
case 3:
|
||||
@ -1679,6 +1680,22 @@ function propertyInterpolate(argsLength: number) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of arguments expected to be passed to a generated instruction in the case of
|
||||
* interpolation instructions.
|
||||
* @param interpolation An interpolation ast
|
||||
*/
|
||||
function getInterpolationArgsLength(interpolation: Interpolation) {
|
||||
const {expressions, strings} = interpolation;
|
||||
if (expressions.length === 1 && strings.length === 2 && strings[0] === '' && strings[1] === '') {
|
||||
// If the interpolation has one interpolated value, but the prefix and suffix are both empty
|
||||
// strings, we only pass one argument, to a special instruction like `propertyInterpolate` or
|
||||
// `textInterpolate`.
|
||||
return 1;
|
||||
} else {
|
||||
return expressions.length + strings.length;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Options that can be used to modify how a template is parsed by `parseTemplate()`.
|
||||
*/
|
||||
|
@ -576,8 +576,8 @@ function readBazelWrittenFilesFrom(
|
||||
function processDirectory(dir: string, dest: string) {
|
||||
const entries = fs.readdirSync(dir);
|
||||
for (const name of entries) {
|
||||
const fullName = path.join(dir, name);
|
||||
const destName = path.join(dest, name);
|
||||
const fullName = path.posix.join(dir, name);
|
||||
const destName = path.posix.join(dest, name);
|
||||
const stat = fs.statSync(fullName);
|
||||
if (!skip(name, fullName)) {
|
||||
if (stat.isDirectory()) {
|
||||
@ -590,11 +590,11 @@ function readBazelWrittenFilesFrom(
|
||||
}
|
||||
}
|
||||
try {
|
||||
processDirectory(bazelPackageRoot, path.join('/node_modules/@angular', packageName));
|
||||
processDirectory(bazelPackageRoot, path.posix.join('/node_modules/@angular', packageName));
|
||||
// todo: check why we always need an index.d.ts
|
||||
if (fs.existsSync(path.join(bazelPackageRoot, `${packageName}.d.ts`))) {
|
||||
const content = fs.readFileSync(path.join(bazelPackageRoot, `${packageName}.d.ts`), 'utf8');
|
||||
map.set(path.join('/node_modules/@angular', packageName, 'index.d.ts'), content);
|
||||
map.set(path.posix.join('/node_modules/@angular', packageName, 'index.d.ts'), content);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
@ -632,24 +632,25 @@ export function setup(options: {
|
||||
if (options.compileAngular) {
|
||||
// If this fails please add //packages/core:npm_package as a test data dependency.
|
||||
readBazelWrittenFilesFrom(
|
||||
path.join(sources, 'angular/packages/core/npm_package'), 'core', angularFiles,
|
||||
resolveNpmTreeArtifact('angular/packages/core/npm_package'), 'core', angularFiles,
|
||||
skipDirs);
|
||||
}
|
||||
if (options.compileFakeCore) {
|
||||
readBazelWrittenFilesFrom(
|
||||
path.join(sources, 'angular/packages/compiler-cli/test/ngtsc/fake_core/npm_package'),
|
||||
resolveNpmTreeArtifact(
|
||||
'angular/packages/compiler-cli/test/ngtsc/fake_core/npm_package'),
|
||||
'core', angularFiles, skipDirs);
|
||||
}
|
||||
if (options.compileAnimations) {
|
||||
// If this fails please add //packages/animations:npm_package as a test data dependency.
|
||||
readBazelWrittenFilesFrom(
|
||||
path.join(sources, 'angular/packages/animations/npm_package'), 'animations',
|
||||
resolveNpmTreeArtifact('angular/packages/animations/npm_package'), 'animations',
|
||||
angularFiles, skipDirs);
|
||||
}
|
||||
if (options.compileCommon) {
|
||||
// If this fails please add //packages/common:npm_package as a test data dependency.
|
||||
readBazelWrittenFilesFrom(
|
||||
path.join(sources, 'angular/packages/common/npm_package'), 'common', angularFiles,
|
||||
resolveNpmTreeArtifact('angular/packages/common/npm_package'), 'common', angularFiles,
|
||||
skipDirs);
|
||||
}
|
||||
return;
|
||||
@ -750,6 +751,10 @@ function isSourceOrDts(fileName: string): boolean {
|
||||
return /\.ts$/.test(fileName);
|
||||
}
|
||||
|
||||
function resolveNpmTreeArtifact(manifestPath: string, resolveFile = 'package.json') {
|
||||
return path.dirname(require.resolve(path.posix.join(manifestPath, resolveFile)));
|
||||
}
|
||||
|
||||
export function compile(
|
||||
rootDirs: MockData, options: {
|
||||
emit?: boolean,
|
||||
|
@ -3,6 +3,7 @@ load("//tools:defaults.bzl", "npm_package")
|
||||
exports_files([
|
||||
"tsconfig.json",
|
||||
"migrations.json",
|
||||
"test-migrations.json",
|
||||
])
|
||||
|
||||
npm_package(
|
||||
|
@ -14,11 +14,6 @@
|
||||
"version": "8-beta",
|
||||
"description": "Warns developers if values are assigned to template variables",
|
||||
"factory": "./migrations/template-var-assignment/index"
|
||||
},
|
||||
"migration-v8-injectable-pipe": {
|
||||
"version": "8-beta",
|
||||
"description": "Migrates all Pipe classes so that they have an Injectable annotation",
|
||||
"factory": "./migrations/injectable-pipe/index"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import {Replacement, RuleFailure, Rules} from 'tslint';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {InjectablePipeVisitor} from '../angular/injectable_pipe_visitor';
|
||||
import {INJECTABLE_DECORATOR_NAME, addNamedImport, getNamedImports} from '../util';
|
||||
import {INJECTABLE_DECORATOR_NAME, addImport, getNamedImports} from '../util';
|
||||
|
||||
/**
|
||||
* TSLint rule that flags `@Pipe` classes that haven't been marked as `@Injectable`.
|
||||
@ -37,8 +37,7 @@ export class Rule extends Rules.TypedRule {
|
||||
fixes.push(new Replacement(
|
||||
namedImports.getStart(), namedImports.getWidth(),
|
||||
printer.printNode(
|
||||
ts.EmitHint.Unspecified,
|
||||
addNamedImport(importDeclarationMissingImport, INJECTABLE_DECORATOR_NAME),
|
||||
ts.EmitHint.Unspecified, addImport(namedImports, INJECTABLE_DECORATOR_NAME),
|
||||
sourceFile)));
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths';
|
||||
import {parseTsconfigFile} from '../../utils/typescript/parse_tsconfig';
|
||||
|
||||
import {InjectablePipeVisitor} from './angular/injectable_pipe_visitor';
|
||||
import {INJECTABLE_DECORATOR_NAME, addNamedImport, getNamedImports} from './util';
|
||||
import {INJECTABLE_DECORATOR_NAME, addImport, getNamedImports} from './util';
|
||||
|
||||
/**
|
||||
* Runs a migration over a TypeScript project that adds an `@Injectable`
|
||||
@ -78,8 +78,7 @@ function runInjectablePipeMigration(tree: Tree, tsconfigPath: string, basePath:
|
||||
update.insertRight(
|
||||
namedImports.getStart(),
|
||||
printer.printNode(
|
||||
ts.EmitHint.Unspecified,
|
||||
addNamedImport(importDeclarationMissingImport, INJECTABLE_DECORATOR_NAME),
|
||||
ts.EmitHint.Unspecified, addImport(namedImports, INJECTABLE_DECORATOR_NAME),
|
||||
sourceFile));
|
||||
}
|
||||
}
|
||||
|
@ -12,28 +12,17 @@ import * as ts from 'typescript';
|
||||
export const INJECTABLE_DECORATOR_NAME = 'Injectable';
|
||||
|
||||
/**
|
||||
* Adds a named import to an import declaration node.
|
||||
* Adds an import to a named import node, if the import does not exist already.
|
||||
* @param node Node to which to add the import.
|
||||
* @param importName Name of the import that should be added.
|
||||
*/
|
||||
export function addNamedImport(node: ts.ImportDeclaration, importName: string) {
|
||||
const namedImports = getNamedImports(node);
|
||||
export function addImport(node: ts.NamedImports, importName: string) {
|
||||
const elements = node.elements;
|
||||
const isAlreadyImported = elements.some(element => element.name.text === importName);
|
||||
|
||||
if (namedImports && ts.isNamedImports(namedImports)) {
|
||||
const elements = namedImports.elements;
|
||||
const isAlreadyImported = elements.some(element => element.name.text === importName);
|
||||
|
||||
if (!isAlreadyImported) {
|
||||
// If there are named imports, there will be an import clause as well.
|
||||
const importClause = node.importClause !;
|
||||
const newImportClause = ts.createNamedImports(
|
||||
[...elements, ts.createImportSpecifier(undefined, ts.createIdentifier(importName))]);
|
||||
|
||||
return ts.updateImportDeclaration(
|
||||
node, node.decorators, node.modifiers,
|
||||
ts.updateImportClause(importClause, importClause.name, newImportClause),
|
||||
node.moduleSpecifier);
|
||||
}
|
||||
if (!isAlreadyImported) {
|
||||
return ts.updateNamedImports(
|
||||
node, [...elements, ts.createImportSpecifier(undefined, ts.createIdentifier(importName))]);
|
||||
}
|
||||
|
||||
return node;
|
||||
|
@ -64,13 +64,13 @@ export class Rule extends Rules.TypedRule {
|
||||
queries.forEach(q => {
|
||||
const queryExpr = q.decorator.node.expression;
|
||||
const {timing, message} = usageStrategy.detectTiming(q);
|
||||
const transformedNode = getTransformedQueryCallExpr(q, timing, !!message);
|
||||
const result = getTransformedQueryCallExpr(q, timing, !!message);
|
||||
|
||||
if (!transformedNode) {
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newText = printer.printNode(ts.EmitHint.Unspecified, transformedNode, sourceFile);
|
||||
const newText = printer.printNode(ts.EmitHint.Unspecified, result.node, sourceFile);
|
||||
|
||||
// Replace the existing query decorator call expression with the
|
||||
// updated call expression node.
|
||||
|
@ -192,23 +192,24 @@ async function runStaticQueryMigration(
|
||||
queries.forEach(q => {
|
||||
const queryExpr = q.decorator.node.expression;
|
||||
const {timing, message} = strategy.detectTiming(q);
|
||||
const transformedNode = getTransformedQueryCallExpr(q, timing, !!message);
|
||||
const result = getTransformedQueryCallExpr(q, timing, !!message);
|
||||
|
||||
if (!transformedNode) {
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newText = printer.printNode(ts.EmitHint.Unspecified, transformedNode, sourceFile);
|
||||
const newText = printer.printNode(ts.EmitHint.Unspecified, result.node, sourceFile);
|
||||
|
||||
// Replace the existing query decorator call expression with the updated
|
||||
// call expression node.
|
||||
update.remove(queryExpr.getStart(), queryExpr.getWidth());
|
||||
update.insertRight(queryExpr.getStart(), newText);
|
||||
|
||||
if (message) {
|
||||
if (result.failureMessage || message) {
|
||||
const {line, character} =
|
||||
ts.getLineAndCharacterOfPosition(sourceFile, q.decorator.node.getStart());
|
||||
failureMessages.push(`${relativePath}@${line + 1}:${character + 1}: ${message}`);
|
||||
failureMessages.push(
|
||||
`${relativePath}@${line + 1}:${character + 1}: ${result.failureMessage || message}`);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -10,6 +10,13 @@ import * as ts from 'typescript';
|
||||
import {getPropertyNameText} from '../../utils/typescript/property_name';
|
||||
import {NgQueryDefinition, QueryTiming} from './angular/query-definition';
|
||||
|
||||
export type TransformedQueryResult = null | {
|
||||
/** Transformed call expression. */
|
||||
node: ts.CallExpression;
|
||||
/** Failure message which is set when the query could not be transformed successfully. */
|
||||
failureMessage: string|null;
|
||||
};
|
||||
|
||||
const TODO_COMMENT = 'TODO: add static flag';
|
||||
|
||||
/**
|
||||
@ -17,8 +24,8 @@ const TODO_COMMENT = 'TODO: add static flag';
|
||||
* determined timing. The updated decorator call expression node will be returned.
|
||||
*/
|
||||
export function getTransformedQueryCallExpr(
|
||||
query: NgQueryDefinition, timing: QueryTiming | null, createTodo: boolean): ts.CallExpression|
|
||||
null {
|
||||
query: NgQueryDefinition, timing: QueryTiming | null,
|
||||
createTodo: boolean): TransformedQueryResult {
|
||||
const queryExpr = query.decorator.node.expression;
|
||||
const queryArguments = queryExpr.arguments;
|
||||
const queryPropertyAssignments = timing === null ?
|
||||
@ -27,29 +34,52 @@ export function getTransformedQueryCallExpr(
|
||||
'static', timing === QueryTiming.STATIC ? ts.createTrue() : ts.createFalse())];
|
||||
|
||||
// If the query decorator is already called with two arguments, we need to
|
||||
// keep the existing options untouched and just add the new property if needed.
|
||||
// keep the existing options untouched and just add the new property if possible.
|
||||
if (queryArguments.length === 2) {
|
||||
const existingOptions = queryArguments[1] as ts.ObjectLiteralExpression;
|
||||
const existingOptions = queryArguments[1];
|
||||
const hasTodoComment = existingOptions.getFullText().includes(TODO_COMMENT);
|
||||
let newOptionsNode: ts.Expression;
|
||||
let failureMessage: string|null = null;
|
||||
|
||||
// In case the options already contains a property for the "static" flag, we just
|
||||
// skip this query and leave it untouched.
|
||||
if (existingOptions.properties.some(
|
||||
p => !!p.name && getPropertyNameText(p.name) === 'static')) {
|
||||
return null;
|
||||
if (ts.isObjectLiteralExpression(existingOptions)) {
|
||||
// In case the options already contains a property for the "static" flag,
|
||||
// we just skip this query and leave it untouched.
|
||||
if (existingOptions.properties.some(
|
||||
p => !!p.name && getPropertyNameText(p.name) === 'static')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
newOptionsNode = ts.updateObjectLiteral(
|
||||
existingOptions, existingOptions.properties.concat(queryPropertyAssignments));
|
||||
|
||||
// In case we want to add a todo and the options do not have the todo
|
||||
// yet, we add the query timing todo as synthetic multi-line comment.
|
||||
if (createTodo && !hasTodoComment) {
|
||||
addQueryTimingTodoToNode(newOptionsNode);
|
||||
}
|
||||
} else {
|
||||
// In case the options query parameter is not an object literal expression, and
|
||||
// we want to set the query timing, we just preserve the existing query parameter.
|
||||
newOptionsNode = existingOptions;
|
||||
// We always want to add a TODO in case the query options cannot be updated.
|
||||
if (!hasTodoComment) {
|
||||
addQueryTimingTodoToNode(existingOptions);
|
||||
}
|
||||
// If there is a new explicit timing that has been determined for the given query,
|
||||
// we create a transformation failure message that shows developers that they need
|
||||
// to set the query timing manually to the determined query timing.
|
||||
if (timing !== null) {
|
||||
failureMessage = 'Cannot update query declaration to explicit timing. Please manually ' +
|
||||
`set the query timing to: "{static: ${(timing === QueryTiming.STATIC).toString()}}"`;
|
||||
}
|
||||
}
|
||||
|
||||
const updatedOptions = ts.updateObjectLiteral(
|
||||
existingOptions, existingOptions.properties.concat(queryPropertyAssignments));
|
||||
|
||||
// In case we want to add a todo and the options do not have the todo
|
||||
// yet, we add the query timing todo as synthetic multi-line comment.
|
||||
if (createTodo && !existingOptions.getFullText().includes(TODO_COMMENT)) {
|
||||
addQueryTimingTodoToNode(updatedOptions);
|
||||
}
|
||||
|
||||
return ts.updateCall(
|
||||
queryExpr, queryExpr.expression, queryExpr.typeArguments,
|
||||
[queryArguments[0], updatedOptions]);
|
||||
return {
|
||||
failureMessage,
|
||||
node: ts.updateCall(
|
||||
queryExpr, queryExpr.expression, queryExpr.typeArguments,
|
||||
[queryArguments[0], newOptionsNode !])
|
||||
};
|
||||
}
|
||||
|
||||
const optionsNode = ts.createObjectLiteral(queryPropertyAssignments);
|
||||
@ -58,8 +88,12 @@ export function getTransformedQueryCallExpr(
|
||||
addQueryTimingTodoToNode(optionsNode);
|
||||
}
|
||||
|
||||
return ts.updateCall(
|
||||
queryExpr, queryExpr.expression, queryExpr.typeArguments, [queryArguments[0], optionsNode]);
|
||||
return {
|
||||
failureMessage: null,
|
||||
node: ts.updateCall(
|
||||
queryExpr, queryExpr.expression, queryExpr.typeArguments,
|
||||
[queryArguments[0], optionsNode])
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
20
packages/core/schematics/test-migrations.json
Normal file
20
packages/core/schematics/test-migrations.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"schematics": {
|
||||
"migration-move-document": {
|
||||
"description": "Migrates DOCUMENT Injection token from platform-browser imports to common import",
|
||||
"factory": "./migrations/move-document/index"
|
||||
},
|
||||
"migration-static-queries": {
|
||||
"description": "Migrates ViewChild and ContentChild to explicit query timing",
|
||||
"factory": "./migrations/static-queries/index"
|
||||
},
|
||||
"migration-template-local-variables": {
|
||||
"description": "Warns developers if values are assigned to template variables",
|
||||
"factory": "./migrations/template-var-assignment/index"
|
||||
},
|
||||
"migration-injectable-pipe": {
|
||||
"description": "Migrates all Pipe classes so that they have an Injectable annotation",
|
||||
"factory": "./migrations/injectable-pipe/index"
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ ts_library(
|
||||
testonly = True,
|
||||
srcs = glob(["**/*.ts"]),
|
||||
data = [
|
||||
"//packages/core/schematics:migrations.json",
|
||||
"//packages/core/schematics:test-migrations.json",
|
||||
],
|
||||
deps = [
|
||||
"//packages/core/schematics/migrations/injectable-pipe",
|
||||
|
@ -85,7 +85,10 @@ describe('Google3 injectable pipe TSLint rule', () => {
|
||||
`);
|
||||
|
||||
runTSLint();
|
||||
expect(getFile('/index.ts')).toContain('import { Pipe, Injectable } from \'@angular/core\'');
|
||||
|
||||
const content = getFile('/index.ts');
|
||||
expect(content).toContain('import { Pipe, Injectable } from \'@angular/core\'');
|
||||
expect((content.match(/import/g) || []).length).toBe(1, 'Expected only one import statement');
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -20,7 +20,7 @@ describe('injectable pipe migration', () => {
|
||||
let previousWorkingDir: string;
|
||||
|
||||
beforeEach(() => {
|
||||
runner = new SchematicTestRunner('test', require.resolve('../migrations.json'));
|
||||
runner = new SchematicTestRunner('test', require.resolve('../test-migrations.json'));
|
||||
host = new TempScopedNodeJsSyncHost();
|
||||
tree = new UnitTestTree(new HostTree(host));
|
||||
|
||||
@ -70,8 +70,10 @@ describe('injectable pipe migration', () => {
|
||||
`);
|
||||
|
||||
runMigration();
|
||||
expect(tree.readContent('/index.ts'))
|
||||
.toContain('import { Pipe, Injectable } from \'@angular/core\'');
|
||||
|
||||
const content = tree.readContent('/index.ts');
|
||||
expect(content).toContain('import { Pipe, Injectable } from \'@angular/core\'');
|
||||
expect((content.match(/import/g) || []).length).toBe(1, 'Expected only one import statement');
|
||||
});
|
||||
|
||||
it('should not add an import for Injectable if it is imported already', () => {
|
||||
@ -121,5 +123,5 @@ describe('injectable pipe migration', () => {
|
||||
host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents));
|
||||
}
|
||||
|
||||
function runMigration() { runner.runSchematic('migration-v8-injectable-pipe', {}, tree); }
|
||||
function runMigration() { runner.runSchematic('migration-injectable-pipe', {}, tree); }
|
||||
});
|
||||
|
@ -20,7 +20,7 @@ describe('move-document migration', () => {
|
||||
let previousWorkingDir: string;
|
||||
|
||||
beforeEach(() => {
|
||||
runner = new SchematicTestRunner('test', require.resolve('../migrations.json'));
|
||||
runner = new SchematicTestRunner('test', require.resolve('../test-migrations.json'));
|
||||
host = new TempScopedNodeJsSyncHost();
|
||||
tree = new UnitTestTree(new HostTree(host));
|
||||
|
||||
@ -151,5 +151,5 @@ describe('move-document migration', () => {
|
||||
host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents));
|
||||
}
|
||||
|
||||
function runMigration() { runner.runSchematic('migration-v8-move-document', {}, tree); }
|
||||
function runMigration() { runner.runSchematic('migration-move-document', {}, tree); }
|
||||
});
|
||||
|
@ -21,7 +21,7 @@ describe('static-queries migration with template strategy', () => {
|
||||
let warnOutput: string[];
|
||||
|
||||
beforeEach(() => {
|
||||
runner = new SchematicTestRunner('test', require.resolve('../migrations.json'));
|
||||
runner = new SchematicTestRunner('test', require.resolve('../test-migrations.json'));
|
||||
host = new TempScopedNodeJsSyncHost();
|
||||
tree = new UnitTestTree(new HostTree(host));
|
||||
|
||||
@ -97,7 +97,7 @@ describe('static-queries migration with template strategy', () => {
|
||||
}
|
||||
|
||||
async function runMigration() {
|
||||
await runner.runSchematicAsync('migration-v8-static-queries', {}, tree).toPromise();
|
||||
await runner.runSchematicAsync('migration-static-queries', {}, tree).toPromise();
|
||||
}
|
||||
|
||||
describe('ViewChild', () => {
|
||||
@ -105,7 +105,7 @@ describe('static-queries migration with template strategy', () => {
|
||||
it('should detect queries selecting elements through template reference', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, NgModule, ViewChild} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: \`
|
||||
<ng-template>
|
||||
<button #myButton>My Button</button>
|
||||
@ -118,7 +118,7 @@ describe('static-queries migration with template strategy', () => {
|
||||
private @ViewChild('myButton') query: any;
|
||||
private @ViewChild('myStaticButton') query2: any;
|
||||
}
|
||||
|
||||
|
||||
@NgModule({declarations: [MyComp]})
|
||||
export class MyModule {}
|
||||
`);
|
||||
@ -134,7 +134,7 @@ describe('static-queries migration with template strategy', () => {
|
||||
it('should detect queries selecting ng-template as static', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, NgModule, ViewChild} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: \`
|
||||
<ng-template #myTmpl>
|
||||
My template
|
||||
@ -143,7 +143,7 @@ describe('static-queries migration with template strategy', () => {
|
||||
export class MyComp {
|
||||
private @ViewChild('myTmpl') query: any;
|
||||
}
|
||||
|
||||
|
||||
@NgModule({declarations: [MyComp]})
|
||||
export class MyModule {}
|
||||
`);
|
||||
@ -157,7 +157,7 @@ describe('static-queries migration with template strategy', () => {
|
||||
it('should detect queries selecting component view providers through string token', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, Directive, NgModule, ViewChild} from '@angular/core';
|
||||
|
||||
|
||||
@Directive({
|
||||
selector: '[myDirective]',
|
||||
providers: [
|
||||
@ -165,7 +165,7 @@ describe('static-queries migration with template strategy', () => {
|
||||
]
|
||||
})
|
||||
export class MyDirective {}
|
||||
|
||||
|
||||
@Directive({
|
||||
selector: '[myDirective2]',
|
||||
providers: [
|
||||
@ -173,13 +173,13 @@ describe('static-queries migration with template strategy', () => {
|
||||
]
|
||||
})
|
||||
export class MyDirective2 {}
|
||||
|
||||
|
||||
@Component({templateUrl: './my-tmpl.html'})
|
||||
export class MyComp {
|
||||
private @ViewChild('my-token') query: any;
|
||||
private @ViewChild('my-token-2') query2: any;
|
||||
}
|
||||
|
||||
|
||||
@NgModule({declarations: [MyComp, MyDirective, MyDirective2]})
|
||||
export class MyModule {}
|
||||
`);
|
||||
@ -202,28 +202,28 @@ describe('static-queries migration with template strategy', () => {
|
||||
it('should detect queries selecting component view providers using class token', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, Directive, NgModule, ViewChild} from '@angular/core';
|
||||
|
||||
|
||||
export class MyService {}
|
||||
export class MyService2 {}
|
||||
|
||||
|
||||
@Directive({
|
||||
selector: '[myDirective]',
|
||||
providers: [MyService]
|
||||
})
|
||||
export class MyDirective {}
|
||||
|
||||
|
||||
@Directive({
|
||||
selector: '[myDirective2]',
|
||||
providers: [MyService2]
|
||||
})
|
||||
export class MyDirective2 {}
|
||||
|
||||
|
||||
@Component({templateUrl: './my-tmpl.html'})
|
||||
export class MyComp {
|
||||
private @ViewChild(MyService) query: any;
|
||||
private @ViewChild(MyService2) query2: any;
|
||||
}
|
||||
|
||||
|
||||
@NgModule({declarations: [MyComp, MyDirective, MyDirective2]})
|
||||
export class MyModule {}
|
||||
`);
|
||||
@ -247,7 +247,7 @@ describe('static-queries migration with template strategy', () => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, NgModule, ViewChild} from '@angular/core';
|
||||
import {HomeComponent, HomeComponent2} from './home-comp';
|
||||
|
||||
|
||||
@Component({
|
||||
template: \`
|
||||
<home-comp></home-comp>
|
||||
@ -260,20 +260,20 @@ describe('static-queries migration with template strategy', () => {
|
||||
private @ViewChild(HomeComponent) query: any;
|
||||
private @ViewChild(HomeComponent2) query2: any;
|
||||
}
|
||||
|
||||
|
||||
@NgModule({declarations: [MyComp, HomeComponent, HomeComponent2]})
|
||||
export class MyModule {}
|
||||
`);
|
||||
|
||||
writeFile(`/home-comp.ts`, `
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'home-comp',
|
||||
template: '<span>Home</span>'
|
||||
})
|
||||
export class HomeComponent {}
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'home-comp2',
|
||||
template: '<span>Home 2</span>'
|
||||
@ -294,12 +294,12 @@ describe('static-queries migration with template strategy', () => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, NgModule, ViewChild} from '@angular/core';
|
||||
import {MyLibComponent} from 'my-lib';
|
||||
|
||||
|
||||
@Component({templateUrl: './my-tmpl.html'})
|
||||
export class MyComp {
|
||||
private @ViewChild(MyLibComponent) query: any;
|
||||
}
|
||||
|
||||
|
||||
@NgModule({declarations: [MyComp, MyLibComponent]})
|
||||
export class MyModule {}
|
||||
`);
|
||||
@ -319,12 +319,12 @@ describe('static-queries migration with template strategy', () => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, NgModule, ViewChild} from '@angular/core';
|
||||
import {MyLibComponent} from 'my-lib';
|
||||
|
||||
|
||||
@Component({templateUrl: './my-tmpl.html'})
|
||||
export class MyComp {
|
||||
private @ViewChild(MyLibComponent) query: any;
|
||||
}
|
||||
|
||||
|
||||
@NgModule({declarations: [MyComp, MyLibComponent]})
|
||||
export class MyModule {}
|
||||
`);
|
||||
@ -345,16 +345,16 @@ describe('static-queries migration with template strategy', () => {
|
||||
it('should detect queries within structural directive', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, Directive, NgModule, ViewChild} from '@angular/core';
|
||||
|
||||
|
||||
@Directive({selector: '[ngIf]'})
|
||||
export class FakeNgIf {}
|
||||
|
||||
|
||||
@Component({templateUrl: 'my-tmpl.html'})
|
||||
export class MyComp {
|
||||
private @ViewChild('myRef') query: any;
|
||||
private @ViewChild('myRef2') query2: any;
|
||||
}
|
||||
|
||||
|
||||
@NgModule({declarations: [MyComp, FakeNgIf]})
|
||||
export class MyModule {}
|
||||
`);
|
||||
@ -375,14 +375,14 @@ describe('static-queries migration with template strategy', () => {
|
||||
it('should detect inherited queries', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, NgModule, ViewChild} from '@angular/core';
|
||||
|
||||
|
||||
export class BaseClass {
|
||||
@ViewChild('myRef') query: any;
|
||||
}
|
||||
|
||||
|
||||
@Component({templateUrl: 'my-tmpl.html'})
|
||||
export class MyComp extends BaseClass {}
|
||||
|
||||
|
||||
@NgModule({declarations: [MyComp]})
|
||||
export class MyModule {}
|
||||
`);
|
||||
@ -400,7 +400,7 @@ describe('static-queries migration with template strategy', () => {
|
||||
it('should add a todo if a query is not declared in any component', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, NgModule, ViewChild, SomeToken} from '@angular/core';
|
||||
|
||||
|
||||
export class NotAComponent {
|
||||
@ViewChild('myRef', {read: SomeToken}) query: any;
|
||||
}
|
||||
@ -420,17 +420,17 @@ describe('static-queries migration with template strategy', () => {
|
||||
it('should add a todo if a query is used multiple times with different timing', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, NgModule, ViewChild} from '@angular/core';
|
||||
|
||||
|
||||
export class BaseClass {
|
||||
@ViewChild('myRef') query: any;
|
||||
}
|
||||
|
||||
|
||||
@Component({template: '<ng-template><p #myRef></p></ng-template>'})
|
||||
export class FirstComp extends BaseClass {}
|
||||
|
||||
|
||||
@Component({template: '<span #myRef></span>'})
|
||||
export class SecondComp extends BaseClass {}
|
||||
|
||||
|
||||
@NgModule({declarations: [FirstComp, SecondComp]})
|
||||
export class MyModule {}
|
||||
`);
|
||||
@ -448,12 +448,12 @@ describe('static-queries migration with template strategy', () => {
|
||||
it('should gracefully exit migration if queries could not be analyzed', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ViewChild} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<ng-template><p #myRef></p></ng-template>'})
|
||||
export class MyComp {
|
||||
@ViewChild('myRef') query: any;
|
||||
}
|
||||
|
||||
|
||||
// **NOTE**: Analysis will fail as there is no "NgModule" that declares the component.
|
||||
`);
|
||||
|
||||
@ -492,6 +492,31 @@ describe('static-queries migration with template strategy', () => {
|
||||
.toMatch(/^⮑ {3}index.ts@6:11: Content queries cannot be migrated automatically\./);
|
||||
});
|
||||
|
||||
it('should add a todo if query options cannot be migrated inline', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, NgModule, ViewChild} from '@angular/core';
|
||||
|
||||
const myOptionsVar = {};
|
||||
|
||||
@Component({template: '<p #myRef></p>'})
|
||||
export class MyComp {
|
||||
@ViewChild('myRef', myOptionsVar) query: any;
|
||||
}
|
||||
|
||||
@NgModule({declarations: [MyComp]})
|
||||
export class MyModule {}
|
||||
`);
|
||||
|
||||
await runMigration();
|
||||
|
||||
expect(tree.readContent('/index.ts'))
|
||||
.toContain(`@ViewChild('myRef', /* TODO: add static flag */ myOptionsVar) query: any;`);
|
||||
expect(warnOutput.length).toBe(1);
|
||||
expect(warnOutput[0])
|
||||
.toMatch(/^⮑ {3}index.ts@8:11: Cannot update query declaration to explicit timing./);
|
||||
expect(warnOutput[0]).toMatch(/Please manually set the query timing to.*static: true/);
|
||||
});
|
||||
|
||||
it('should not normalize stylesheets which are referenced in component', async() => {
|
||||
writeFile('sub_dir/index.ts', `
|
||||
import {Component, NgModule, ContentChild} from '@angular/core';
|
||||
@ -533,7 +558,7 @@ describe('static-queries migration with template strategy', () => {
|
||||
writeFile('/src/test.ts', `
|
||||
import {ViewChild} from '@angular/core';
|
||||
import {AppComponent} from './app.component';
|
||||
|
||||
|
||||
@Component({template: '<span #test>Test</span>'})
|
||||
class MyTestComponent {
|
||||
@ViewChild('test') query: any;
|
||||
@ -542,7 +567,7 @@ describe('static-queries migration with template strategy', () => {
|
||||
|
||||
writeFile('/src/app.component.ts', `
|
||||
import {Component, ViewChild} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class AppComponent {
|
||||
@ViewChild('test') query: any;
|
||||
@ -552,7 +577,7 @@ describe('static-queries migration with template strategy', () => {
|
||||
writeFile('/src/app.module.ts', `
|
||||
import {NgModule} from '@angular/core';
|
||||
import {AppComponent} from './app.component';
|
||||
|
||||
|
||||
@NgModule({declarations: [AppComponent]})
|
||||
export class MyModule {}
|
||||
`);
|
||||
|
@ -26,7 +26,7 @@ describe('static-queries migration with usage strategy', () => {
|
||||
afterAll(() => process.env['NG_STATIC_QUERY_USAGE_STRATEGY'] = '');
|
||||
|
||||
beforeEach(() => {
|
||||
runner = new SchematicTestRunner('test', require.resolve('../migrations.json'));
|
||||
runner = new SchematicTestRunner('test', require.resolve('../test-migrations.json'));
|
||||
host = new TempScopedNodeJsSyncHost();
|
||||
tree = new UnitTestTree(new HostTree(host));
|
||||
|
||||
@ -58,11 +58,11 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should mark view queries used in "ngAfterContentInit" as static', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ViewChild} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@ViewChild('test') query: any;
|
||||
|
||||
|
||||
ngAfterContentInit() {
|
||||
this.query.classList.add('test');
|
||||
}
|
||||
@ -78,11 +78,11 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should mark view queries used in "ngAfterContentChecked" as static', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ViewChild} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@ViewChild('test') query: any;
|
||||
|
||||
|
||||
ngAfterContentChecked() {
|
||||
this.query.classList.add('test');
|
||||
}
|
||||
@ -102,11 +102,11 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should not mark content queries used in "ngAfterContentInit" as static', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ContentChild} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@ContentChild('test') query: any;
|
||||
|
||||
|
||||
ngAfterContentInit() {
|
||||
this.query.classList.add('test');
|
||||
}
|
||||
@ -122,11 +122,11 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should not mark content queries used in "ngAfterContentChecked" as static', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ContentChild} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@ContentChild('test') query: any;
|
||||
|
||||
|
||||
ngAfterContentChecked() {
|
||||
this.query.classList.add('test');
|
||||
}
|
||||
@ -145,19 +145,19 @@ describe('static-queries migration with usage strategy', () => {
|
||||
}
|
||||
|
||||
async function runMigration() {
|
||||
await runner.runSchematicAsync('migration-v8-static-queries', {}, tree).toPromise();
|
||||
await runner.runSchematicAsync('migration-static-queries', {}, tree).toPromise();
|
||||
}
|
||||
|
||||
function createQueryTests(queryType: 'ViewChild' | 'ContentChild') {
|
||||
it('should mark queries as dynamic', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@${queryType}('test') unused: any;
|
||||
@${queryType}('dynamic') dynamic: any;
|
||||
|
||||
|
||||
onClick() {
|
||||
this.dynamicQuery.classList.add('test');
|
||||
}
|
||||
@ -175,13 +175,13 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should mark queries used in "ngOnChanges" as static', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@${queryType}('test') query: any;
|
||||
|
||||
|
||||
ngOnChanges() {
|
||||
this.query.classList.add('test');
|
||||
this.query.classList.add('test');
|
||||
}
|
||||
}
|
||||
`);
|
||||
@ -195,13 +195,13 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should mark queries used in "ngOnInit" as static', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@${queryType}('test') query: any;
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.query.classList.add('test');
|
||||
this.query.classList.add('test');
|
||||
}
|
||||
}
|
||||
`);
|
||||
@ -215,13 +215,13 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should mark queries used in "ngDoCheck" as static', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@${queryType}('test') query: any;
|
||||
|
||||
|
||||
ngDoCheck() {
|
||||
this.query.classList.add('test');
|
||||
this.query.classList.add('test');
|
||||
}
|
||||
}
|
||||
`);
|
||||
@ -235,11 +235,11 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should keep existing query options when updating timing', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@${queryType}('test', { /* test */ read: null }) query: any;
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.query.classList.add('test');
|
||||
}
|
||||
@ -255,7 +255,7 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should not overwrite existing explicit query timing', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@${queryType}('test', {static: /* untouched */ someVal}) query: any;
|
||||
@ -271,26 +271,26 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect queries used in deep method chain', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
// We intentionally add this comma for the second parameter in order
|
||||
// to ensure that the migration does not incorrectly create an invalid
|
||||
// decorator call with three parameters. e.g. "ViewQuery('test', {...}, )"
|
||||
@${queryType}('test', ) query: any;
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.a();
|
||||
}
|
||||
|
||||
|
||||
a() {
|
||||
this.b();
|
||||
}
|
||||
|
||||
|
||||
b() {
|
||||
this.c();
|
||||
}
|
||||
|
||||
|
||||
c() {
|
||||
console.log(this.query);
|
||||
}
|
||||
@ -306,16 +306,16 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should properly exit if recursive function is analyzed', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@${queryType}('test') query: any;
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.recursive();
|
||||
}
|
||||
|
||||
recursive() {
|
||||
|
||||
recursive() {
|
||||
this.recursive();
|
||||
}
|
||||
}
|
||||
@ -330,27 +330,27 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect queries used in newly instantiated classes', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@${queryType}('test') query: any;
|
||||
@${queryType}('test') query2: any;
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
new A(this);
|
||||
|
||||
|
||||
new class Inline {
|
||||
constructor(private ctx: MyComp) {
|
||||
this.a();
|
||||
}
|
||||
|
||||
|
||||
a() {
|
||||
this.ctx.query2.useStatically();
|
||||
}
|
||||
}(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class A {
|
||||
constructor(ctx: MyComp) {
|
||||
ctx.query.test();
|
||||
@ -369,16 +369,16 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect queries used in parenthesized new expressions', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@${queryType}('test') query: any;
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
new ((A))(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class A {
|
||||
constructor(ctx: MyComp) {
|
||||
ctx.query.test();
|
||||
@ -395,11 +395,11 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect queries in lifecycle hook with string literal name', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@${queryType}('test') query: any;
|
||||
|
||||
|
||||
'ngOnInit'() {
|
||||
this.query.test();
|
||||
}
|
||||
@ -415,19 +415,19 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect static queries within nested inheritance', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@${queryType}('test') query: any;
|
||||
}
|
||||
|
||||
|
||||
export class A extends MyComp {}
|
||||
export class B extends A {
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.query.testFn();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
`);
|
||||
|
||||
@ -440,11 +440,11 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect static queries used within input setters', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, Input, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@${queryType}('test') query: any;
|
||||
|
||||
|
||||
@Input()
|
||||
get myVal() { return null; }
|
||||
set myVal(newVal: any) {
|
||||
@ -462,14 +462,14 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect inputs defined in metadata', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
template: '<span #test></span>',
|
||||
inputs: ["myVal"],
|
||||
})
|
||||
export class MyComp {
|
||||
@${queryType}('test') query: any;
|
||||
|
||||
|
||||
// We don't use the input decorator here as we want to verify
|
||||
// that it properly detects the input through the component metadata.
|
||||
get myVal() { return null; }
|
||||
@ -488,14 +488,14 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect aliased inputs declared in metadata', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
template: '<span #test></span>',
|
||||
inputs: ['prop: publicName'],
|
||||
})
|
||||
export class MyComp {
|
||||
@${queryType}('test') query: any;
|
||||
|
||||
|
||||
set prop(val: any) {
|
||||
this.query.test();
|
||||
}
|
||||
@ -511,11 +511,11 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should not mark query as static if query is used in non-input setter', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@${queryType}('test') query: any;
|
||||
|
||||
|
||||
set myProperty(val: any) {
|
||||
this.query.test();
|
||||
}
|
||||
@ -531,13 +531,13 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect input decorator on setter', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Input, Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@${queryType}('test') query: any;
|
||||
|
||||
|
||||
get myProperty() { return null; }
|
||||
|
||||
|
||||
// Usually the decorator is set on the get accessor, but it's also possible
|
||||
// to declare the input on the setter. This ensures that it is handled properly.
|
||||
@Input()
|
||||
@ -556,7 +556,7 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect setter inputs in derived classes', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
template: '<span #test></span>',
|
||||
inputs: ['childSetter'],
|
||||
@ -564,7 +564,7 @@ describe('static-queries migration with usage strategy', () => {
|
||||
export class MyComp {
|
||||
protected @${queryType}('test') query: any;
|
||||
}
|
||||
|
||||
|
||||
export class B extends MyComp {
|
||||
set childSetter(newVal: any) {
|
||||
this.query.test();
|
||||
@ -581,7 +581,7 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should properly detect static query in external derived class', async() => {
|
||||
writeFile('/src/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@${queryType}('test') query: any;
|
||||
@ -590,7 +590,7 @@ describe('static-queries migration with usage strategy', () => {
|
||||
|
||||
writeFile('/src/external.ts', `
|
||||
import {MyComp} from './index';
|
||||
|
||||
|
||||
export class ExternalComp extends MyComp {
|
||||
ngOnInit() {
|
||||
this.query.test();
|
||||
@ -614,30 +614,30 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should not mark queries used in promises as static', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
private @${queryType}('test') query: any;
|
||||
private @${queryType}('test') query2: any;
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
const a = Promise.resolve();
|
||||
|
||||
|
||||
Promise.resolve().then(() => {
|
||||
this.query.doSomething();
|
||||
});
|
||||
|
||||
|
||||
Promise.reject().catch(() => {
|
||||
this.query.doSomething();
|
||||
});
|
||||
|
||||
|
||||
a.then(() => {}).then(() => {
|
||||
this.query.doSomething();
|
||||
});
|
||||
|
||||
|
||||
Promise.resolve().then(this.createPromiseCb());
|
||||
}
|
||||
|
||||
|
||||
createPromiseCb() {
|
||||
this.query2.doSomething();
|
||||
return () => { /* empty callback */}
|
||||
@ -656,19 +656,19 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should handle function callbacks which statically access queries', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
private @${queryType}('test') query: any;
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
ngOnInit() {
|
||||
this.callSync(() => this.query.doSomething());
|
||||
}
|
||||
|
||||
|
||||
callSync(cb: Function) {
|
||||
this.callSync2(cb);
|
||||
}
|
||||
|
||||
|
||||
callSync2(cb: Function) {
|
||||
cb();
|
||||
}
|
||||
@ -686,12 +686,12 @@ describe('static-queries migration with usage strategy', () => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
import {External} from './external';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
private @${queryType}('test') query: any;
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
ngOnInit() {
|
||||
new External(() => this.query.doSomething());
|
||||
}
|
||||
}
|
||||
@ -700,7 +700,7 @@ describe('static-queries migration with usage strategy', () => {
|
||||
writeFile('/external.ts', `
|
||||
export class External {
|
||||
constructor(cb: () => void) {
|
||||
// Add extra parentheses to ensure that expression is unwrapped.
|
||||
// Add extra parentheses to ensure that expression is unwrapped.
|
||||
((cb))();
|
||||
}
|
||||
}
|
||||
@ -715,21 +715,21 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should handle nested functions with arguments from parent closure', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
private @${queryType}('test') query: any;
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
ngOnInit() {
|
||||
this.callSync(() => this.query.doSomething());
|
||||
}
|
||||
|
||||
|
||||
callSync(cb: Function) {
|
||||
function callSyncNested() {
|
||||
// The "cb" identifier comes from the "callSync" function.
|
||||
cb();
|
||||
}
|
||||
|
||||
|
||||
callSyncNested();
|
||||
}
|
||||
}
|
||||
@ -744,22 +744,22 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should not mark queries used in setTimeout as static', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
private @${queryType}('test') query: any;
|
||||
private @${queryType}('test') query2: any;
|
||||
private @${queryType}('test') query3: any;
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
setTimeout(function() {
|
||||
this.query.doSomething();
|
||||
});
|
||||
|
||||
|
||||
setTimeout(createCallback(this));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function createCallback(instance: MyComp) {
|
||||
instance.query2.doSomething();
|
||||
return () => instance.query3.doSomething();
|
||||
@ -779,13 +779,13 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should not mark queries used in "addEventListener" as static', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ElementRef, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
private @${queryType}('test') query: any;
|
||||
|
||||
|
||||
constructor(private elementRef: ElementRef) {}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.elementRef.addEventListener(() => {
|
||||
this.query.classList.add('test');
|
||||
@ -803,13 +803,13 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should not mark queries used in "requestAnimationFrame" as static', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ElementRef, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
private @${queryType}('test') query: any;
|
||||
|
||||
|
||||
constructor(private elementRef: ElementRef) {}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
requestAnimationFrame(() => {
|
||||
this.query.classList.add('test');
|
||||
@ -827,17 +827,17 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should mark queries used in immediately-invoked function expression as static', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
private @${queryType}('test') query: any;
|
||||
private @${queryType}('test') query2: any;
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
(() => {
|
||||
this.query.usedStatically();
|
||||
})();
|
||||
|
||||
|
||||
(function(ctx) {
|
||||
ctx.query2.useStatically();
|
||||
})(this);
|
||||
@ -857,11 +857,11 @@ describe('static-queries migration with usage strategy', () => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
import {externalFn} from './external';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
private @${queryType}('test') query: any;
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
externalFn(this);
|
||||
}
|
||||
@ -870,7 +870,7 @@ describe('static-queries migration with usage strategy', () => {
|
||||
|
||||
writeFile('/external.ts', `
|
||||
import {MyComp} from './index';
|
||||
|
||||
|
||||
export function externalFn(ctx: MyComp) {
|
||||
ctx.query.usedStatically();
|
||||
}
|
||||
@ -885,15 +885,15 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect static queries used through getter property access', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
private @${queryType}('test') query: any;
|
||||
|
||||
|
||||
get myProp() {
|
||||
return this.query.myValue;
|
||||
}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.myProp.test();
|
||||
}
|
||||
@ -910,17 +910,17 @@ describe('static-queries migration with usage strategy', () => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
import {External} from './external';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
@${queryType}('test') query: any;
|
||||
|
||||
|
||||
private external = new External(this);
|
||||
|
||||
|
||||
get myProp() {
|
||||
return this.query.myValue;
|
||||
}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
console.log(this.external.query);
|
||||
}
|
||||
@ -929,10 +929,10 @@ describe('static-queries migration with usage strategy', () => {
|
||||
|
||||
writeFile('/external.ts', `
|
||||
import {MyComp} from './index';
|
||||
|
||||
|
||||
export class External {
|
||||
constructor(private comp: MyComp) {}
|
||||
|
||||
|
||||
set query() { /** noop */ }
|
||||
get query() { return this.comp.query; }
|
||||
}
|
||||
@ -947,16 +947,16 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should not mark queries as static if a value is assigned to accessor property', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
private @${queryType}('test') query: any;
|
||||
|
||||
|
||||
set myProp(value: any) { /* noop */}
|
||||
get myProp() {
|
||||
return this.query.myValue;
|
||||
}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.myProp = true;
|
||||
}
|
||||
@ -972,16 +972,16 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should mark queries as static if non-input setter uses query', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
private @${queryType}('test') query: any;
|
||||
|
||||
|
||||
get myProp() { return null; }
|
||||
set myProp(value: any) {
|
||||
this.query.doSomething();
|
||||
}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.myProp = 'newValue';
|
||||
}
|
||||
@ -997,17 +997,17 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should check setter and getter when using compound assignment', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
private @${queryType}('test') query: any;
|
||||
private @${queryType}('test') query2: any;
|
||||
|
||||
|
||||
get myProp() { return this.query2 }
|
||||
set myProp(value: any) {
|
||||
this.query.doSomething();
|
||||
}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.myProp *= 5;
|
||||
}
|
||||
@ -1025,14 +1025,14 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should check getters when using comparison operator in binary expression', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
private @${queryType}('test') query: any;
|
||||
|
||||
|
||||
get myProp() { return this.query }
|
||||
set myProp(value: any) { /* noop */ }
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
if (this.myProp === 3) {
|
||||
// noop
|
||||
@ -1050,29 +1050,29 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should check derived abstract class methods', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
export abstract class RootBaseClass {
|
||||
abstract getQuery(): any;
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.getQuery().doSomething();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export abstract class BaseClass extends RootBaseClass {
|
||||
abstract getQuery2(): any;
|
||||
|
||||
|
||||
getQuery() {
|
||||
this.getQuery2();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class Subclass extends BaseClass {
|
||||
@${queryType}('test') query: any;
|
||||
|
||||
|
||||
getQuery2(): any {
|
||||
return this.query;
|
||||
return this.query;
|
||||
}
|
||||
}
|
||||
`);
|
||||
@ -1086,25 +1086,25 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect queries accessed through deep abstract class method', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
export abstract class RootBaseClass {
|
||||
abstract getQuery(): any;
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.getQuery().doSomething();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export abstract class BaseClass extends RootBaseClass {
|
||||
/* additional layer of indirection */
|
||||
}
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class Subclass extends BaseClass {
|
||||
@${queryType}('test') query: any;
|
||||
|
||||
|
||||
getQuery(): any {
|
||||
return this.query;
|
||||
return this.query;
|
||||
}
|
||||
}
|
||||
`);
|
||||
@ -1118,19 +1118,19 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect queries accessed through abstract property getter', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
export abstract class BaseClass {
|
||||
abstract myQuery: any;
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.myQuery.doSomething();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class Subclass extends BaseClass {
|
||||
@${queryType}('test') query: any;
|
||||
|
||||
|
||||
get myQuery() { return this.query; }
|
||||
}
|
||||
`);
|
||||
@ -1144,19 +1144,19 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect queries accessed through abstract property setter', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
export abstract class BaseClass {
|
||||
abstract myQuery: any;
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.myQuery = "trigger";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class Subclass extends BaseClass {
|
||||
@${queryType}('test') query: any;
|
||||
|
||||
|
||||
set myQuery(val: any) { this.query.doSomething() }
|
||||
get myQuery() { /* noop */ }
|
||||
}
|
||||
@ -1171,27 +1171,27 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect query usage in abstract class methods accessing inherited query', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
export abstract class RootBaseClass {
|
||||
abstract getQuery(): any;
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.getQuery().doSomething();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export abstract class BaseClass extends RootBaseClass {
|
||||
@${queryType}('test') query: any;
|
||||
abstract getQuery2(): any;
|
||||
|
||||
|
||||
getQuery() {
|
||||
this.getQuery2();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class Subclass extends BaseClass {
|
||||
|
||||
|
||||
getQuery2(): any {
|
||||
return this.query;
|
||||
}
|
||||
@ -1207,7 +1207,7 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect query usage within component template', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({templateUrl: 'my-template.html'})
|
||||
export class MyComponent {
|
||||
@${queryType}('test') query: any;
|
||||
@ -1228,7 +1228,7 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect query usage with nested property read within component template', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({templateUrl: 'my-template.html'})
|
||||
export class MyComponent {
|
||||
@${queryType}('test') query: any;
|
||||
@ -1250,7 +1250,7 @@ describe('static-queries migration with usage strategy', () => {
|
||||
async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({templateUrl: 'my-template.html'})
|
||||
export class MyComponent {
|
||||
@${queryType}('test') query: any;
|
||||
@ -1274,7 +1274,7 @@ describe('static-queries migration with usage strategy', () => {
|
||||
async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({templateUrl: 'my-template.html'})
|
||||
export class MyComponent {
|
||||
myObject: {someProp: any};
|
||||
@ -1299,7 +1299,7 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should ignore queries accessed within <ng-template> element', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({templateUrl: 'my-template.html'})
|
||||
export class MyComponent {
|
||||
@${queryType}('test') query: any;
|
||||
@ -1308,7 +1308,7 @@ describe('static-queries migration with usage strategy', () => {
|
||||
|
||||
writeFile(`/my-template.html`, `
|
||||
<foo #test></foo>
|
||||
|
||||
|
||||
<ng-template>
|
||||
<my-comp [myInput]="query"></my-comp>
|
||||
</ng-template>
|
||||
@ -1323,11 +1323,11 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should detect inherited queries used in templates', async() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
export class ParentClass {
|
||||
@${queryType}('test') query: any;
|
||||
}
|
||||
|
||||
|
||||
@Component({templateUrl: 'my-template.html'})
|
||||
export class MyComponent extends ParentClass {}
|
||||
`);
|
||||
@ -1346,7 +1346,7 @@ describe('static-queries migration with usage strategy', () => {
|
||||
it('should properly handle multiple tsconfig files', async() => {
|
||||
writeFile('/src/index.ts', `
|
||||
import {Component, ${queryType}} from '@angular/core';
|
||||
|
||||
|
||||
@Component({template: '<span #test></span>'})
|
||||
export class MyComp {
|
||||
private @${queryType}('test') query: any;
|
||||
|
@ -21,7 +21,7 @@ describe('template variable assignment migration', () => {
|
||||
let warnOutput: string[];
|
||||
|
||||
beforeEach(() => {
|
||||
runner = new SchematicTestRunner('test', require.resolve('../migrations.json'));
|
||||
runner = new SchematicTestRunner('test', require.resolve('../test-migrations.json'));
|
||||
host = new TempScopedNodeJsSyncHost();
|
||||
tree = new UnitTestTree(new HostTree(host));
|
||||
|
||||
@ -58,14 +58,12 @@ describe('template variable assignment migration', () => {
|
||||
host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents));
|
||||
}
|
||||
|
||||
function runMigration() {
|
||||
runner.runSchematic('migration-v8-template-local-variables', {}, tree);
|
||||
}
|
||||
function runMigration() { runner.runSchematic('migration-template-local-variables', {}, tree); }
|
||||
|
||||
it('should warn for two-way data binding variable assignment', () => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
template: '<cmp *ngFor="let optionName of options" [(opt)]="optionName"></cmp>',
|
||||
})
|
||||
@ -81,7 +79,7 @@ describe('template variable assignment migration', () => {
|
||||
it('should warn for two-way data binding assigning to "as" variable', () => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: './tmpl.html',
|
||||
})
|
||||
@ -103,7 +101,7 @@ describe('template variable assignment migration', () => {
|
||||
it('should warn for bound event assignments to "as" variable', () => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: './sub_dir/tmpl.html',
|
||||
})
|
||||
@ -127,7 +125,7 @@ describe('template variable assignment migration', () => {
|
||||
it('should warn for bound event assignments to template "let" variables', () => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: './sub_dir/tmpl.html',
|
||||
})
|
||||
@ -151,7 +149,7 @@ describe('template variable assignment migration', () => {
|
||||
it('should not warn for bound event assignments to component property', () => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: './sub_dir/tmpl.html',
|
||||
})
|
||||
@ -168,7 +166,7 @@ describe('template variable assignment migration', () => {
|
||||
it('should not warn for bound event assignments to template variable object property', () => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: './sub_dir/tmpl.html',
|
||||
})
|
||||
@ -188,7 +186,7 @@ describe('template variable assignment migration', () => {
|
||||
() => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: './sub_dir/tmpl.html',
|
||||
})
|
||||
@ -213,7 +211,7 @@ describe('template variable assignment migration', () => {
|
||||
it('should not warn for property writes with template variable name but different scope', () => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: './sub_dir/tmpl.html',
|
||||
})
|
||||
@ -236,7 +234,7 @@ describe('template variable assignment migration', () => {
|
||||
it('should not throw an error if a detected template fails parsing', () => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: './sub_dir/tmpl.html',
|
||||
})
|
||||
@ -253,12 +251,12 @@ describe('template variable assignment migration', () => {
|
||||
it('should be able to report multiple templates within the same source file', () => {
|
||||
writeFile('/index.ts', `
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
template: '<ng-template let-one><a (sayHello)="one=true"></a></ng-template>',
|
||||
})
|
||||
export class MyComp {}
|
||||
|
||||
|
||||
@Component({
|
||||
template: '<ng-template let-two><b (greet)="two=true"></b></ng-template>',
|
||||
})
|
||||
|
@ -71,10 +71,23 @@ export function injectInjectorOnly<T>(
|
||||
/**
|
||||
* Generated instruction: Injects a token from the currently active injector.
|
||||
*
|
||||
* WARNING: This function is meant to be generated by the Ivy compiler, and is not meant for
|
||||
* developer consumption!
|
||||
* Must be used in the context of a factory function such as one defined for an
|
||||
* `InjectionToken`. Throws an error if not called from such a context.
|
||||
*
|
||||
* https://github.com/angular/angular/blob/master/packages/core/src/render3/DELTA_INSTRUCTIONS.md
|
||||
* (Additional documentation moved to `inject`, as it is the public API, and an alias for this instruction)
|
||||
*
|
||||
* @see inject
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵinject<T>(token: Type<T>| InjectionToken<T>): T;
|
||||
export function ɵɵinject<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags): T|null;
|
||||
export function ɵɵinject<T>(token: Type<T>| InjectionToken<T>, flags = InjectFlags.Default): T|
|
||||
null {
|
||||
return (_injectImplementation || injectInjectorOnly)(token, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects a token from the currently active injector.
|
||||
*
|
||||
* Must be used in the context of a factory function such as one defined for an
|
||||
* `InjectionToken`. Throws an error if not called from such a context.
|
||||
@ -97,17 +110,6 @@ export function injectInjectorOnly<T>(
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export function ɵɵinject<T>(token: Type<T>| InjectionToken<T>): T;
|
||||
export function ɵɵinject<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags): T|null;
|
||||
export function ɵɵinject<T>(token: Type<T>| InjectionToken<T>, flags = InjectFlags.Default): T|
|
||||
null {
|
||||
return (_injectImplementation || injectInjectorOnly)(token, flags);
|
||||
}
|
||||
/**
|
||||
* @deprecated in v8, delete after v10. This API should be used only be generated code, and that
|
||||
* code should now use ɵɵinject instead.
|
||||
* @publicApi
|
||||
*/
|
||||
export const inject = ɵɵinject;
|
||||
|
||||
/**
|
||||
|
@ -110,6 +110,8 @@ function listenerInternal(
|
||||
ngDevMode && assertNodeOfPossibleTypes(
|
||||
tNode, TNodeType.Element, TNodeType.Container, TNodeType.ElementContainer);
|
||||
|
||||
let processOutputs = true;
|
||||
|
||||
// add native event listener - applicable to elements only
|
||||
if (tNode.type === TNodeType.Element) {
|
||||
const native = getNativeByTNode(tNode, lView) as RElement;
|
||||
@ -149,6 +151,7 @@ function listenerInternal(
|
||||
// Attach a new listener at the head of the coalesced listeners list.
|
||||
(<any>listenerFn).__ngNextListenerFn__ = (<any>existingListener).__ngNextListenerFn__;
|
||||
(<any>existingListener).__ngNextListenerFn__ = listenerFn;
|
||||
processOutputs = false;
|
||||
} else {
|
||||
// The first argument of `listen` function in Procedural Renderer is:
|
||||
// - either a target name (as a string) in case of global target (window, document, body)
|
||||
@ -180,7 +183,7 @@ function listenerInternal(
|
||||
|
||||
const outputs = tNode.outputs;
|
||||
let props: PropertyAliasValue|undefined;
|
||||
if (outputs && (props = outputs[eventName])) {
|
||||
if (processOutputs && outputs && (props = outputs[eventName])) {
|
||||
const propsLength = props.length;
|
||||
if (propsLength) {
|
||||
const lCleanup = getCleanup(lView);
|
||||
|
@ -7,6 +7,7 @@
|
||||
*/
|
||||
import {assertEqual, assertLessThan} from '../../util/assert';
|
||||
import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4} from '../bindings';
|
||||
import {SanitizerFn} from '../interfaces/sanitization';
|
||||
import {BINDING_INDEX, TVIEW} from '../interfaces/view';
|
||||
import {getLView, getSelectedIndex} from '../state';
|
||||
import {NO_CHANGE} from '../tokens';
|
||||
@ -15,6 +16,7 @@ import {renderStringify} from '../util/misc_utils';
|
||||
import {TsickleIssue1009, elementPropertyInternal, storeBindingMetadata} from './shared';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create interpolation bindings with a variable number of expressions.
|
||||
*
|
||||
@ -290,12 +292,6 @@ export function ɵɵinterpolation8(
|
||||
/// NEW INSTRUCTIONS
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Shared reference to a string, used in `ɵɵpropertyInterpolate`.
|
||||
*/
|
||||
const EMPTY_STRING = '';
|
||||
|
||||
/**
|
||||
*
|
||||
* Update an interpolated property on an element with a lone bound value
|
||||
@ -321,11 +317,13 @@ const EMPTY_STRING = '';
|
||||
* @param prefix Static value used for concatenation only.
|
||||
* @param v0 Value checked for change.
|
||||
* @param suffix Static value used for concatenation only.
|
||||
* @param sanitizer An optional sanitizer function
|
||||
* @returns itself, so that it may be chained.
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵpropertyInterpolate(propName: string, v0: any): TsickleIssue1009 {
|
||||
ɵɵpropertyInterpolate1(propName, EMPTY_STRING, v0, EMPTY_STRING);
|
||||
export function ɵɵpropertyInterpolate(
|
||||
propName: string, v0: any, sanitizer?: SanitizerFn): TsickleIssue1009 {
|
||||
ɵɵpropertyInterpolate1(propName, '', v0, '', sanitizer);
|
||||
return ɵɵpropertyInterpolate;
|
||||
}
|
||||
|
||||
@ -354,13 +352,15 @@ export function ɵɵpropertyInterpolate(propName: string, v0: any): TsickleIssue
|
||||
* @param prefix Static value used for concatenation only.
|
||||
* @param v0 Value checked for change.
|
||||
* @param suffix Static value used for concatenation only.
|
||||
* @param sanitizer An optional sanitizer function
|
||||
* @returns itself, so that it may be chained.
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵpropertyInterpolate1(
|
||||
propName: string, prefix: string, v0: any, suffix: string): TsickleIssue1009 {
|
||||
propName: string, prefix: string, v0: any, suffix: string,
|
||||
sanitizer?: SanitizerFn): TsickleIssue1009 {
|
||||
const index = getSelectedIndex();
|
||||
elementPropertyInternal(index, propName, ɵɵinterpolation1(prefix, v0, suffix));
|
||||
elementPropertyInternal(index, propName, ɵɵinterpolation1(prefix, v0, suffix), sanitizer);
|
||||
return ɵɵpropertyInterpolate1;
|
||||
}
|
||||
|
||||
@ -390,14 +390,15 @@ export function ɵɵpropertyInterpolate1(
|
||||
* @param i0 Static value used for concatenation only.
|
||||
* @param v1 Value checked for change.
|
||||
* @param suffix Static value used for concatenation only.
|
||||
* @param sanitizer An optional sanitizer function
|
||||
* @returns itself, so that it may be chained.
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵpropertyInterpolate2(
|
||||
propName: string, prefix: string, v0: any, i0: string, v1: any,
|
||||
suffix: string): TsickleIssue1009 {
|
||||
propName: string, prefix: string, v0: any, i0: string, v1: any, suffix: string,
|
||||
sanitizer?: SanitizerFn): TsickleIssue1009 {
|
||||
const index = getSelectedIndex();
|
||||
elementPropertyInternal(index, propName, ɵɵinterpolation2(prefix, v0, i0, v1, suffix));
|
||||
elementPropertyInternal(index, propName, ɵɵinterpolation2(prefix, v0, i0, v1, suffix), sanitizer);
|
||||
return ɵɵpropertyInterpolate2;
|
||||
}
|
||||
|
||||
@ -430,14 +431,16 @@ export function ɵɵpropertyInterpolate2(
|
||||
* @param i1 Static value used for concatenation only.
|
||||
* @param v2 Value checked for change.
|
||||
* @param suffix Static value used for concatenation only.
|
||||
* @param sanitizer An optional sanitizer function
|
||||
* @returns itself, so that it may be chained.
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵpropertyInterpolate3(
|
||||
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any,
|
||||
suffix: string): TsickleIssue1009 {
|
||||
suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009 {
|
||||
const index = getSelectedIndex();
|
||||
elementPropertyInternal(index, propName, ɵɵinterpolation3(prefix, v0, i0, v1, i1, v2, suffix));
|
||||
elementPropertyInternal(
|
||||
index, propName, ɵɵinterpolation3(prefix, v0, i0, v1, i1, v2, suffix), sanitizer);
|
||||
return ɵɵpropertyInterpolate3;
|
||||
}
|
||||
|
||||
@ -472,15 +475,16 @@ export function ɵɵpropertyInterpolate3(
|
||||
* @param i2 Static value used for concatenation only.
|
||||
* @param v3 Value checked for change.
|
||||
* @param suffix Static value used for concatenation only.
|
||||
* @param sanitizer An optional sanitizer function
|
||||
* @returns itself, so that it may be chained.
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵpropertyInterpolate4(
|
||||
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
|
||||
v3: any, suffix: string): TsickleIssue1009 {
|
||||
v3: any, suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009 {
|
||||
const index = getSelectedIndex();
|
||||
elementPropertyInternal(
|
||||
index, propName, ɵɵinterpolation4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix));
|
||||
index, propName, ɵɵinterpolation4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix), sanitizer);
|
||||
return ɵɵpropertyInterpolate4;
|
||||
}
|
||||
|
||||
@ -517,15 +521,17 @@ export function ɵɵpropertyInterpolate4(
|
||||
* @param i3 Static value used for concatenation only.
|
||||
* @param v4 Value checked for change.
|
||||
* @param suffix Static value used for concatenation only.
|
||||
* @param sanitizer An optional sanitizer function
|
||||
* @returns itself, so that it may be chained.
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵpropertyInterpolate5(
|
||||
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
|
||||
v3: any, i3: string, v4: any, suffix: string): TsickleIssue1009 {
|
||||
v3: any, i3: string, v4: any, suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009 {
|
||||
const index = getSelectedIndex();
|
||||
elementPropertyInternal(
|
||||
index, propName, ɵɵinterpolation5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix));
|
||||
index, propName, ɵɵinterpolation5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix),
|
||||
sanitizer);
|
||||
return ɵɵpropertyInterpolate5;
|
||||
}
|
||||
|
||||
@ -564,16 +570,18 @@ export function ɵɵpropertyInterpolate5(
|
||||
* @param i4 Static value used for concatenation only.
|
||||
* @param v5 Value checked for change.
|
||||
* @param suffix Static value used for concatenation only.
|
||||
* @param sanitizer An optional sanitizer function
|
||||
* @returns itself, so that it may be chained.
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵpropertyInterpolate6(
|
||||
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
|
||||
v3: any, i3: string, v4: any, i4: string, v5: any, suffix: string): TsickleIssue1009 {
|
||||
v3: any, i3: string, v4: any, i4: string, v5: any, suffix: string,
|
||||
sanitizer?: SanitizerFn): TsickleIssue1009 {
|
||||
const index = getSelectedIndex();
|
||||
elementPropertyInternal(
|
||||
index, propName,
|
||||
ɵɵinterpolation6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix));
|
||||
index, propName, ɵɵinterpolation6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix),
|
||||
sanitizer);
|
||||
return ɵɵpropertyInterpolate6;
|
||||
}
|
||||
|
||||
@ -614,17 +622,19 @@ export function ɵɵpropertyInterpolate6(
|
||||
* @param i5 Static value used for concatenation only.
|
||||
* @param v6 Value checked for change.
|
||||
* @param suffix Static value used for concatenation only.
|
||||
* @param sanitizer An optional sanitizer function
|
||||
* @returns itself, so that it may be chained.
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵpropertyInterpolate7(
|
||||
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
|
||||
v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any,
|
||||
suffix: string): TsickleIssue1009 {
|
||||
v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, suffix: string,
|
||||
sanitizer?: SanitizerFn): TsickleIssue1009 {
|
||||
const index = getSelectedIndex();
|
||||
elementPropertyInternal(
|
||||
index, propName,
|
||||
ɵɵinterpolation7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix));
|
||||
ɵɵinterpolation7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix),
|
||||
sanitizer);
|
||||
return ɵɵpropertyInterpolate7;
|
||||
}
|
||||
|
||||
@ -667,17 +677,19 @@ export function ɵɵpropertyInterpolate7(
|
||||
* @param i6 Static value used for concatenation only.
|
||||
* @param v7 Value checked for change.
|
||||
* @param suffix Static value used for concatenation only.
|
||||
* @param sanitizer An optional sanitizer function
|
||||
* @returns itself, so that it may be chained.
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵpropertyInterpolate8(
|
||||
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
|
||||
v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any,
|
||||
suffix: string): TsickleIssue1009 {
|
||||
suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009 {
|
||||
const index = getSelectedIndex();
|
||||
elementPropertyInternal(
|
||||
index, propName,
|
||||
ɵɵinterpolation8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix));
|
||||
ɵɵinterpolation8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix),
|
||||
sanitizer);
|
||||
return ɵɵpropertyInterpolate8;
|
||||
}
|
||||
|
||||
@ -707,12 +719,14 @@ export function ɵɵpropertyInterpolate8(
|
||||
* @param values The a collection of values and the strings inbetween those values, beginning with a
|
||||
* string prefix and ending with a string suffix.
|
||||
* (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
|
||||
* @param sanitizer An optional sanitizer function
|
||||
* @returns itself, so that it may be chained.
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵpropertyInterpolateV(propName: string, values: any[]): TsickleIssue1009 {
|
||||
export function ɵɵpropertyInterpolateV(
|
||||
propName: string, values: any[], sanitizer?: SanitizerFn): TsickleIssue1009 {
|
||||
const index = getSelectedIndex();
|
||||
|
||||
elementPropertyInternal(index, propName, ɵɵinterpolationV(values));
|
||||
elementPropertyInternal(index, propName, ɵɵinterpolationV(values), sanitizer);
|
||||
return ɵɵpropertyInterpolateV;
|
||||
}
|
||||
|
@ -905,15 +905,20 @@ export function setNgReflectProperty(
|
||||
attrName = normalizeDebugBindingName(attrName);
|
||||
const debugValue = normalizeDebugBindingValue(value);
|
||||
if (type === TNodeType.Element) {
|
||||
isProceduralRenderer(renderer) ?
|
||||
renderer.setAttribute((element as RElement), attrName, debugValue) :
|
||||
(element as RElement).setAttribute(attrName, debugValue);
|
||||
} else if (value !== undefined) {
|
||||
const value = `bindings=${JSON.stringify({[attrName]: debugValue}, null, 2)}`;
|
||||
if (isProceduralRenderer(renderer)) {
|
||||
renderer.setValue((element as RComment), value);
|
||||
if (value == null) {
|
||||
isProceduralRenderer(renderer) ? renderer.removeAttribute((element as RElement), attrName) :
|
||||
(element as RElement).removeAttribute(attrName);
|
||||
} else {
|
||||
(element as RComment).textContent = value;
|
||||
isProceduralRenderer(renderer) ?
|
||||
renderer.setAttribute((element as RElement), attrName, debugValue) :
|
||||
(element as RElement).setAttribute(attrName, debugValue);
|
||||
}
|
||||
} else {
|
||||
const textContent = `bindings=${JSON.stringify({[attrName]: debugValue}, null, 2)}`;
|
||||
if (isProceduralRenderer(renderer)) {
|
||||
renderer.setValue((element as RComment), textContent);
|
||||
} else {
|
||||
(element as RComment).textContent = textContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import {Type} from '../../interface/type';
|
||||
import {registerNgModuleType} from '../../linker/ng_module_factory_loader';
|
||||
import {Component} from '../../metadata';
|
||||
import {ModuleWithProviders, NgModule, NgModuleDef, NgModuleTransitiveScopes} from '../../metadata/ng_module';
|
||||
import {flatten} from '../../util/array_utils';
|
||||
import {assertDefined} from '../../util/assert';
|
||||
import {getComponentDef, getDirectiveDef, getNgModuleDef, getPipeDef} from '../definition';
|
||||
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from '../fields';
|
||||
@ -158,6 +159,7 @@ function verifySemanticsOfNgModuleDef(moduleType: NgModuleType): void {
|
||||
const errors: string[] = [];
|
||||
const declarations = maybeUnwrapFn(ngModuleDef.declarations);
|
||||
const imports = maybeUnwrapFn(ngModuleDef.imports);
|
||||
flatten(imports, unwrapModuleWithProvidersImports).forEach(verifySemanticsOfNgModuleDef);
|
||||
const exports = maybeUnwrapFn(ngModuleDef.exports);
|
||||
declarations.forEach(verifyDeclarationsHaveDefinitions);
|
||||
const combinedDeclarations: Type<any>[] = [
|
||||
@ -464,18 +466,6 @@ export function transitiveScopesFor<T>(
|
||||
return scopes;
|
||||
}
|
||||
|
||||
function flatten<T>(values: any[], mapFn?: (value: T) => any): Type<T>[] {
|
||||
const out: Type<T>[] = [];
|
||||
values.forEach(value => {
|
||||
if (Array.isArray(value)) {
|
||||
out.push(...flatten<T>(value, mapFn));
|
||||
} else {
|
||||
out.push(mapFn ? mapFn(value) : value);
|
||||
}
|
||||
});
|
||||
return out;
|
||||
}
|
||||
|
||||
function expandModuleWithProviders(value: Type<any>| ModuleWithProviders<{}>): Type<any> {
|
||||
if (isModuleWithProviders(value)) {
|
||||
return value.ngModule;
|
||||
|
@ -21,7 +21,7 @@ export function addAllToArray(items: any[], arr: any[]) {
|
||||
/**
|
||||
* Flattens an array in non-recursive way. Input arrays are not modified.
|
||||
*/
|
||||
export function flatten(list: any[]): any[] {
|
||||
export function flatten(list: any[], mapFn?: (value: any) => any): any[] {
|
||||
const result: any[] = [];
|
||||
let i = 0;
|
||||
while (i < list.length) {
|
||||
@ -34,7 +34,7 @@ export function flatten(list: any[]): any[] {
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
result.push(item);
|
||||
result.push(mapFn ? mapFn(item) : item);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,9 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component, InjectionToken} from '@angular/core';
|
||||
import {Component, ComponentFactoryResolver, ComponentRef, InjectionToken, NgModule, Type, ViewChild, ViewContainerRef} from '@angular/core';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
|
||||
describe('component', () => {
|
||||
@ -49,4 +50,42 @@ describe('component', () => {
|
||||
expect(destroyCalls).toBe(1, 'Expected `ngOnDestroy` to only be called once.');
|
||||
});
|
||||
});
|
||||
|
||||
it('should support entry components from another module', () => {
|
||||
@Component({selector: 'other-component', template: `bar`})
|
||||
class OtherComponent {
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [OtherComponent],
|
||||
exports: [OtherComponent],
|
||||
entryComponents: [OtherComponent]
|
||||
})
|
||||
class OtherModule {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'test_component',
|
||||
template: `foo|<ng-template #vc></ng-template>`,
|
||||
entryComponents: [OtherComponent]
|
||||
})
|
||||
class TestComponent {
|
||||
@ViewChild('vc', {read: ViewContainerRef}) vcref !: ViewContainerRef;
|
||||
|
||||
constructor(private _cfr: ComponentFactoryResolver) {}
|
||||
|
||||
createComponentView<T>(cmptType: Type<T>): ComponentRef<T> {
|
||||
const cf = this._cfr.resolveComponentFactory(cmptType);
|
||||
return this.vcref.createComponent(cf);
|
||||
}
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [TestComponent], imports: [OtherModule]});
|
||||
const fixture = TestBed.createComponent(TestComponent);
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.componentInstance.createComponentView(OtherComponent);
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('foo|bar');
|
||||
});
|
||||
});
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -135,6 +135,86 @@ describe('exports', () => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('span').innerHTML).toBe('First');
|
||||
});
|
||||
|
||||
describe('forward refs', () => {
|
||||
it('should work with basic text bindings', () => {
|
||||
const fixture = initWithTemplate(AppComp, '{{ myInput.value}} <input value="one" #myInput>');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('one <input value="one">');
|
||||
});
|
||||
|
||||
it('should work with element properties', () => {
|
||||
const fixture = initWithTemplate(
|
||||
AppComp, '<div [title]="myInput.value"></div> <input value="one" #myInput>');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('<div title="one"></div><input value="one">');
|
||||
});
|
||||
|
||||
it('should work with element attrs', () => {
|
||||
const fixture = initWithTemplate(
|
||||
AppComp, '<div [attr.aria-label]="myInput.value"></div> <input value="one" #myInput>');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.innerHTML)
|
||||
.toEqual('<div aria-label="one"></div><input value="one">');
|
||||
});
|
||||
|
||||
it('should work with element classes', () => {
|
||||
const fixture = initWithTemplate(
|
||||
AppComp,
|
||||
'<div [class.red]="myInput.checked"></div> <input type="checkbox" checked #myInput>');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.innerHTML).toContain('<div class="red"></div>');
|
||||
});
|
||||
|
||||
it('should work with component refs', () => {
|
||||
const fixture = initWithTemplate(
|
||||
AppComp, '<div [dirWithInput]="myComp"></div><comp-to-ref #myComp></comp-to-ref>');
|
||||
fixture.detectChanges();
|
||||
|
||||
const dirWithInput = fixture.debugElement.children[0].injector.get(DirWithCompInput);
|
||||
const myComp = fixture.debugElement.children[1].injector.get(ComponentToReference);
|
||||
|
||||
expect(dirWithInput.comp).toEqual(myComp);
|
||||
});
|
||||
|
||||
it('should work with multiple forward refs', () => {
|
||||
const fixture = initWithTemplate(
|
||||
AppComp,
|
||||
'{{ myInput.value }} {{ myComp.name }} <comp-to-ref #myComp></comp-to-ref> <input value="one" #myInput>');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.innerHTML)
|
||||
.toEqual('one Nancy <comp-to-ref></comp-to-ref><input value="one">');
|
||||
});
|
||||
|
||||
it('should support local refs in nested dynamic views', () => {
|
||||
const fixture = initWithTemplate(AppComp, `
|
||||
<input value="one" #outerInput>
|
||||
<div *ngIf="outer">
|
||||
{{ outerInput.value }}
|
||||
<input value = "two" #innerInput>
|
||||
<div *ngIf="inner">
|
||||
{{ outerInput.value }} - {{ innerInput.value}}
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
fixture.detectChanges();
|
||||
fixture.componentInstance.outer = true;
|
||||
fixture.componentInstance.inner = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
// result should be <input value="one"><div>one <input value="two"><div>one - two</div></div>
|
||||
// but contains bindings comments for ngIf
|
||||
// so we check the outer div
|
||||
expect(fixture.nativeElement.innerHTML).toContain('one <input value="two">');
|
||||
// and the inner div
|
||||
expect(fixture.nativeElement.innerHTML).toContain('one - two');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function initWithTemplate(compType: Type<any>, template: string) {
|
||||
@ -149,6 +229,8 @@ class ComponentToReference {
|
||||
|
||||
@Component({selector: 'app-comp', template: ``})
|
||||
class AppComp {
|
||||
outer = false;
|
||||
inner = false;
|
||||
}
|
||||
|
||||
@Directive({selector: '[dir]', exportAs: 'dir'})
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component, Directive, ErrorHandler, HostListener, QueryList, ViewChildren} from '@angular/core';
|
||||
import {Component, Directive, ErrorHandler, EventEmitter, HostListener, Input, Output, QueryList, ViewChild, ViewChildren} from '@angular/core';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {By} from '@angular/platform-browser';
|
||||
import {onlyInIvy} from '@angular/private/testing';
|
||||
@ -203,5 +203,40 @@ describe('event listeners', () => {
|
||||
expect(returnsFalseDir.event.preventDefault).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not subscribe twice to the output when there are 2 coalesced listeners', () => {
|
||||
@Directive({selector: '[foo]'})
|
||||
class FooDirective {
|
||||
@Input('foo') model: any;
|
||||
@Output('fooChange') update = new EventEmitter();
|
||||
|
||||
updateValue(value: any) { this.update.emit(value); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'test-component',
|
||||
template: `<div [(foo)]="someValue" (fooChange)="fooChange($event)"></div>`
|
||||
})
|
||||
class TestComponent {
|
||||
count = 0;
|
||||
someValue = -1;
|
||||
|
||||
@ViewChild(FooDirective) fooDirective: FooDirective|null = null;
|
||||
|
||||
fooChange() { this.count++; }
|
||||
|
||||
triggerUpdate(value: any) { this.fooDirective !.updateValue(value); }
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [TestComponent, FooDirective]});
|
||||
const fixture = TestBed.createComponent(TestComponent);
|
||||
fixture.detectChanges();
|
||||
|
||||
const componentInstance = fixture.componentInstance;
|
||||
componentInstance.triggerUpdate(42);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(componentInstance.count).toEqual(1);
|
||||
expect(componentInstance.someValue).toEqual(42);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -10,8 +10,9 @@ import {Component, Input} from '@angular/core';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {By} from '@angular/platform-browser';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
import {of } from 'rxjs';
|
||||
|
||||
describe('elementProperty', () => {
|
||||
describe('property instructions', () => {
|
||||
it('should bind to properties whose names do not correspond to their attribute names', () => {
|
||||
@Component({template: '<label [for]="forValue"></label>'})
|
||||
class MyComp {
|
||||
@ -33,6 +34,25 @@ describe('elementProperty', () => {
|
||||
expect(labelNode.nativeElement.getAttribute('for')).toBe('some-textarea');
|
||||
});
|
||||
|
||||
it('should not allow unsanitary urls in bound properties', () => {
|
||||
@Component({
|
||||
template: `
|
||||
<img [src]="naughty">
|
||||
`
|
||||
})
|
||||
class App {
|
||||
naughty = 'javascript:alert("haha, I am taking over your computer!!!");';
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [App]});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
const img = fixture.nativeElement.querySelector('img');
|
||||
|
||||
expect(img.src.indexOf('unsafe:')).toBe(0);
|
||||
});
|
||||
|
||||
|
||||
it('should not map properties whose names do not correspond to their attribute names, ' +
|
||||
'if they correspond to inputs',
|
||||
() => {
|
||||
@ -60,4 +80,154 @@ describe('elementProperty', () => {
|
||||
expect(myCompNode.nativeElement.getAttribute('for')).toBeFalsy();
|
||||
expect(myCompNode.componentInstance.for).toBe('hej');
|
||||
});
|
||||
|
||||
it('should handle all flavors of interpolated properties', () => {
|
||||
@Component({
|
||||
template: `
|
||||
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h{{eight}}i{{nine}}j"></div>
|
||||
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h{{eight}}i"></div>
|
||||
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h"></div>
|
||||
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g"></div>
|
||||
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f"></div>
|
||||
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e"></div>
|
||||
<div title="a{{one}}b{{two}}c{{three}}d"></div>
|
||||
<div title="a{{one}}b{{two}}c"></div>
|
||||
<div title="a{{one}}b"></div>
|
||||
<div title="{{one}}"></div>
|
||||
`
|
||||
})
|
||||
class App {
|
||||
one = 1;
|
||||
two = 2;
|
||||
three = 3;
|
||||
four = 4;
|
||||
five = 5;
|
||||
six = 6;
|
||||
seven = 7;
|
||||
eight = 8;
|
||||
nine = 9;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [App]});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
const titles = Array.from(fixture.nativeElement.querySelectorAll('div[title]'))
|
||||
.map((div: HTMLDivElement) => div.title);
|
||||
|
||||
expect(titles).toEqual([
|
||||
'a1b2c3d4e5f6g7h8i9j',
|
||||
'a1b2c3d4e5f6g7h8i',
|
||||
'a1b2c3d4e5f6g7h',
|
||||
'a1b2c3d4e5f6g',
|
||||
'a1b2c3d4e5f',
|
||||
'a1b2c3d4e',
|
||||
'a1b2c3d',
|
||||
'a1b2c',
|
||||
'a1b',
|
||||
'1',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle pipes in interpolated properties', () => {
|
||||
@Component({
|
||||
template: `
|
||||
<img title="{{(details | async)?.title}}" src="{{(details | async)?.url}}" />
|
||||
`
|
||||
})
|
||||
class App {
|
||||
details = of ({
|
||||
title: 'cool image',
|
||||
url: 'http://somecooldomain:1234/cool_image.png',
|
||||
});
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [App]});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
const img: HTMLImageElement = fixture.nativeElement.querySelector('img');
|
||||
expect(img.src).toBe('http://somecooldomain:1234/cool_image.png');
|
||||
expect(img.title).toBe('cool image');
|
||||
});
|
||||
|
||||
// From https://angular-team.atlassian.net/browse/FW-1287
|
||||
it('should handle multiple elvis operators', () => {
|
||||
@Component({
|
||||
template: `
|
||||
<img src="{{leadSurgeon?.getCommonInfo()?.getPhotoUrl() }}">
|
||||
`
|
||||
})
|
||||
class App {
|
||||
/** Clearly this is a doctor of heavy metals. */
|
||||
leadSurgeon = {
|
||||
getCommonInfo() {
|
||||
return {getPhotoUrl() { return 'http://somecooldomain:1234/cool_image.png'; }};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [App]});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
const img = fixture.nativeElement.querySelector('img');
|
||||
|
||||
expect(img.src).toBe('http://somecooldomain:1234/cool_image.png');
|
||||
});
|
||||
|
||||
it('should not allow unsanitary urls in interpolated properties', () => {
|
||||
@Component({
|
||||
template: `
|
||||
<img src="{{naughty}}">
|
||||
`
|
||||
})
|
||||
class App {
|
||||
naughty = 'javascript:alert("haha, I am taking over your computer!!!");';
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [App]});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
const img: HTMLImageElement = fixture.nativeElement.querySelector('img');
|
||||
|
||||
expect(img.src.indexOf('unsafe:')).toBe(0);
|
||||
});
|
||||
|
||||
it('should not allow unsanitary urls in interpolated properties, even if you are tricky', () => {
|
||||
@Component({
|
||||
template: `
|
||||
<img src="{{ja}}{{va}}script:{{naughty}}">
|
||||
`
|
||||
})
|
||||
class App {
|
||||
ja = 'ja';
|
||||
va = 'va';
|
||||
naughty = 'alert("I am a h4xx0rz1!!");';
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [App]});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
const img = fixture.nativeElement.querySelector('img');
|
||||
|
||||
expect(img.src.indexOf('unsafe:')).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle interpolations with 10+ values', () => {
|
||||
@Component({
|
||||
selector: 'app-comp',
|
||||
template: `
|
||||
<a href="http://g.com/?one={{'1'}}&two={{'2'}}&three={{'3'}}&four={{'4'}}&five={{'5'}}&six={{'6'}}&seven={{'7'}}&eight={{'8'}}&nine={{'9'}}&ten={{'10'}}">link2</a>`
|
||||
})
|
||||
class AppComp {
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [AppComp]});
|
||||
const fixture = TestBed.createComponent(AppComp);
|
||||
fixture.detectChanges();
|
||||
const anchor = fixture.debugElement.query(By.css('a')).nativeElement;
|
||||
expect(anchor.getAttribute('href'))
|
||||
.toEqual(
|
||||
`http://g.com/?one=1&two=2&three=3&four=4&five=5&six=6&seven=7&eight=8&nine=9&ten=10`);
|
||||
});
|
||||
});
|
||||
|
42
packages/core/test/bundling/core_all/BUILD.bazel
Normal file
42
packages/core/test/bundling/core_all/BUILD.bazel
Normal file
@ -0,0 +1,42 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load("//tools:defaults.bzl", "ng_rollup_bundle", "ts_library")
|
||||
load("//tools/size-tracking:index.bzl", "js_size_tracking_test")
|
||||
|
||||
ts_library(
|
||||
name = "core_all",
|
||||
srcs = ["index.ts"],
|
||||
tags = ["ivy-only"],
|
||||
deps = [
|
||||
"//packages/core",
|
||||
],
|
||||
)
|
||||
|
||||
ng_rollup_bundle(
|
||||
name = "bundle",
|
||||
entry_point = "packages/core/test/bundling/core_all/index.js",
|
||||
tags = [
|
||||
"ivy-only",
|
||||
],
|
||||
deps = [
|
||||
":core_all",
|
||||
"//packages/core",
|
||||
"@npm//rxjs",
|
||||
],
|
||||
)
|
||||
|
||||
js_size_tracking_test(
|
||||
name = "size_test",
|
||||
src = "angular/packages/core/test/bundling/core_all/bundle.min.js",
|
||||
data = [
|
||||
":bundle",
|
||||
":bundle.golden_size_map.json",
|
||||
],
|
||||
diffThreshold = 3,
|
||||
goldenFile = "angular/packages/core/test/bundling/core_all/bundle.golden_size_map.json",
|
||||
sourceMap = "angular/packages/core/test/bundling/core_all/bundle.min.js.map",
|
||||
tags = [
|
||||
"ivy-only",
|
||||
"manual",
|
||||
],
|
||||
)
|
362
packages/core/test/bundling/core_all/bundle.golden_size_map.json
Normal file
362
packages/core/test/bundling/core_all/bundle.golden_size_map.json
Normal file
@ -0,0 +1,362 @@
|
||||
{
|
||||
"unmapped": 25,
|
||||
"files": {
|
||||
"size": 268455,
|
||||
"@angular/": {
|
||||
"size": 248616,
|
||||
"core/": {
|
||||
"size": 248616,
|
||||
"src/": {
|
||||
"size": 248535,
|
||||
"application_init.ts": 626,
|
||||
"application_module.ts": 634,
|
||||
"application_ref.ts": 7371,
|
||||
"application_tokens.ts": 307,
|
||||
"change_detection/": {
|
||||
"size": 14119,
|
||||
"change_detection.ts": 46,
|
||||
"change_detection_util.ts": 822,
|
||||
"change_detector_ref.ts": 93,
|
||||
"constants.ts": 411,
|
||||
"differs/": {
|
||||
"size": 12747,
|
||||
"default_iterable_differ.ts": 7623,
|
||||
"default_keyvalue_differ.ts": 3882,
|
||||
"iterable_differs.ts": 655,
|
||||
"keyvalue_differs.ts": 587
|
||||
}
|
||||
},
|
||||
"compiler/": {
|
||||
"size": 442,
|
||||
"compiler_facade.ts": 442
|
||||
},
|
||||
"console.ts": 217,
|
||||
"debug/": {
|
||||
"size": 7621,
|
||||
"debug_node.ts": 7621
|
||||
},
|
||||
"di/": {
|
||||
"size": 20079,
|
||||
"forward_ref.ts": 211,
|
||||
"injectable.ts": 82,
|
||||
"injection_token.ts": 322,
|
||||
"injector.ts": 3872,
|
||||
"injector_compatibility.ts": 1005,
|
||||
"interface/": {
|
||||
"size": 484,
|
||||
"defs.ts": 339,
|
||||
"injector.ts": 145
|
||||
},
|
||||
"jit/": {
|
||||
"size": 1988,
|
||||
"environment.ts": 162,
|
||||
"injectable.ts": 803,
|
||||
"util.ts": 1023
|
||||
},
|
||||
"metadata.ts": 157,
|
||||
"r3_injector.ts": 4765,
|
||||
"reflective_errors.ts": 1376,
|
||||
"reflective_injector.ts": 3062,
|
||||
"reflective_key.ts": 661,
|
||||
"reflective_provider.ts": 2000,
|
||||
"scope.ts": 90,
|
||||
"util.ts": 4
|
||||
},
|
||||
"error_handler.ts": 444,
|
||||
"errors.ts": 175,
|
||||
"event_emitter.ts": 952,
|
||||
"i18n/": {
|
||||
"size": 178,
|
||||
"tokens.ts": 178
|
||||
},
|
||||
"interface/": {
|
||||
"size": 222,
|
||||
"simple_change.ts": 170,
|
||||
"type.ts": 52
|
||||
},
|
||||
"ivy_switch.ts": 936,
|
||||
"linker/": {
|
||||
"size": 4923,
|
||||
"compiler.ts": 825,
|
||||
"component_factory.ts": 91,
|
||||
"component_factory_resolver.ts": 1003,
|
||||
"element_ref.ts": 119,
|
||||
"ng_module_factory.ts": 78,
|
||||
"ng_module_factory_loader.ts": 449,
|
||||
"query_list.ts": 1011,
|
||||
"system_js_ng_module_factory_loader.ts": 957,
|
||||
"template_ref.ts": 97,
|
||||
"view_container_ref.ts": 97,
|
||||
"view_ref.ts": 196
|
||||
},
|
||||
"metadata/": {
|
||||
"size": 3522,
|
||||
"di.ts": 547,
|
||||
"directives.ts": 604,
|
||||
"ng_module.ts": 95,
|
||||
"resource_loading.ts": 839,
|
||||
"schema.ts": 1306,
|
||||
"view.ts": 131
|
||||
},
|
||||
"platform_core_providers.ts": 118,
|
||||
"profile/": {
|
||||
"size": 442,
|
||||
"profile.ts": 170,
|
||||
"wtf_impl.ts": 272
|
||||
},
|
||||
"reflection/": {
|
||||
"size": 4878,
|
||||
"reflection.ts": 15,
|
||||
"reflection_capabilities.ts": 3678,
|
||||
"reflector.ts": 1185
|
||||
},
|
||||
"render/": {
|
||||
"size": 482,
|
||||
"api.ts": 482
|
||||
},
|
||||
"render3/": {
|
||||
"size": 103297,
|
||||
"bindings.ts": 300,
|
||||
"component.ts": 4000,
|
||||
"component_ref.ts": 2512,
|
||||
"context_discovery.ts": 2098,
|
||||
"definition.ts": 2486,
|
||||
"di.ts": 3651,
|
||||
"di_setup.ts": 1584,
|
||||
"empty.ts": 16,
|
||||
"errors.ts": 89,
|
||||
"features/": {
|
||||
"size": 2677,
|
||||
"inherit_definition_feature.ts": 1993,
|
||||
"ng_onchanges_feature.ts": 571,
|
||||
"providers_feature.ts": 113
|
||||
},
|
||||
"fields.ts": 140,
|
||||
"hooks.ts": 1843,
|
||||
"i18n.ts": 14527,
|
||||
"instructions/": {
|
||||
"size": 20030,
|
||||
"alloc_host_vars.ts": 290,
|
||||
"change_detection.ts": 91,
|
||||
"container.ts": 758,
|
||||
"di.ts": 129,
|
||||
"element.ts": 1214,
|
||||
"element_container.ts": 335,
|
||||
"embedded_view.ts": 678,
|
||||
"get_current_view.ts": 26,
|
||||
"listener.ts": 1401,
|
||||
"next_context.ts": 44,
|
||||
"projection.ts": 348,
|
||||
"property.ts": 193,
|
||||
"property_interpolation.ts": 2584,
|
||||
"select.ts": 51,
|
||||
"shared.ts": 10205,
|
||||
"storage.ts": 169,
|
||||
"styling.ts": 1329,
|
||||
"text.ts": 185
|
||||
},
|
||||
"interfaces/": {
|
||||
"size": 619,
|
||||
"container.ts": 24,
|
||||
"context.ts": 19,
|
||||
"i18n.ts": 48,
|
||||
"injector.ts": 242,
|
||||
"renderer.ts": 176,
|
||||
"view.ts": 110
|
||||
},
|
||||
"jit/": {
|
||||
"size": 9479,
|
||||
"directive.ts": 3409,
|
||||
"environment.ts": 2758,
|
||||
"module.ts": 3047,
|
||||
"pipe.ts": 265
|
||||
},
|
||||
"metadata.ts": 615,
|
||||
"ng_module_ref.ts": 986,
|
||||
"node_manipulation.ts": 4571,
|
||||
"node_selector_matcher.ts": 1780,
|
||||
"node_util.ts": 335,
|
||||
"pipe.ts": 958,
|
||||
"players.ts": 564,
|
||||
"pure_function.ts": 1273,
|
||||
"query.ts": 3303,
|
||||
"state.ts": 1442,
|
||||
"styling/": {
|
||||
"size": 11242,
|
||||
"class_and_style_bindings.ts": 9074,
|
||||
"core_player_handler.ts": 274,
|
||||
"host_instructions_queue.ts": 335,
|
||||
"player_factory.ts": 118,
|
||||
"shared.ts": 5,
|
||||
"state.ts": 55,
|
||||
"util.ts": 1381
|
||||
},
|
||||
"tokens.ts": 10,
|
||||
"util/": {
|
||||
"size": 4102,
|
||||
"attrs_utils.ts": 423,
|
||||
"discovery_utils.ts": 1489,
|
||||
"global_utils.ts": 374,
|
||||
"injector_utils.ts": 150,
|
||||
"misc_utils.ts": 625,
|
||||
"view_traversal_utils.ts": 221,
|
||||
"view_utils.ts": 820
|
||||
},
|
||||
"view_engine_compatibility.ts": 3815,
|
||||
"view_engine_compatibility_prebound.ts": 38,
|
||||
"view_ref.ts": 2212
|
||||
},
|
||||
"sanitization/": {
|
||||
"size": 9766,
|
||||
"bypass.ts": 669,
|
||||
"html_sanitizer.ts": 4721,
|
||||
"inert_body.ts": 2066,
|
||||
"sanitization.ts": 1057,
|
||||
"security.ts": 206,
|
||||
"style_sanitizer.ts": 574,
|
||||
"url_sanitizer.ts": 473
|
||||
},
|
||||
"testability/": {
|
||||
"size": 3796,
|
||||
"testability.ts": 3796
|
||||
},
|
||||
"util/": {
|
||||
"size": 4317,
|
||||
"array_utils.ts": 210,
|
||||
"assert.ts": 81,
|
||||
"closure.ts": 37,
|
||||
"comparison.ts": 90,
|
||||
"decorators.ts": 1640,
|
||||
"errors.ts": 164,
|
||||
"global.ts": 271,
|
||||
"is_dev_mode.ts": 358,
|
||||
"lang.ts": 109,
|
||||
"microtask.ts": 159,
|
||||
"ng_i18n_closure_mode.ts": 118,
|
||||
"ng_reflect.ts": 334,
|
||||
"property.ts": 201,
|
||||
"stringify.ts": 290,
|
||||
"symbol.ts": 255
|
||||
},
|
||||
"version.ts": 179,
|
||||
"view/": {
|
||||
"size": 55747,
|
||||
"element.ts": 3814,
|
||||
"entrypoint.ts": 962,
|
||||
"errors.ts": 642,
|
||||
"ng_content.ts": 447,
|
||||
"ng_module.ts": 2448,
|
||||
"provider.ts": 5363,
|
||||
"pure_expression.ts": 2279,
|
||||
"query.ts": 2385,
|
||||
"refs.ts": 9337,
|
||||
"services.ts": 11639,
|
||||
"text.ts": 1551,
|
||||
"types.ts": 768,
|
||||
"util.ts": 4728,
|
||||
"view.ts": 8143,
|
||||
"view_attach.ts": 1241
|
||||
},
|
||||
"zone/": {
|
||||
"size": 2745,
|
||||
"ng_zone.ts": 2745
|
||||
}
|
||||
},
|
||||
"test/": {
|
||||
"size": 81,
|
||||
"bundling/": {
|
||||
"size": 81,
|
||||
"core_all/": {
|
||||
"size": 81,
|
||||
"index.ts": 81
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"external/": {
|
||||
"size": 19814,
|
||||
"npm/": {
|
||||
"size": 19814,
|
||||
"node_modules/": {
|
||||
"size": 19814,
|
||||
"rxjs/": {
|
||||
"size": 18753,
|
||||
"_esm5/": {
|
||||
"size": 18753,
|
||||
"internal/": {
|
||||
"size": 18753,
|
||||
"InnerSubscriber.js": 415,
|
||||
"Notification.js": 15,
|
||||
"Observable.js": 1420,
|
||||
"Observer.js": 137,
|
||||
"OuterSubscriber.js": 298,
|
||||
"Subject.js": 1910,
|
||||
"SubjectSubscription.js": 346,
|
||||
"Subscriber.js": 3254,
|
||||
"Subscription.js": 1536,
|
||||
"config.js": 136,
|
||||
"observable/": {
|
||||
"size": 3191,
|
||||
"ConnectableObservable.js": 1435,
|
||||
"from.js": 245,
|
||||
"fromArray.js": 186,
|
||||
"fromIterable.js": 395,
|
||||
"fromObservable.js": 347,
|
||||
"fromPromise.js": 287,
|
||||
"merge.js": 296
|
||||
},
|
||||
"operators/": {
|
||||
"size": 3322,
|
||||
"map.js": 624,
|
||||
"mergeAll.js": 69,
|
||||
"mergeMap.js": 1445,
|
||||
"multicast.js": 415,
|
||||
"refCount.js": 683,
|
||||
"share.js": 82,
|
||||
"windowToggle.js": 4
|
||||
},
|
||||
"symbol/": {
|
||||
"size": 256,
|
||||
"iterator.js": 104,
|
||||
"observable.js": 64,
|
||||
"rxSubscriber.js": 88
|
||||
},
|
||||
"util/": {
|
||||
"size": 2517,
|
||||
"EmptyError.js": 6,
|
||||
"ObjectUnsubscribedError.js": 168,
|
||||
"UnsubscriptionError.js": 279,
|
||||
"canReportError.js": 114,
|
||||
"hostReportError.js": 47,
|
||||
"identity.js": 24,
|
||||
"isArray.js": 67,
|
||||
"isArrayLike.js": 74,
|
||||
"isFunction.js": 42,
|
||||
"isInteropObservable.js": 49,
|
||||
"isIterable.js": 49,
|
||||
"isObject.js": 51,
|
||||
"isPromise.js": 84,
|
||||
"isScheduler.js": 54,
|
||||
"noop.js": 15,
|
||||
"pipe.js": 105,
|
||||
"subscribeTo.js": 434,
|
||||
"subscribeToArray.js": 114,
|
||||
"subscribeToIterable.js": 213,
|
||||
"subscribeToObservable.js": 192,
|
||||
"subscribeToPromise.js": 146,
|
||||
"subscribeToResult.js": 74,
|
||||
"toSubscriber.js": 116
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tslib/": {
|
||||
"size": 1061,
|
||||
"tslib.es6.js": 1061
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
13
packages/core/test/bundling/core_all/index.ts
Normal file
13
packages/core/test/bundling/core_all/index.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. 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
|
||||
*/
|
||||
|
||||
import * as core from '@angular/core';
|
||||
|
||||
// We need to something with the "core" import in order to ensure
|
||||
// that all symbols from core are preserved in the bundle.
|
||||
console.error(core);
|
@ -1772,6 +1772,99 @@ function declareTests(config?: {useJit: boolean}) {
|
||||
fixture.detectChanges();
|
||||
expect(getDOM().getInnerHTML(fixture.nativeElement)).toContain('[ERROR]');
|
||||
});
|
||||
|
||||
it('should not reflect undefined values', () => {
|
||||
TestBed.configureTestingModule({declarations: [MyComp, MyDir, MyDir2]});
|
||||
TestBed.overrideComponent(
|
||||
MyComp, {set: {template: `<div my-dir [elprop]="ctxProp"></div>`}});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
fixture.componentInstance.ctxProp = 'hello';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getDOM().getInnerHTML(fixture.nativeElement))
|
||||
.toContain('ng-reflect-dir-prop="hello"');
|
||||
|
||||
fixture.componentInstance.ctxProp = undefined !;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getDOM().getInnerHTML(fixture.nativeElement)).not.toContain('ng-reflect-');
|
||||
});
|
||||
|
||||
it('should not reflect null values', () => {
|
||||
TestBed.configureTestingModule({declarations: [MyComp, MyDir, MyDir2]});
|
||||
TestBed.overrideComponent(
|
||||
MyComp, {set: {template: `<div my-dir [elprop]="ctxProp"></div>`}});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
fixture.componentInstance.ctxProp = 'hello';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getDOM().getInnerHTML(fixture.nativeElement))
|
||||
.toContain('ng-reflect-dir-prop="hello"');
|
||||
|
||||
fixture.componentInstance.ctxProp = null !;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getDOM().getInnerHTML(fixture.nativeElement)).not.toContain('ng-reflect-');
|
||||
});
|
||||
|
||||
it('should reflect empty strings', () => {
|
||||
TestBed.configureTestingModule({declarations: [MyComp, MyDir, MyDir2]});
|
||||
TestBed.overrideComponent(
|
||||
MyComp, {set: {template: `<div my-dir [elprop]="ctxProp"></div>`}});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
fixture.componentInstance.ctxProp = '';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getDOM().getInnerHTML(fixture.nativeElement)).toContain('ng-reflect-dir-prop=""');
|
||||
});
|
||||
|
||||
it('should not reflect in comment nodes when the value changes to undefined', () => {
|
||||
const fixture =
|
||||
TestBed.configureTestingModule({declarations: [MyComp]})
|
||||
.overrideComponent(
|
||||
MyComp, {set: {template: `<ng-template [ngIf]="ctxBoolProp"></ng-template>`}})
|
||||
.createComponent(MyComp);
|
||||
|
||||
fixture.componentInstance.ctxBoolProp = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
let html = getDOM().getInnerHTML(fixture.nativeElement);
|
||||
expect(html).toContain('bindings={');
|
||||
expect(html).toContain('"ng-reflect-ng-if": "true"');
|
||||
|
||||
fixture.componentInstance.ctxBoolProp = undefined !;
|
||||
fixture.detectChanges();
|
||||
|
||||
html = getDOM().getInnerHTML(fixture.nativeElement);
|
||||
expect(html).toContain('bindings={');
|
||||
expect(html).not.toContain('ng-reflect');
|
||||
});
|
||||
|
||||
it('should reflect in comment nodes when the value changes to null', () => {
|
||||
const fixture =
|
||||
TestBed.configureTestingModule({declarations: [MyComp]})
|
||||
.overrideComponent(
|
||||
MyComp, {set: {template: `<ng-template [ngIf]="ctxBoolProp"></ng-template>`}})
|
||||
.createComponent(MyComp);
|
||||
|
||||
fixture.componentInstance.ctxBoolProp = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
let html = getDOM().getInnerHTML(fixture.nativeElement);
|
||||
expect(html).toContain('bindings={');
|
||||
expect(html).toContain('"ng-reflect-ng-if": "true"');
|
||||
|
||||
fixture.componentInstance.ctxBoolProp = null !;
|
||||
fixture.detectChanges();
|
||||
|
||||
html = getDOM().getInnerHTML(fixture.nativeElement);
|
||||
expect(html).toContain('bindings={');
|
||||
expect(html).toContain('"ng-reflect-ng-if": null');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('property decorators', () => {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,176 +6,20 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AttributeMarker, ɵɵdefineComponent, ɵɵdefineDirective} from '../../src/render3/index';
|
||||
import {ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementAttribute, ɵɵelementClassProp, ɵɵelementEnd, ɵɵelementProperty, ɵɵelementStart, ɵɵelementStyling, ɵɵelementStylingApply, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵinterpolation2, ɵɵnextContext, ɵɵreference, ɵɵtemplate, ɵɵtext, ɵɵtextBinding} from '../../src/render3/instructions/all';
|
||||
import {ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵreference, ɵɵtext, ɵɵtextBinding} from '../../src/render3/instructions/all';
|
||||
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
||||
|
||||
import {NgIf} from './common_with_def';
|
||||
import {ComponentFixture, createComponent, renderToHtml} from './render_util';
|
||||
import {ComponentFixture, createComponent} from './render_util';
|
||||
|
||||
describe('exports', () => {
|
||||
// For basic use cases, see core/test/acceptance/exports_spec.ts.
|
||||
|
||||
describe('forward refs', () => {
|
||||
it('should work with basic text bindings', () => {
|
||||
/** {{ myInput.value}} <input value="one" #myInput> */
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵtext(0);
|
||||
ɵɵelement(1, 'input', ['value', 'one'], ['myInput', '']);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
const tmp = ɵɵreference(2) as any;
|
||||
ɵɵtextBinding(0, ɵɵbind(tmp.value));
|
||||
}
|
||||
}, 3, 1);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(fixture.html).toEqual('one<input value="one">');
|
||||
});
|
||||
|
||||
|
||||
it('should work with element properties', () => {
|
||||
/** <div [title]="myInput.value"</div> <input value="one" #myInput> */
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵelement(0, 'div');
|
||||
ɵɵelement(1, 'input', ['value', 'one'], ['myInput', '']);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
const tmp = ɵɵreference(2) as any;
|
||||
ɵɵelementProperty(0, 'title', ɵɵbind(tmp.value));
|
||||
}
|
||||
}, 3, 1);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(fixture.html).toEqual('<div title="one"></div><input value="one">');
|
||||
});
|
||||
|
||||
it('should work with element attrs', () => {
|
||||
/** <div [attr.aria-label]="myInput.value"</div> <input value="one" #myInput> */
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵelement(0, 'div');
|
||||
ɵɵelement(1, 'input', ['value', 'one'], ['myInput', '']);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
const tmp = ɵɵreference(2) as any;
|
||||
ɵɵelementAttribute(0, 'aria-label', ɵɵbind(tmp.value));
|
||||
}
|
||||
}, 3, 1);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(fixture.html).toEqual('<div aria-label="one"></div><input value="one">');
|
||||
});
|
||||
|
||||
it('should work with element classes', () => {
|
||||
/** <div [class.red]="myInput.checked"</div> <input type="checkbox" checked #myInput> */
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵelementStart(0, 'div', [AttributeMarker.Classes, 'red']);
|
||||
ɵɵelementStyling(['red']);
|
||||
ɵɵelementEnd();
|
||||
ɵɵelement(1, 'input', ['type', 'checkbox', 'checked', 'true'], ['myInput', '']);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
const tmp = ɵɵreference(2) as any;
|
||||
ɵɵelementClassProp(0, 0, tmp.checked);
|
||||
ɵɵelementStylingApply(0);
|
||||
}
|
||||
}, 3);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(fixture.html).toEqual('<div class="red"></div><input checked="true" type="checkbox">');
|
||||
});
|
||||
|
||||
it('should work with component refs', () => {
|
||||
|
||||
let myComponent: MyComponent;
|
||||
let myDir: MyDir;
|
||||
|
||||
class MyComponent {
|
||||
constructor() { myComponent = this; }
|
||||
|
||||
static ngComponentDef = ɵɵdefineComponent({
|
||||
type: MyComponent,
|
||||
selectors: [['comp']],
|
||||
consts: 0,
|
||||
vars: 0,
|
||||
template: function(rf: RenderFlags, ctx: MyComponent) {},
|
||||
factory: () => new MyComponent
|
||||
});
|
||||
}
|
||||
|
||||
class MyDir {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
myDir !: MyComponent;
|
||||
|
||||
constructor() { myDir = this; }
|
||||
|
||||
static ngDirectiveDef = ɵɵdefineDirective({
|
||||
type: MyDir,
|
||||
selectors: [['', 'myDir', '']],
|
||||
factory: () => new MyDir,
|
||||
inputs: {myDir: 'myDir'}
|
||||
});
|
||||
}
|
||||
|
||||
/** <div [myDir]="myComp"></div><comp #myComp></comp> */
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵelement(0, 'div', ['myDir', '']);
|
||||
ɵɵelement(1, 'comp', null, ['myComp', '']);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
const tmp = ɵɵreference(2) as any;
|
||||
ɵɵelementProperty(0, 'myDir', ɵɵbind(tmp));
|
||||
}
|
||||
}, 3, 1, [MyComponent, MyDir]);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(myDir !.myDir).toEqual(myComponent !);
|
||||
});
|
||||
|
||||
it('should work with multiple forward refs', () => {
|
||||
let myComponent: MyComponent;
|
||||
|
||||
class MyComponent {
|
||||
name = 'Nancy';
|
||||
|
||||
constructor() { myComponent = this; }
|
||||
|
||||
static ngComponentDef = ɵɵdefineComponent({
|
||||
type: MyComponent,
|
||||
selectors: [['comp']],
|
||||
consts: 0,
|
||||
vars: 0,
|
||||
template: function() {},
|
||||
factory: () => new MyComponent
|
||||
});
|
||||
}
|
||||
|
||||
/** {{ myInput.value }} {{ myComp.name }} <comp #myComp></comp> <input value="one" #myInput>
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵtext(0);
|
||||
ɵɵtext(1);
|
||||
ɵɵelement(2, 'comp', null, ['myComp', '']);
|
||||
ɵɵelement(4, 'input', ['value', 'one'], ['myInput', '']);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
const tmp1 = ɵɵreference(3) as any;
|
||||
const tmp2 = ɵɵreference(5) as any;
|
||||
ɵɵtextBinding(0, ɵɵbind(tmp2.value));
|
||||
ɵɵtextBinding(1, ɵɵbind(tmp1.name));
|
||||
}
|
||||
}, 6, 2, [MyComponent]);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(fixture.html).toEqual('oneNancy<comp></comp><input value="one">');
|
||||
});
|
||||
|
||||
/**
|
||||
* This test needs to be moved to acceptance/exports_spec.ts
|
||||
* when Ivy compiler supports inline views.
|
||||
*/
|
||||
it('should work inside a view container', () => {
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
@ -214,74 +58,5 @@ describe('exports', () => {
|
||||
fixture.update();
|
||||
expect(fixture.html).toEqual('<div></div>');
|
||||
});
|
||||
|
||||
it('should support local refs in nested dynamic views', () => {
|
||||
/**
|
||||
* <input value="one" #outerInput>
|
||||
* <div *ngIf="outer">
|
||||
* {{ outerInput.value }}
|
||||
*
|
||||
* <input value = "two" #innerInput>
|
||||
*
|
||||
* <div *ngIf="inner">
|
||||
* {{ outerInput.value }} - {{ innerInput.value}}
|
||||
* </div>
|
||||
* </div>
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, app: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵelementStart(0, 'input', ['value', 'one'], ['outerInput', '']);
|
||||
ɵɵelementEnd();
|
||||
ɵɵtemplate(2, outerTemplate, 5, 2, 'div', [AttributeMarker.Template, 'ngIf']);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ɵɵelementProperty(2, 'ngIf', ɵɵbind(app.outer));
|
||||
}
|
||||
}, 3, 1, [NgIf]);
|
||||
|
||||
function outerTemplate(rf: RenderFlags, outer: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵelementStart(0, 'div');
|
||||
{
|
||||
ɵɵtext(1);
|
||||
ɵɵelementStart(2, 'input', ['value', 'two'], ['innerInput', '']);
|
||||
ɵɵelementEnd();
|
||||
ɵɵtemplate(4, innerTemplate, 2, 2, 'div', [AttributeMarker.Template, 'ngIf']);
|
||||
}
|
||||
ɵɵelementEnd();
|
||||
}
|
||||
|
||||
if (rf & RenderFlags.Update) {
|
||||
const app = ɵɵnextContext();
|
||||
const outerInput = ɵɵreference(1) as any;
|
||||
ɵɵtextBinding(1, ɵɵbind(outerInput.value));
|
||||
ɵɵelementProperty(4, 'ngIf', ɵɵbind(app.inner));
|
||||
}
|
||||
}
|
||||
|
||||
function innerTemplate(rf: RenderFlags, inner: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵelementStart(0, 'div');
|
||||
{ ɵɵtext(1); }
|
||||
ɵɵelementEnd();
|
||||
}
|
||||
|
||||
if (rf & RenderFlags.Update) {
|
||||
ɵɵnextContext();
|
||||
const innerInput = ɵɵreference(3) as any;
|
||||
ɵɵnextContext();
|
||||
const outerInput = ɵɵreference(1) as any;
|
||||
ɵɵtextBinding(1, ɵɵinterpolation2('', outerInput.value, ' - ', innerInput.value, ''));
|
||||
}
|
||||
}
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
fixture.component.outer = true;
|
||||
fixture.component.inner = true;
|
||||
fixture.update();
|
||||
expect(fixture.html)
|
||||
.toEqual(`<input value="one"><div>one<input value="two"><div>one - two</div></div>`);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
@ -548,9 +548,8 @@ export class R3TestBedCompiler {
|
||||
}
|
||||
|
||||
// TODO(ocombe): make this work with an Injector directly instead of creating a module for it
|
||||
@NgModule({providers})
|
||||
class CompilerModule {
|
||||
}
|
||||
class CompilerModule {}
|
||||
compileNgModuleDefs(CompilerModule as NgModuleType<any>, {providers});
|
||||
|
||||
const CompilerModuleFactory = new R3NgModuleFactory(CompilerModule);
|
||||
this._injector = CompilerModuleFactory.create(this.platform.injector).injector;
|
||||
|
@ -70,7 +70,7 @@ export interface ControlValueAccessor {
|
||||
*
|
||||
* ```ts
|
||||
* host: {
|
||||
* (change): '_onChange($event.target.value)'
|
||||
* '(change)': '_onChange($event.target.value)'
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
|
@ -113,7 +113,7 @@ export const controlNameBinding: any = {
|
||||
*
|
||||
* ```ts
|
||||
* imports: [
|
||||
* ReactiveFormsModule.withConfig({warnOnNgModelWithFormControl: 'never'});
|
||||
* ReactiveFormsModule.withConfig({warnOnNgModelWithFormControl: 'never'})
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user