Compare commits

...

39 Commits

Author SHA1 Message Date
9798229fde release: cut the v8.0.0-rc.2 release 2019-04-29 12:03:39 -07:00
4b2fcfd5dc fix: disable injectable-pipe migration (#30180)
Disables the injectable pipe migration until we can decide whether this is the right solution for Ivy. Rolling it out properly will involve a more detailed plan and more changes like updating the styleguide, scaffolding schematics etc.

Context for the new `test-migrations.json`: since we use the `migrations.json` both for the real migrations and for tests, it doesn't allow us to disable a schematic, but continue running its tests. This change adds the test-specific file so that we can continue running the `injectable-pipe` tests, even though the schematic itself is disabled.

PR Close #30180
2019-04-29 09:40:00 -07:00
b4d291aa7a fix(ivy): injectable pipe schematic generating incorrect import statements (#30170)
Currently the injectable pipe schematic generates invalid imports like `import import { Pipe, PipeTransform, Injectable } from '@angular/core'; from '@angular/core';`. The issue wasn't caught by the unit tests, because the invalid import still contains the valid one.

Fixes #30159.

PR Close #30170
2019-04-29 09:39:11 -07:00
b0ecafdc2f docs: temporary disable aio_monitoring job due to a version skew (#30161)
It looks like `aio_monitoring` CircleCI job is still failing. Disabling it for now to keep master green.

PR Close #30161
2019-04-26 17:38:59 -07:00
6816bb62d7 Revert "refactor: use new Http library in playground (#29355)"
This reverts commit 908d43a5bb.
2019-04-26 16:51:38 -07:00
4b05b8cea0 refactor(ivy): move exports tests to acceptance (#30157)
PR Close #30157
2019-04-26 16:37:34 -07:00
a0728aedf7 docs: update readme. sentence correction. (#30136)
PR Close #30136
2019-04-26 16:36:53 -07:00
ea96f6112a build: unable to accept new symbol-extractor golden on windows (#30127)
Currently when working on Windows, it's not possible to accept a new
golden for a `symbol-extractor` Bazel test. This is because the generated
executable output from the `nodejs_binary` rule (without a macro) misses
a Windows executable wrapper that sets up the proper environment
variables for the runfiles. Causing the following failure on Windows:

```
 >>>> FAIL: RUNFILES environment variable is not set. <<<<
```

PR Close #30127
2019-04-26 16:35:51 -07:00
b706800ea8 fix(language-service): Remove tsserverlibrary from rollup globals (#30123)
This PR removes `tsserverlibrary` from rollup globals since the symbol
should not appear by the time rollup is invoked. `tsserverlibrary` is
used for types only, so the import statement should not be emitted by
tsc.

PR Close #30123
2019-04-26 16:35:05 -07:00
c6f95b1d70 ci: enable language service tests in codefresh (#30113)
PR Close #30113
2019-04-26 16:34:23 -07:00
d896126604 test: fix language service tests in windows (#30113)
This PR parially addresses #29785 and fixes ` //packages/language-service/test:test`

PR Close #30113
2019-04-26 16:34:23 -07:00
a20da5ddcc ci(docs-infra): use the tests from the stable branch in aio_monitoring_stable CircleCI job (#30110)
Previously, the `aio_monitoring_stable` job (which runs tests against
https://angular.io/) was using the tests from the master branch. As a
result, if the master branch included changes in those tests that were
not yet backported to the stable branch (and thus deployed to
https://angular.io/), the tests would fail.

This commit fixes this by using the tests from the stable branch to test
against https://angular.io/.

Fixes #30101

PR Close #30110
2019-04-26 16:33:46 -07:00
18878600ba ci(docs-infra): split the aio_monitoring CircleCI job into two jobs (#30110)
Previously, the `aio_monitoring` job was testing both the stable
(https://angular.io/) and the @next (https://next.angular.io/) versions.

This commit splits the tests into two separate jobs (still run as part
of the same workflow). This speeds up the tests (since the two jobs can
now run in parallel) and makes it easier to isolate failures (e.g.
identify which branch is failing, disable one of the two, etc.).
(Credits to @petebacondarwin 😉)

PR Close #30110
2019-04-26 16:33:46 -07:00
d7e10f3f7e ci(docs-infra): re-use setup CircleCI job in aio_monitoring (#30110)
PR Close #30110
2019-04-26 16:33:46 -07:00
4d044ea5b2 ci(docs-infra): re-enable aio_monitoring CircleCI job (#30110)
The job started failing for https://angular.io/, due to changes in tests
that only affected https://next.angular.io/, and was disabled in #30102.

This commit re-enables the job (since it does not block anything and it
will be fixed in a subsequent commit).

PR Close #30110
2019-04-26 16:33:46 -07:00
e2d1e0cd98 docs(docs-infra): fix typo in workspace-config.md file (#30108)
Fixed typo in 'Project asset configuration' section inside workdspace-config.md

PR Close #30108
2019-04-26 16:33:03 -07:00
4e056580bb test: fix api guardian tests on windows when node_modules are not installed (#30105)
When the workspace node_modules are not installed outside of bazel context the api guardian tests fails because the tree artifacts files are not symlinked in windows.

We need to pass the node module location in the node_path

PR Close #30105
2019-04-26 16:32:23 -07:00
e4c2e6a904 ci: add public_api_guard tests to codefresh config (#30105)
PR Close #30105
2019-04-26 16:32:23 -07:00
a50989832d test: fix ts api guardian and public guard tests on windows (#30105)
This change addresses several issues with ts-api-guardian and public api guards related tests in Windows

The fixes contain 3 main changes:
1) In `stripExportPattern` - replace `^` with `^^^^`  in RegExp due to a double escaping requirment under Windows. Note that under Linux this the extra character has no effect because it's still a valid RegExp in Js.

2. Force `*.patch` files to always be with a LF line sequence instead of CRLF in windows

3. When adding JSDoc comments consider the presence of a carriage return in a line new feed

Partially addresses #29785

PR Close #30105
2019-04-26 16:32:23 -07:00
525307b6a3 fix(ivy): correctly reflect undefined values (#30103)
Fixes Ivy reflecting properties with `undefined` values, rather than omitting them. Also fixes that Ivy doesn't clear the reflected values when property value changes from something that is defined to undefined.

This PR resolves FW-1277.

PR Close #30103
2019-04-26 16:31:50 -07:00
a3ab76b216 docs: update redirect links and fix typo (#30092)
PR Close #30092
2019-04-26 16:31:04 -07:00
f2265d4b46 build: upgrade yargs package to 13.1.0 (#29722)
Update yargs, because the old version was transitively (via os-local) depending on a vulnerable version of the mem package: https://app.snyk.io/vuln/npm:mem:20180117

PR Close #29722
2019-04-26 16:29:29 -07:00
d3ac709b99 fix(ivy): @Component should support entry components from another module (#29566)
PR Close #29566
2019-04-26 16:27:19 -07:00
908d43a5bb refactor: use new Http library in playground (#29355)
PR Close #29355
2019-04-26 16:26:31 -07:00
71cdb0a08e refactor(ivy): move di tests for inject to acceptance (#29299)
PR Close #29299
2019-04-26 16:23:44 -07:00
c7fbbdfa99 refactor(ivy): move di tests for flags to acceptance (#29299)
Including tests for `@Optional`, `@Self`, `@SkipSelf` and `@Host`.

PR Close #29299
2019-04-26 16:23:44 -07:00
10e4ab7712 refactor(ivy): move di tests for directive injection to acceptance (#29299)
PR Close #29299
2019-04-26 16:23:44 -07:00
5114c23c21 refactor(ivy): move di tests for DI tokens to acceptance (#29299)
Move tests for special tokens like `Injector`, `ElementRef`, `TemplateRef`, `ViewContainerRef`, `ChangeDectetorRef` and custom string tokens.

PR Close #29299
2019-04-26 16:23:43 -07:00
c3e585d7eb refactor(ivy): move di tests for Attribute to acceptance (#29299)
PR Close #29299
2019-04-26 16:23:43 -07:00
0776daec88 release: cut the v8.0.0-rc.1 release 2019-04-26 13:28:49 -07:00
615e1a58b2 test(ivy): pin deps on hello world size tests (#30152)
We recently had an unexpected size regression in the hello world
tests because the CLI devkit released an RC that regressed us and
the dependencies were not pinned. This change ensures that we only
update dependencies like devkit deliberately, so we do not have
mysterious breakages caused by other packages.

PR Close #30152
2019-04-26 12:34:10 -07:00
606758357e fix(bazel): update peerDep ranges (#30155)
PR Close #30155
2019-04-26 12:32:35 -07:00
ba2a3595c6 fix(ivy): output should not be subscribe twice when 2 listeners (#30144)
PR Close #30144
2019-04-26 11:11:09 -07:00
a50bfe5054 fix(ivy): property bindings use correct indices (#30129)
- Extracts and documents code that will be common to interpolation instructions
- Ensures that binding indices are updated at the proper time during compilation
- Adds additional tests

Related #30011

PR Close #30129
2019-04-26 11:09:51 -07:00
c8983bc367 docs: remove note about ivy being coupled to dynamic import (#30151)
PR Close #30151
2019-04-26 11:08:51 -07:00
8d6d2c6704 build: bazel ts-api-guardian usage fails on workspaces which don't depend on chalk (#30138)
When using the npm package in a workspace which doesn't depend on chalk, ts-api-guardian fails with an error `Error: Cannot find module 'chalk'`

PR Close #30138
2019-04-26 11:08:05 -07:00
6711f22e62 fix(bazel): Exclude common/upgrade* in metadata.tsconfig.json (#30133)
It has a dependency on @angular/upgrade which is not part of the
dependencies in package.json, so postinstall would fail.

PR Close #30133
2019-04-26 11:07:34 -07:00
8dd9192fe3 refactor(ivy): undeprecate inject (#30132)
PR Close #30132
2019-04-26 11:06:42 -07:00
870e0dab48 fix(ivy): remove debug utilities from ivy production builds (#30130)
Prior to this commit, we were pulling DebugNode and DebugElement
into production builds because BrowserModule automatically pulled
in NgProbe and thus getDebugNode. In Ivy, this is not necessary
because Ivy has its own set of debug utilities. We should use these
existing tools instead of NgProbe.

This commit adds an Ivy switch so we do not pull in NgProbe utilities
when running with Ivy. This saves us ~8KB in prod builds.

PR Close #30130
2019-04-26 11:04:48 -07:00
66 changed files with 2668 additions and 2534 deletions

View File

@ -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:
@ -486,20 +486,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.
@ -693,10 +716,16 @@ workflows:
# More info is available here: https://github.com/angular/angular/issues/30101
# aio_monitoring:
# jobs:
# - aio_monitoring
# - setup
# - aio_monitoring_stable:
# requires:
# - setup
# - aio_monitoring_next:
# requires:
# - setup
# triggers:
# - schedule:
# # Runs AIO monitoring job at 00:00AM every day.
# # Runs AIO monitoring jobs at 00:00AM every day.
# cron: "0 0 * * *"
# filters:
# branches:

View File

@ -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;
}

View File

@ -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.
####################################################################################################

View File

@ -20,5 +20,6 @@ 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/...

3
.gitattributes vendored
View File

@ -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

View File

@ -1,3 +1,25 @@
<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)

View File

@ -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>

View File

@ -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.

View File

@ -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">

View File

@ -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*"},

View File

@ -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!"
)

View File

@ -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

View File

@ -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
}
}

View File

@ -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

View File

@ -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*"
]
}

View File

@ -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"
}
}
}

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -1,6 +1,6 @@
{
"name": "angular-srcs",
"version": "8.0.0-rc.0",
"version": "8.0.0-rc.2",
"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": {

View File

@ -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": {

View File

@ -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*"
]
}

View File

@ -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",

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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()`.
*/

View File

@ -3,6 +3,7 @@ load("//tools:defaults.bzl", "npm_package")
exports_files([
"tsconfig.json",
"migrations.json",
"test-migrations.json",
])
npm_package(

View File

@ -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"
}
}
}

View File

@ -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)));
}
}

View File

@ -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));
}
}

View File

@ -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;

View 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"
}
}
}

View File

@ -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",

View File

@ -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');
});
});

View File

@ -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); }
});

View File

@ -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); }
});

View File

@ -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.
`);
@ -533,7 +533,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 +542,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 +552,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 {}
`);

View File

@ -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;

View File

@ -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>',
})

View File

@ -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;
/**

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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++;
}
}

View File

@ -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

View File

@ -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'})

View File

@ -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);
});
});
});

View File

@ -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,136 @@ 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);
});
});

View File

@ -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

View File

@ -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>`);
});
});
});

View File

@ -7,7 +7,6 @@ ls_rollup_bundle(
"fs": "fs",
"path": "path",
"typescript": "ts",
"typescript/lib/tsserverlibrary": "tsserverlibrary",
},
license_banner = "banner.js.txt",
visibility = ["//packages/language-service:__pkg__"],

View File

@ -6,15 +6,16 @@
* found in the LICENSE file at https://angular.io/license
*/
import * as ts from 'typescript/lib/tsserverlibrary';
import * as ts from 'typescript'; // used as value, passed in by tsserver at runtime
import * as tss from 'typescript/lib/tsserverlibrary'; // used as type only
import {createLanguageService} from './language_service';
import {Completion, Diagnostic, DiagnosticMessageChain} from './types';
import {TypeScriptServiceHost} from './typescript_host';
const projectHostMap = new WeakMap<ts.server.Project, TypeScriptServiceHost>();
const projectHostMap = new WeakMap<tss.server.Project, TypeScriptServiceHost>();
export function getExternalFiles(project: ts.server.Project): string[]|undefined {
export function getExternalFiles(project: tss.server.Project): string[]|undefined {
const host = projectHostMap.get(project);
if (host) {
const externalFiles = host.getTemplateReferences();
@ -63,7 +64,7 @@ function diagnosticToDiagnostic(d: Diagnostic, file: ts.SourceFile): ts.Diagnost
return result;
}
export function create(info: ts.server.PluginCreateInfo): ts.LanguageService {
export function create(info: tss.server.PluginCreateInfo): ts.LanguageService {
const oldLS: ts.LanguageService = info.languageService;
const proxy: ts.LanguageService = Object.assign({}, oldLS);
const logger = info.project.projectService.logger;

View File

@ -7,12 +7,8 @@
*/
import * as path from 'path';
import * as ts from 'typescript';
import {createLanguageService} from '../src/language_service';
import {ReflectorHost} from '../src/reflector_host';
import {Completions, LanguageService} from '../src/types';
import {TypeScriptServiceHost} from '../src/typescript_host';
import {toh} from './test_data';
import {MockTypescriptHost} from './test_utils';
@ -25,12 +21,14 @@ describe('reflector_host_spec', () => {
let mockHost = new MockTypescriptHost(
['/app/main.ts', '/app/parsing-cases.ts'], toh, 'app/node_modules',
{...path, join: (...args: string[]) => originalJoin.apply(path, args)});
let service = ts.createLanguageService(mockHost);
let ngHost = new TypeScriptServiceHost(mockHost, service);
let ngService = createLanguageService(ngHost);
const reflectorHost = new ReflectorHost(() => undefined as any, mockHost, {basePath: '\\app'});
spyOn(path, 'join').and.callFake((...args: string[]) => { return path.win32.join(...args); });
if (process.platform !== 'win32') {
// If we call this in Windows it will cause a 'Maximum call stack size exceeded error'
// Because we are spying on the same function that we are call faking
spyOn(path, 'join').and.callFake((...args: string[]) => { return path.win32.join(...args); });
}
const result = reflectorHost.moduleNameToFileName('@angular/core');
expect(result).not.toBeNull('could not find @angular/core using path.win32');
});

View File

@ -36,10 +36,19 @@ function _ngProbeTokensToMap(tokens: core.NgProbeToken[]): {[name: string]: any}
return tokens.reduce((prev: any, t: any) => (prev[t.name] = t.token, prev), {});
}
/**
* In Ivy, we don't support NgProbe because we have our own set of testing utilities
* with more robust functionality.
*
* We shouldn't bring in NgProbe because it prevents DebugNode and friends from
* tree-shaking properly.
*/
export const ELEMENT_PROBE_PROVIDERS__POST_R3__ = [];
/**
* Providers which support debugging Angular applications (e.g. via `ng.probe`).
*/
export const ELEMENT_PROBE_PROVIDERS: core.Provider[] = [
export const ELEMENT_PROBE_PROVIDERS__PRE_R3__: core.Provider[] = [
{
provide: core.APP_INITIALIZER,
useFactory: _createNgProbe,
@ -49,3 +58,5 @@ export const ELEMENT_PROBE_PROVIDERS: core.Provider[] = [
multi: true,
},
];
export const ELEMENT_PROBE_PROVIDERS = ELEMENT_PROBE_PROVIDERS__PRE_R3__;

View File

@ -18,3 +18,5 @@ export {DomSanitizer, SafeHtml, SafeResourceUrl, SafeScript, SafeStyle, SafeUrl,
export * from './private_export';
export {VERSION} from './version';
// This must be exported so it doesn't get tree-shaken away prematurely
export {ELEMENT_PROBE_PROVIDERS__POST_R3__ as ɵELEMENT_PROBE_PROVIDERS__POST_R3__} from './dom/debug/ng_probe';

View File

@ -383,7 +383,6 @@ export interface HostListenerDecorator {
new (eventName: string, args?: string[]): any;
}
/** @deprecated */
export declare const inject: typeof ɵɵinject;
export interface Inject {
@ -944,25 +943,25 @@ export declare function ɵɵprojectionDef(selectors?: CssSelectorList[]): void;
export declare function ɵɵproperty<T>(propName: string, value: T, sanitizer?: SanitizerFn | null, nativeOnly?: boolean): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate(propName: string, v0: any): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate(propName: string, v0: any, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate1(propName: string, prefix: string, v0: any, suffix: string): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate1(propName: string, prefix: string, v0: any, suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate2(propName: string, prefix: string, v0: any, i0: string, v1: any, suffix: string): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate2(propName: string, prefix: string, v0: any, i0: string, v1: any, suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate3(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate3(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate4(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, suffix: string): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate4(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare 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;
export declare 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, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare 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;
export declare 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, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare 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;
export declare 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, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare 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;
export declare 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, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare function ɵɵpropertyInterpolateV(propName: string, values: any[]): TsickleIssue1009;
export declare function ɵɵpropertyInterpolateV(propName: string, values: any[], sanitizer?: SanitizerFn): TsickleIssue1009;
export declare function ɵɵProvidersFeature<T>(providers: Provider[], viewProviders?: Provider[]): (definition: DirectiveDef<T>) => void;

View File

@ -43,7 +43,7 @@ function main(argv: [string, string, string] | [string, string]): boolean {
const defineFlag = (compile !== 'legacy') ? `--define=compile=${compile} ` : '';
console.error(`TEST FAILED!`);
console.error(` To update the golden file run: `);
console.error(` yarn bazel run ${defineFlag}${process.env['BAZEL_TARGET']}.accept`);
console.error(` yarn bazel run ${defineFlag}${process.env['TEST_TARGET']}.accept`);
}
}
return passed;

View File

@ -3,12 +3,11 @@
# Use of this source code is governed by an MIT-style license that can be
# found in the LICENSE file at https://angular.io/license
"""This test verifies that a set of top level symbols from a javascript file match a gold file.
"""
load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary", "nodejs_test")
# This does a deep import under //internal because of not wanting the wrapper macro
# because it introduces an extra target_bin target.
load("@build_bazel_rules_nodejs//internal/node:node.bzl", "nodejs_binary", "nodejs_test")
"""
This test verifies that a set of top level symbols from a javascript file match a gold file.
"""
def js_expected_symbol_test(name, src, golden, data = [], **kwargs):
"""This test verifies that a set of top level symbols from a javascript file match a gold file.
@ -17,7 +16,6 @@ def js_expected_symbol_test(name, src, golden, data = [], **kwargs):
src,
golden,
Label("//tools/symbol-extractor:lib"),
Label("@bazel_tools//tools/bash/runfiles"),
Label("@npm//typescript"),
]
entry_point = "angular/tools/symbol-extractor/cli.js"

View File

@ -37,6 +37,11 @@ def ts_api_guardian_test(
# But it will replaced to @npm//ts-api-guardian when publishing
"@angular//tools/ts-api-guardian:lib",
"@angular//tools/ts-api-guardian:bin",
# The below are required during runtime
"@npm//chalk",
"@npm//diff",
"@npm//minimist",
"@npm//typescript",
]
args = [
@ -46,7 +51,8 @@ def ts_api_guardian_test(
]
for i in strip_export_pattern:
args += ["--stripExportPattern", i]
# The below replacement is needed because under Windows '^' needs to be escaped twice
args += ["--stripExportPattern", i.replace("^", "^^^^")]
for i in allow_module_identifiers:
args += ["--allowModuleIdentifiers", i]

View File

@ -298,7 +298,7 @@ class ResolvedDeclarationEmitter {
const jsdocComment = this.processJsDocTags(node, tagOptions);
if (jsdocComment) {
// Add the annotation after the leading whitespace
output = output.replace(/^(\n\s*)/, `$1${jsdocComment} `);
output = output.replace(/^(\r?\n\s*)/, `$1${jsdocComment} `);
}
}

View File

@ -124,7 +124,11 @@ function execute(args: string[]): {stdout: string, stderr: string, status: numbe
// We need to determine the directory that includes the `ts-api-guardian` npm_package that
// will be used to spawn the CLI binary. This is a workaround because technically we shouldn't
// spawn a child process that doesn't have the custom NodeJS module resolution for Bazel.
const nodePath = path.join(path.dirname(require.resolve('../lib/cli.js')), '../');
const nodePath = [
path.join(require.resolve('npm/node_modules/chalk/package.json'), '../../'),
path.join(require.resolve('../lib/cli.js'), '../../'),
].join(process.platform === 'win32' ? ';' : ':');
const output = child_process.spawnSync(process.execPath, [BINARY_PATH, ...args], {
env: {
'NODE_PATH': nodePath,

232
yarn.lock
View File

@ -952,6 +952,11 @@ ansi-regex@^4.0.0:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9"
integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==
ansi-regex@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
@ -1851,6 +1856,11 @@ camelcase@^4.0.0, camelcase@^4.1.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
camelcase@^5.0.0:
version "5.3.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
canonical-path@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-1.0.0.tgz#fcb470c23958def85081856be7a86e904f180d1d"
@ -2158,15 +2168,6 @@ cliui@^2.1.0:
right-align "^0.1.1"
wordwrap "0.0.2"
cliui@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=
dependencies:
string-width "^1.0.1"
strip-ansi "^3.0.1"
wrap-ansi "^2.0.0"
cliui@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49"
@ -2840,7 +2841,7 @@ cross-spawn@^5.0.1:
shebang-command "^1.2.0"
which "^1.2.9"
cross-spawn@^6.0.5:
cross-spawn@^6.0.0, cross-spawn@^6.0.5:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
@ -3004,7 +3005,7 @@ decamelize-keys@^1.0.0:
decamelize "^1.1.0"
map-obj "^1.0.0"
decamelize@^1.0.0, decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2:
decamelize@^1.0.0, decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
@ -3300,6 +3301,11 @@ ee-first@1.1.1:
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
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"
@ -3663,6 +3669,19 @@ execa@^0.7.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
execa@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
dependencies:
cross-spawn "^6.0.0"
get-stream "^4.0.0"
is-stream "^1.1.0"
npm-run-path "^2.0.0"
p-finally "^1.0.0"
signal-exit "^3.0.0"
strip-eof "^1.0.0"
exit-code@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/exit-code/-/exit-code-1.0.2.tgz#ce165811c9f117af6a5f882940b96ae7f9aecc34"
@ -4014,6 +4033,13 @@ find-up@^2.0.0, find-up@^2.1.0:
dependencies:
locate-path "^2.0.0"
find-up@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
dependencies:
locate-path "^3.0.0"
findup-sync@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc"
@ -4495,9 +4521,14 @@ genfun@^5.0.0:
integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==
get-caller-file@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
integrity sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=
version "1.0.3"
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-func-name@^2.0.0:
version "2.0.0"
@ -4525,7 +4556,7 @@ get-stream@3.0.0, get-stream@^3.0.0:
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
get-stream@^4.1.0:
get-stream@^4.0.0, get-stream@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
@ -5530,6 +5561,11 @@ invert-kv@^1.0.0:
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
invert-kv@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==
ip@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
@ -6502,6 +6538,13 @@ lcid@^1.0.0:
dependencies:
invert-kv "^1.0.0"
lcid@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==
dependencies:
invert-kv "^2.0.0"
levn@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
@ -6547,16 +6590,6 @@ load-json-file@^1.0.0:
pinkie-promise "^2.0.0"
strip-bom "^2.0.0"
load-json-file@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8"
integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=
dependencies:
graceful-fs "^4.1.2"
parse-json "^2.2.0"
pify "^2.0.0"
strip-bom "^3.0.0"
load-json-file@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
@ -6594,6 +6627,14 @@ locate-path@^2.0.0:
p-locate "^2.0.0"
path-exists "^3.0.0"
locate-path@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
dependencies:
p-locate "^3.0.0"
path-exists "^3.0.0"
lodash._basecopy@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36"
@ -7000,6 +7041,13 @@ make-iterator@^1.0.0:
dependencies:
kind-of "^6.0.2"
map-age-cleaner@^0.1.1:
version "0.1.3"
resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a"
integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==
dependencies:
p-defer "^1.0.0"
map-cache@^0.2.0, map-cache@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
@ -7062,6 +7110,15 @@ mem@^1.1.0:
dependencies:
mimic-fn "^1.0.0"
mem@^4.0.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178"
integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==
dependencies:
map-age-cleaner "^0.1.1"
mimic-fn "^2.0.0"
p-is-promise "^2.0.0"
memoizeasync@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/memoizeasync/-/memoizeasync-1.1.0.tgz#9d7028a6f266deb733510bb7dbba5f51878c561e"
@ -7264,6 +7321,11 @@ mimic-fn@^1.0.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
mimic-fn@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
mimic-response@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
@ -8025,6 +8087,15 @@ os-locale@^2.0.0:
lcid "^1.0.0"
mem "^1.1.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==
dependencies:
execa "^1.0.0"
lcid "^2.0.0"
mem "^4.0.0"
os-shim@^0.1.2:
version "0.1.3"
resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917"
@ -8053,6 +8124,11 @@ p-cancelable@^0.4.0:
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0"
integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==
p-defer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=
p-finally@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
@ -8063,6 +8139,11 @@ p-is-promise@^1.1.0:
resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e"
integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=
p-is-promise@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.0.0.tgz#7554e3d572109a87e1f3f53f6a7d85d1b194f4c5"
integrity sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==
p-limit@^1.1.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
@ -8070,6 +8151,13 @@ p-limit@^1.1.0:
dependencies:
p-try "^1.0.0"
p-limit@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2"
integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==
dependencies:
p-try "^2.0.0"
p-locate@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
@ -8077,6 +8165,13 @@ p-locate@^2.0.0:
dependencies:
p-limit "^1.1.0"
p-locate@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
dependencies:
p-limit "^2.0.0"
p-timeout@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038"
@ -8089,6 +8184,11 @@ p-try@^1.0.0:
resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
p-try@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
package-json@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed"
@ -8304,13 +8404,6 @@ path-type@^1.0.0:
pify "^2.0.0"
pinkie-promise "^2.0.0"
path-type@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=
dependencies:
pify "^2.0.0"
path-type@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
@ -8787,14 +8880,6 @@ read-pkg-up@^1.0.1:
find-up "^1.0.0"
read-pkg "^1.0.0"
read-pkg-up@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be"
integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=
dependencies:
find-up "^2.0.0"
read-pkg "^2.0.0"
read-pkg-up@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07"
@ -8812,15 +8897,6 @@ read-pkg@^1.0.0, read-pkg@^1.1.0:
normalize-package-data "^2.3.2"
path-type "^1.0.0"
read-pkg@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8"
integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=
dependencies:
load-json-file "^2.0.0"
normalize-package-data "^2.3.2"
path-type "^2.0.0"
read-pkg@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
@ -9143,6 +9219,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==
requirejs@2.3.5:
version "2.3.5"
resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.5.tgz#617b9acbbcb336540ef4914d790323a8d4b861b0"
@ -10220,6 +10301,15 @@ string-width@^1.0.1:
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_decoder@~0.10.25, string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
@ -10258,6 +10348,13 @@ strip-ansi@^5.0.0:
dependencies:
ansi-regex "^4.0.0"
strip-ansi@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
dependencies:
ansi-regex "^4.1.0"
strip-bom-buf@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz#1cb45aaf57530f4caf86c7f75179d2c9a51dd572"
@ -11614,12 +11711,13 @@ yallist@^3.0.0, yallist@^3.0.2:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
yargs-parser@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9"
integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k=
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 "^4.1.0"
camelcase "^5.0.0"
decamelize "^1.2.0"
yargs-parser@^9.0.2:
version "9.0.2"
@ -11646,24 +11744,22 @@ yargs@11.0.0:
y18n "^3.2.1"
yargs-parser "^9.0.2"
yargs@9.0.1:
version "9.0.1"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c"
integrity sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=
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:
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"
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 "^1.0.1"
require-main-filename "^2.0.0"
set-blocking "^2.0.0"
string-width "^2.0.0"
string-width "^3.0.0"
which-module "^2.0.0"
y18n "^3.2.1"
yargs-parser "^7.0.0"
y18n "^4.0.0"
yargs-parser "^13.0.0"
yargs@^11.0.0:
version "11.1.0"