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 - *attach_workspace
- *init_environment - *init_environment
# Deploy angular.io to production (if necessary) # 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 - run: yarn --cwd aio deploy-production
test_aio_local: test_aio_local:
@ -486,20 +486,43 @@ jobs:
command: 'openssl aes-256-cbc -d -in .circleci/github_token -k "${KEY}" -out ~/.git_credentials' command: 'openssl aes-256-cbc -d -in .circleci/github_token -k "${KEY}" -out ~/.git_credentials'
- run: ./scripts/ci/publish-build-artifacts.sh - run: ./scripts/ci/publish-build-artifacts.sh
aio_monitoring: aio_monitoring_stable:
<<: *job_defaults <<: *job_defaults
docker: docker:
# This job needs Chrome to be globally installed because the tests run with Protractor # 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. # which does not load the browser through the Bazel webtesting rules.
- image: *browsers_docker_image - image: *browsers_docker_image
steps: steps:
- checkout - *attach_workspace
- *post_checkout - *init_environment
- *restore_cache - 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 - *init_environment
- run: - run:
name: Run tests against the deployed apps name: Run tests against https://next.angular.io/
command: ./aio/scripts/test-production.sh $CI_AIO_MIN_PWA_SCORE command: ./aio/scripts/test-production.sh https://next.angular.io/ $CI_AIO_MIN_PWA_SCORE
- run: - run:
name: Notify caretaker about failure name: Notify caretaker about failure
# `$SLACK_CARETAKER_WEBHOOK_URL` is a secret env var defined in CircleCI project settings. # `$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 # More info is available here: https://github.com/angular/angular/issues/30101
# aio_monitoring: # aio_monitoring:
# jobs: # jobs:
# - aio_monitoring # - setup
# - aio_monitoring_stable:
# requires:
# - setup
# - aio_monitoring_next:
# requires:
# - setup
# triggers: # triggers:
# - schedule: # - schedule:
# # Runs AIO monitoring job at 00:00AM every day. # # Runs AIO monitoring jobs at 00:00AM every day.
# cron: "0 0 * * *" # cron: "0 0 * * *"
# filters: # filters:
# branches: # branches:

View File

@ -36,3 +36,38 @@ function setSecretVar() {
# Restore original shell options. # Restore original shell options.
eval "$originalShellOptions"; 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"; 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. # Define SECRET environment variables for CircleCI.
#################################################################################################### ####################################################################################################

View File

@ -20,5 +20,6 @@ steps:
# Add Bazel CI config # Add Bazel CI config
- copy .codefresh\bazel.rc %ProgramData%\bazel.bazelrc - copy .codefresh\bazel.rc %ProgramData%\bazel.bazelrc
# Run tests # 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 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 *.js eol=lf
*.ts 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 # Must keep Windows line ending to be parsed correctly
scripts/windows/packages.txt eol=crlf 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> <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) # [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"> <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). **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).
**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.
</div> </div>

View File

@ -157,7 +157,7 @@ export class <%= classify(name) %>Service {
</code-example> </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. * 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 ## 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. By default, the `src/assets/` folder and `src/favicon.ico` are copied over.
<code-example format="." language="json" linenums="false"> <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/SelectControlValueAccessor-*", "destination": "/api/forms/SelectControlValueAccessor"},
{"type": 301, "source": "/**/api/common/NgModel", "destination": "/api/forms/NgModel"}, {"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 // `@angular/http` package was removed, and new `HttpClient` APIs are available under `@angular/common/http` package
{"type": 301, "source": "/api/http/:rest*", "destination": "/guide/deprecation#http"}, {"type": 301, "source": "/api/http/:rest*", "destination": "/guide/deprecations#http"},
{"type": 301, "source": "/api/http", "destination": "/guide/deprecation#http"}, {"type": 301, "source": "/api/http", "destination": "/guide/deprecations#http"},
// Animations moves, renames and removals // Animations moves, renames and removals
{"type": 301, "source": "/api/animate/:rest*", "destination": "/api/animations/:rest*"}, {"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 aioDir="$(realpath $thisDir/..)"
readonly protractorConf="$aioDir/tests/deployment/e2e/protractor.conf.js" readonly protractorConf="$aioDir/tests/deployment/e2e/protractor.conf.js"
readonly minPwaScore="$1" readonly targetUrl="$1"
readonly urls=( readonly minPwaScore="$2"
"https://angular.io/"
"https://next.angular.io/"
)
cd "$aioDir" cd "$aioDir"
@ -19,16 +16,14 @@ set +x -eu -o pipefail
yarn install --frozen-lockfile --non-interactive yarn install --frozen-lockfile --non-interactive
yarn update-webdriver yarn update-webdriver
# Run checks for all URLs. # Run checks for target URL.
for url in "${urls[@]}"; do echo -e "\nChecking '$targetUrl'...\n-----"
echo -e "\nChecking '$url'...\n-----"
# Run basic e2e and deployment config tests. # Run basic e2e and deployment config tests.
yarn protractor "$protractorConf" --baseUrl "$url" yarn protractor "$protractorConf" --baseUrl "$targetUrl"
# Run PWA-score tests. # Run PWA-score tests.
yarn test-pwa-score "$url" "$minPwaScore" yarn test-pwa-score "$targetUrl" "$minPwaScore"
done
echo -e "\nAll checks passed!" 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/index/TestBed-class.html /api/core/testing/TestBed
/api/core/testing/inject-function /api/core/testing/inject /api/core/testing/inject-function /api/core/testing/inject
/api/core/testing/inject-function.html /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 /guide/deprecations#http
/api/http/Headers-class.html /guide/deprecation#http /api/http/Headers-class.html /guide/deprecations#http
/api/http/HTTP_PROVIDERS-let /guide/deprecation#http /api/http/HTTP_PROVIDERS-let /guide/deprecations#http
/api/http/testing/index/MockBackend-class /guide/deprecation#http /api/http/testing/index/MockBackend-class /guide/deprecations#http
/api/http/testing/index/MockBackend-class.html /guide/deprecation#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-dynamic/testing/index/platformBrowserDynamicTesting-let.html /api/platform-browser-dynamic/testing/platformBrowserDynamicTesting
/api/platform-browser/AnimationDriver /api/animations/browser/AnimationDriver /api/platform-browser/AnimationDriver /api/animations/browser/AnimationDriver
/api/router/Route-class /api/router/Route /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/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/NG_VALIDATORS-let /api/forms/NG_VALIDATORS
/docs/js/latest/api/forms/index/Validator-interface.html /api/forms/Validator /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/ConnectionBackend-class /guide/deprecations#http
/docs/js/latest/api/http/index/Http-class.html /guide/deprecation#http /docs/js/latest/api/http/index/Http-class.html /guide/deprecations#http
/docs/js/latest/api/http/index/Jsonp-class.html /guide/deprecation#http /docs/js/latest/api/http/index/Jsonp-class.html /guide/deprecations#http
/docs/js/latest/api/http/index/ResponseOptions-class.html /guide/deprecation#http /docs/js/latest/api/http/index/ResponseOptions-class.html /guide/deprecations#http
/docs/js/latest/api/http/index/URLSearchParams-class /guide/deprecation#http /docs/js/latest/api/http/index/URLSearchParams-class /guide/deprecations#http
/docs/js/latest/api/http/index/XHRConnection-class /guide/deprecation#http /docs/js/latest/api/http/index/XHRConnection-class /guide/deprecations#http
/docs/js/latest/api/http/index/XHRConnection-class.html /guide/deprecation#http /docs/js/latest/api/http/index/XHRConnection-class.html /guide/deprecations#http
/docs/js/latest/api/http/testing/index/MockConnection-class.html /guide/deprecation#http /docs/js/latest/api/http/testing/index/MockConnection-class.html /guide/deprecations#http
/docs/js/latest/api/http/testing/MockBackend-class /guide/deprecation#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/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-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 /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/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/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/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/Connection-class.html /guide/deprecations#http
/docs/ts/latest/api/http/testing/index/MockBackend-class.html /guide/deprecation#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/deprecation#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/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/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 /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": { "master": {
"uncompressed": { "uncompressed": {
"runtime": 1497, "runtime": 1497,
"main": 167065, "main": 164945,
"polyfills": 43626 "polyfills": 43626
} }
} }
@ -12,7 +12,7 @@
"master": { "master": {
"uncompressed": { "uncompressed": {
"runtime": 1440, "runtime": 1440,
"main": 30932, "main": 14487,
"polyfills": 43567 "polyfills": 43567
} }
} }
@ -21,7 +21,7 @@
"master": { "master": {
"uncompressed": { "uncompressed": {
"runtime": 1440, "runtime": 1440,
"main": 157393, "main": 149205,
"polyfills": 43567 "polyfills": 43567
} }
} }

View File

@ -9,7 +9,7 @@ function installLocalPackages() {
readonly pwd=$(pwd) readonly pwd=$(pwd)
readonly packages=( readonly packages=(
animations common compiler core forms platform-browser 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=() local local_packages=()
for package in "${packages[@]}"; do for package in "${packages[@]}"; do

View File

@ -23,6 +23,7 @@
"node_modules/@angular/core/schematics/**", "node_modules/@angular/core/schematics/**",
"node_modules/@angular/compiler-cli/**", "node_modules/@angular/compiler-cli/**",
"node_modules/@angular/**/testing/**", "node_modules/@angular/**/testing/**",
"node_modules/@angular/common/upgrade*",
"node_modules/@angular/router/upgrade*" "node_modules/@angular/router/upgrade*"
] ]
} }

View File

@ -10,7 +10,6 @@
"@angular/platform-browser": "packages-dist:platform-browser", "@angular/platform-browser": "packages-dist:platform-browser",
"@angular/platform-browser-dynamic": "packages-dist:platform-browser-dynamic", "@angular/platform-browser-dynamic": "packages-dist:platform-browser-dynamic",
"@angular/router": "packages-dist:router", "@angular/router": "packages-dist:router",
"@angular/upgrade": "packages-dist:upgrade",
"reflect-metadata": "0.1.12", "reflect-metadata": "0.1.12",
"rxjs": "6.4.0", "rxjs": "6.4.0",
"tslib": "1.9.3", "tslib": "1.9.3",
@ -31,4 +30,4 @@
"postinstall": "ngc -p ./angular-metadata.tsconfig.json", "postinstall": "ngc -p ./angular-metadata.tsconfig.json",
"//": "TODO(gregmagolan): figure out how to keep dependencies here up to date with the root package.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" "zone.js": "file:../../node_modules/zone.js"
}, },
"devDependencies": { "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/cli": "file:../../node_modules/@angular/cli",
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli", "@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
"@angular/language-service": "file:../../dist/packages-dist/language-service", "@angular/language-service": "file:../../dist/packages-dist/language-service",

View File

@ -28,7 +28,7 @@
"zone.js": "file:../../node_modules/zone.js" "zone.js": "file:../../node_modules/zone.js"
}, },
"devDependencies": { "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/cli": "file:../../node_modules/@angular/cli",
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli", "@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
"@angular/language-service": "file:../../dist/packages-dist/language-service", "@angular/language-service": "file:../../dist/packages-dist/language-service",

View File

@ -28,7 +28,7 @@
"zone.js": "file:../../node_modules/zone.js" "zone.js": "file:../../node_modules/zone.js"
}, },
"devDependencies": { "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/cli": "file:../../node_modules/@angular/cli",
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli", "@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
"@angular/language-service": "file:../../dist/packages-dist/language-service", "@angular/language-service": "file:../../dist/packages-dist/language-service",

View File

@ -1,6 +1,6 @@
{ {
"name": "angular-srcs", "name": "angular-srcs",
"version": "8.0.0-rc.0", "version": "8.0.0-rc.2",
"private": true, "private": true,
"branchPattern": "2.0.*", "branchPattern": "2.0.*",
"description": "Angular - a web framework for modern web apps", "description": "Angular - a web framework for modern web apps",
@ -107,7 +107,7 @@
"tslint": "5.7.0", "tslint": "5.7.0",
"typescript": "~3.4.2", "typescript": "~3.4.2",
"xhr2": "0.1.4", "xhr2": "0.1.4",
"yargs": "9.0.1", "yargs": "13.1.0",
"zone.js": "^0.9.0" "zone.js": "^0.9.0"
}, },
"optionalDependencies": { "optionalDependencies": {

View File

@ -34,11 +34,11 @@
"@types/node": "6.0.84", "@types/node": "6.0.84",
"semver": "^5.6.0", "semver": "^5.6.0",
"shelljs": "0.8.2", "shelljs": "0.8.2",
"tsickle": "0.34.3" "tsickle": "^0.35.0"
}, },
"peerDependencies": { "peerDependencies": {
"@angular/compiler-cli": "0.0.0-PLACEHOLDER", "@angular/compiler-cli": "0.0.0-PLACEHOLDER",
"@bazel/typescript": "0.27.12", "@bazel/typescript": "0.*",
"typescript": ">=3.4 <3.5" "typescript": ">=3.4 <3.5"
}, },
"repository": { "repository": {

View File

@ -20,6 +20,7 @@
"node_modules/@angular/core/schematics/**", "node_modules/@angular/core/schematics/**",
"node_modules/@angular/compiler-cli/**", "node_modules/@angular/compiler-cli/**",
"node_modules/@angular/**/testing/**", "node_modules/@angular/**/testing/**",
"node_modules/@angular/common/upgrade*",
"node_modules/@angular/router/upgrade*" "node_modules/@angular/router/upgrade*"
] ]
} }

View File

@ -20,7 +20,7 @@
"shelljs": "^0.8.1", "shelljs": "^0.8.1",
"source-map": "^0.6.1", "source-map": "^0.6.1",
"tslib": "^1.9.0", "tslib": "^1.9.0",
"yargs": "9.0.1" "yargs": "13.1.0"
}, },
"peerDependencies": { "peerDependencies": {
"@angular/compiler": "0.0.0-PLACEHOLDER", "@angular/compiler": "0.0.0-PLACEHOLDER",

View File

@ -470,7 +470,7 @@ describe('compiler compliance: bindings', () => {
if (rf & 2) { if (rf & 2) {
i0.ɵɵselect(0); 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.ɵɵ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.ɵɵ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); i0.ɵɵselect(2);

View File

@ -122,20 +122,21 @@ export function setupBazelTo(tmpDirPath: string) {
fs.mkdirSync(nodeModulesPath); fs.mkdirSync(nodeModulesPath);
fs.mkdirSync(angularDirectory); fs.mkdirSync(angularDirectory);
getAngularPackagesFromRunfiles().forEach( getAngularPackagesFromRunfiles().forEach(({pkgPath, name}) => {
({pkgPath, name}) => { fs.symlinkSync(pkgPath, path.join(angularDirectory, name), 'dir'); }); fs.symlinkSync(pkgPath, path.join(angularDirectory, name), 'junction');
});
// Link typescript // Link typescript
const typeScriptSource = resolveNpmTreeArtifact('npm/node_modules/typescript'); const typeScriptSource = resolveNpmTreeArtifact('npm/node_modules/typescript');
const typescriptDest = path.join(nodeModulesPath, '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 // 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. // not all compiler-cli tests need "rxjs" set up.
try { try {
const rxjsSource = resolveNpmTreeArtifact('rxjs', 'index.js'); const rxjsSource = resolveNpmTreeArtifact('rxjs', 'index.js');
const rxjsDest = path.join(nodeModulesPath, 'rxjs'); const rxjsDest = path.join(nodeModulesPath, 'rxjs');
fs.symlinkSync(rxjsSource, rxjsDest, 'dir'); fs.symlinkSync(rxjsSource, rxjsDest, 'junction');
} catch (e) { } catch (e) {
if (e.code !== 'MODULE_NOT_FOUND') throw e; if (e.code !== 'MODULE_NOT_FOUND') throw e;
} }

View File

@ -155,16 +155,12 @@ export function convertPropertyBinding(
localResolver = new DefaultLocalResolver(); localResolver = new DefaultLocalResolver();
} }
const currValExpr = createCurrValueExpr(bindingId); const currValExpr = createCurrValueExpr(bindingId);
const stmts: o.Statement[] = [];
const visitor = const visitor =
new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction); new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction);
const outputExpr: o.Expression = expressionWithoutBuiltins.visit(visitor, _Mode.Expression); const outputExpr: o.Expression = expressionWithoutBuiltins.visit(visitor, _Mode.Expression);
const stmts: o.Statement[] = getStatementsFromVisitor(visitor, bindingId);
if (visitor.temporaryCount) { if (visitor.temporaryCount === 0 && form == BindingForm.TrySimple) {
for (let i = 0; i < visitor.temporaryCount; i++) {
stmts.push(temporaryDeclaration(bindingId, i));
}
} else if (form == BindingForm.TrySimple) {
return new ConvertPropertyBindingResult([], outputExpr); return new ConvertPropertyBindingResult([], outputExpr);
} }
@ -172,6 +168,58 @@ export function convertPropertyBinding(
return new ConvertPropertyBindingResult(stmts, currValExpr); 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 { function convertBuiltins(converterFactory: BuiltinConverterFactory, ast: cdAst.AST): cdAst.AST {
const visitor = new _BuiltinAstConverter(converterFactory); const visitor = new _BuiltinAstConverter(converterFactory);
return ast.visit(visitor); return ast.visit(visitor);

View File

@ -7,7 +7,7 @@
*/ */
import {flatten, sanitizeIdentifier} from '../../compile_metadata'; 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 {ConstantPool} from '../../constant_pool';
import * as core from '../../core'; import * as core from '../../core';
import {AST, AstMemoryEfficientTransformer, BindingPipe, BindingType, FunctionCall, ImplicitReceiver, Interpolation, LiteralArray, LiteralMap, LiteralPrimitive, ParsedEventType, PropertyRead} from '../../expression_parser/ast'; 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 (inputType === BindingType.Property) {
if (value instanceof Interpolation) { 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( this.updateInstruction(
elementIndex, input.sourceSpan, propertyInterpolate(args.length), () => { elementIndex, input.sourceSpan, getPropertyInterpolationExpression(value),
return [o.literal(attrName), ...args, ...params]; () =>
}); [o.literal(attrName),
...this.getUpdateInstructionArguments(o.variable(CONTEXT_NAME), value),
...params]);
} else { } else {
// Bound, un-interpolated properties // Bound, un-interpolated properties
this.updateInstruction(elementIndex, input.sourceSpan, R3.property, () => { 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]); 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) { private matchDirectives(tagName: string, elOrTpl: t.Element|t.Template) {
if (this.directiveMatcher) { if (this.directiveMatcher) {
const selector = createCssSelector(tagName, getAttrsForDirectiveMatching(elOrTpl)); 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)]); return o.importExpr(R3.interpolationV).callFn([o.literalArr(args)]);
} }
function isEmptyStringExpression(exp: o.Expression) { /**
return exp instanceof o.LiteralExpr && exp.value === ''; * Gets the instruction to generate for an interpolated property
} * @param interpolation An Interpolation AST
*/
function propertyInterpolate(argsLength: number) { function getPropertyInterpolationExpression(interpolation: Interpolation) {
if (argsLength % 2 !== 1) { switch (getInterpolationArgsLength(interpolation)) {
error(`Invalid propertyInterpolate argument length ${argsLength}`);
}
switch (argsLength) {
case 1: case 1:
return R3.propertyInterpolate; return R3.propertyInterpolate;
case 3: 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()`. * 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([ exports_files([
"tsconfig.json", "tsconfig.json",
"migrations.json", "migrations.json",
"test-migrations.json",
]) ])
npm_package( npm_package(

View File

@ -14,11 +14,6 @@
"version": "8-beta", "version": "8-beta",
"description": "Warns developers if values are assigned to template variables", "description": "Warns developers if values are assigned to template variables",
"factory": "./migrations/template-var-assignment/index" "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 * as ts from 'typescript';
import {InjectablePipeVisitor} from '../angular/injectable_pipe_visitor'; 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`. * 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( fixes.push(new Replacement(
namedImports.getStart(), namedImports.getWidth(), namedImports.getStart(), namedImports.getWidth(),
printer.printNode( printer.printNode(
ts.EmitHint.Unspecified, ts.EmitHint.Unspecified, addImport(namedImports, INJECTABLE_DECORATOR_NAME),
addNamedImport(importDeclarationMissingImport, INJECTABLE_DECORATOR_NAME),
sourceFile))); sourceFile)));
} }
} }

View File

@ -14,7 +14,7 @@ import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths';
import {parseTsconfigFile} from '../../utils/typescript/parse_tsconfig'; import {parseTsconfigFile} from '../../utils/typescript/parse_tsconfig';
import {InjectablePipeVisitor} from './angular/injectable_pipe_visitor'; 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` * Runs a migration over a TypeScript project that adds an `@Injectable`
@ -78,8 +78,7 @@ function runInjectablePipeMigration(tree: Tree, tsconfigPath: string, basePath:
update.insertRight( update.insertRight(
namedImports.getStart(), namedImports.getStart(),
printer.printNode( printer.printNode(
ts.EmitHint.Unspecified, ts.EmitHint.Unspecified, addImport(namedImports, INJECTABLE_DECORATOR_NAME),
addNamedImport(importDeclarationMissingImport, INJECTABLE_DECORATOR_NAME),
sourceFile)); sourceFile));
} }
} }

View File

@ -12,28 +12,17 @@ import * as ts from 'typescript';
export const INJECTABLE_DECORATOR_NAME = 'Injectable'; 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 node Node to which to add the import.
* @param importName Name of the import that should be added. * @param importName Name of the import that should be added.
*/ */
export function addNamedImport(node: ts.ImportDeclaration, importName: string) { export function addImport(node: ts.NamedImports, importName: string) {
const namedImports = getNamedImports(node); const elements = node.elements;
const isAlreadyImported = elements.some(element => element.name.text === importName);
if (namedImports && ts.isNamedImports(namedImports)) { if (!isAlreadyImported) {
const elements = namedImports.elements; return ts.updateNamedImports(
const isAlreadyImported = elements.some(element => element.name.text === importName); node, [...elements, ts.createImportSpecifier(undefined, ts.createIdentifier(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);
}
} }
return node; 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, testonly = True,
srcs = glob(["**/*.ts"]), srcs = glob(["**/*.ts"]),
data = [ data = [
"//packages/core/schematics:migrations.json", "//packages/core/schematics:test-migrations.json",
], ],
deps = [ deps = [
"//packages/core/schematics/migrations/injectable-pipe", "//packages/core/schematics/migrations/injectable-pipe",

View File

@ -85,7 +85,10 @@ describe('Google3 injectable pipe TSLint rule', () => {
`); `);
runTSLint(); 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; let previousWorkingDir: string;
beforeEach(() => { beforeEach(() => {
runner = new SchematicTestRunner('test', require.resolve('../migrations.json')); runner = new SchematicTestRunner('test', require.resolve('../test-migrations.json'));
host = new TempScopedNodeJsSyncHost(); host = new TempScopedNodeJsSyncHost();
tree = new UnitTestTree(new HostTree(host)); tree = new UnitTestTree(new HostTree(host));
@ -70,8 +70,10 @@ describe('injectable pipe migration', () => {
`); `);
runMigration(); 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', () => { 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)); 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; let previousWorkingDir: string;
beforeEach(() => { beforeEach(() => {
runner = new SchematicTestRunner('test', require.resolve('../migrations.json')); runner = new SchematicTestRunner('test', require.resolve('../test-migrations.json'));
host = new TempScopedNodeJsSyncHost(); host = new TempScopedNodeJsSyncHost();
tree = new UnitTestTree(new HostTree(host)); tree = new UnitTestTree(new HostTree(host));
@ -151,5 +151,5 @@ describe('move-document migration', () => {
host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents)); 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[]; let warnOutput: string[];
beforeEach(() => { beforeEach(() => {
runner = new SchematicTestRunner('test', require.resolve('../migrations.json')); runner = new SchematicTestRunner('test', require.resolve('../test-migrations.json'));
host = new TempScopedNodeJsSyncHost(); host = new TempScopedNodeJsSyncHost();
tree = new UnitTestTree(new HostTree(host)); tree = new UnitTestTree(new HostTree(host));
@ -97,7 +97,7 @@ describe('static-queries migration with template strategy', () => {
} }
async function runMigration() { async function runMigration() {
await runner.runSchematicAsync('migration-v8-static-queries', {}, tree).toPromise(); await runner.runSchematicAsync('migration-static-queries', {}, tree).toPromise();
} }
describe('ViewChild', () => { describe('ViewChild', () => {
@ -105,7 +105,7 @@ describe('static-queries migration with template strategy', () => {
it('should detect queries selecting elements through template reference', async() => { it('should detect queries selecting elements through template reference', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, NgModule, ViewChild} from '@angular/core'; import {Component, NgModule, ViewChild} from '@angular/core';
@Component({template: \` @Component({template: \`
<ng-template> <ng-template>
<button #myButton>My Button</button> <button #myButton>My Button</button>
@ -118,7 +118,7 @@ describe('static-queries migration with template strategy', () => {
private @ViewChild('myButton') query: any; private @ViewChild('myButton') query: any;
private @ViewChild('myStaticButton') query2: any; private @ViewChild('myStaticButton') query2: any;
} }
@NgModule({declarations: [MyComp]}) @NgModule({declarations: [MyComp]})
export class MyModule {} export class MyModule {}
`); `);
@ -134,7 +134,7 @@ describe('static-queries migration with template strategy', () => {
it('should detect queries selecting ng-template as static', async() => { it('should detect queries selecting ng-template as static', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, NgModule, ViewChild} from '@angular/core'; import {Component, NgModule, ViewChild} from '@angular/core';
@Component({template: \` @Component({template: \`
<ng-template #myTmpl> <ng-template #myTmpl>
My template My template
@ -143,7 +143,7 @@ describe('static-queries migration with template strategy', () => {
export class MyComp { export class MyComp {
private @ViewChild('myTmpl') query: any; private @ViewChild('myTmpl') query: any;
} }
@NgModule({declarations: [MyComp]}) @NgModule({declarations: [MyComp]})
export class MyModule {} 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() => { it('should detect queries selecting component view providers through string token', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, Directive, NgModule, ViewChild} from '@angular/core'; import {Component, Directive, NgModule, ViewChild} from '@angular/core';
@Directive({ @Directive({
selector: '[myDirective]', selector: '[myDirective]',
providers: [ providers: [
@ -165,7 +165,7 @@ describe('static-queries migration with template strategy', () => {
] ]
}) })
export class MyDirective {} export class MyDirective {}
@Directive({ @Directive({
selector: '[myDirective2]', selector: '[myDirective2]',
providers: [ providers: [
@ -173,13 +173,13 @@ describe('static-queries migration with template strategy', () => {
] ]
}) })
export class MyDirective2 {} export class MyDirective2 {}
@Component({templateUrl: './my-tmpl.html'}) @Component({templateUrl: './my-tmpl.html'})
export class MyComp { export class MyComp {
private @ViewChild('my-token') query: any; private @ViewChild('my-token') query: any;
private @ViewChild('my-token-2') query2: any; private @ViewChild('my-token-2') query2: any;
} }
@NgModule({declarations: [MyComp, MyDirective, MyDirective2]}) @NgModule({declarations: [MyComp, MyDirective, MyDirective2]})
export class MyModule {} 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() => { it('should detect queries selecting component view providers using class token', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, Directive, NgModule, ViewChild} from '@angular/core'; import {Component, Directive, NgModule, ViewChild} from '@angular/core';
export class MyService {} export class MyService {}
export class MyService2 {} export class MyService2 {}
@Directive({ @Directive({
selector: '[myDirective]', selector: '[myDirective]',
providers: [MyService] providers: [MyService]
}) })
export class MyDirective {} export class MyDirective {}
@Directive({ @Directive({
selector: '[myDirective2]', selector: '[myDirective2]',
providers: [MyService2] providers: [MyService2]
}) })
export class MyDirective2 {} export class MyDirective2 {}
@Component({templateUrl: './my-tmpl.html'}) @Component({templateUrl: './my-tmpl.html'})
export class MyComp { export class MyComp {
private @ViewChild(MyService) query: any; private @ViewChild(MyService) query: any;
private @ViewChild(MyService2) query2: any; private @ViewChild(MyService2) query2: any;
} }
@NgModule({declarations: [MyComp, MyDirective, MyDirective2]}) @NgModule({declarations: [MyComp, MyDirective, MyDirective2]})
export class MyModule {} export class MyModule {}
`); `);
@ -247,7 +247,7 @@ describe('static-queries migration with template strategy', () => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, NgModule, ViewChild} from '@angular/core'; import {Component, NgModule, ViewChild} from '@angular/core';
import {HomeComponent, HomeComponent2} from './home-comp'; import {HomeComponent, HomeComponent2} from './home-comp';
@Component({ @Component({
template: \` template: \`
<home-comp></home-comp> <home-comp></home-comp>
@ -260,20 +260,20 @@ describe('static-queries migration with template strategy', () => {
private @ViewChild(HomeComponent) query: any; private @ViewChild(HomeComponent) query: any;
private @ViewChild(HomeComponent2) query2: any; private @ViewChild(HomeComponent2) query2: any;
} }
@NgModule({declarations: [MyComp, HomeComponent, HomeComponent2]}) @NgModule({declarations: [MyComp, HomeComponent, HomeComponent2]})
export class MyModule {} export class MyModule {}
`); `);
writeFile(`/home-comp.ts`, ` writeFile(`/home-comp.ts`, `
import {Component} from '@angular/core'; import {Component} from '@angular/core';
@Component({ @Component({
selector: 'home-comp', selector: 'home-comp',
template: '<span>Home</span>' template: '<span>Home</span>'
}) })
export class HomeComponent {} export class HomeComponent {}
@Component({ @Component({
selector: 'home-comp2', selector: 'home-comp2',
template: '<span>Home 2</span>' template: '<span>Home 2</span>'
@ -294,12 +294,12 @@ describe('static-queries migration with template strategy', () => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, NgModule, ViewChild} from '@angular/core'; import {Component, NgModule, ViewChild} from '@angular/core';
import {MyLibComponent} from 'my-lib'; import {MyLibComponent} from 'my-lib';
@Component({templateUrl: './my-tmpl.html'}) @Component({templateUrl: './my-tmpl.html'})
export class MyComp { export class MyComp {
private @ViewChild(MyLibComponent) query: any; private @ViewChild(MyLibComponent) query: any;
} }
@NgModule({declarations: [MyComp, MyLibComponent]}) @NgModule({declarations: [MyComp, MyLibComponent]})
export class MyModule {} export class MyModule {}
`); `);
@ -319,12 +319,12 @@ describe('static-queries migration with template strategy', () => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, NgModule, ViewChild} from '@angular/core'; import {Component, NgModule, ViewChild} from '@angular/core';
import {MyLibComponent} from 'my-lib'; import {MyLibComponent} from 'my-lib';
@Component({templateUrl: './my-tmpl.html'}) @Component({templateUrl: './my-tmpl.html'})
export class MyComp { export class MyComp {
private @ViewChild(MyLibComponent) query: any; private @ViewChild(MyLibComponent) query: any;
} }
@NgModule({declarations: [MyComp, MyLibComponent]}) @NgModule({declarations: [MyComp, MyLibComponent]})
export class MyModule {} export class MyModule {}
`); `);
@ -345,16 +345,16 @@ describe('static-queries migration with template strategy', () => {
it('should detect queries within structural directive', async() => { it('should detect queries within structural directive', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, Directive, NgModule, ViewChild} from '@angular/core'; import {Component, Directive, NgModule, ViewChild} from '@angular/core';
@Directive({selector: '[ngIf]'}) @Directive({selector: '[ngIf]'})
export class FakeNgIf {} export class FakeNgIf {}
@Component({templateUrl: 'my-tmpl.html'}) @Component({templateUrl: 'my-tmpl.html'})
export class MyComp { export class MyComp {
private @ViewChild('myRef') query: any; private @ViewChild('myRef') query: any;
private @ViewChild('myRef2') query2: any; private @ViewChild('myRef2') query2: any;
} }
@NgModule({declarations: [MyComp, FakeNgIf]}) @NgModule({declarations: [MyComp, FakeNgIf]})
export class MyModule {} export class MyModule {}
`); `);
@ -375,14 +375,14 @@ describe('static-queries migration with template strategy', () => {
it('should detect inherited queries', async() => { it('should detect inherited queries', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, NgModule, ViewChild} from '@angular/core'; import {Component, NgModule, ViewChild} from '@angular/core';
export class BaseClass { export class BaseClass {
@ViewChild('myRef') query: any; @ViewChild('myRef') query: any;
} }
@Component({templateUrl: 'my-tmpl.html'}) @Component({templateUrl: 'my-tmpl.html'})
export class MyComp extends BaseClass {} export class MyComp extends BaseClass {}
@NgModule({declarations: [MyComp]}) @NgModule({declarations: [MyComp]})
export class MyModule {} 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() => { it('should add a todo if a query is not declared in any component', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, NgModule, ViewChild, SomeToken} from '@angular/core'; import {Component, NgModule, ViewChild, SomeToken} from '@angular/core';
export class NotAComponent { export class NotAComponent {
@ViewChild('myRef', {read: SomeToken}) query: any; @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() => { it('should add a todo if a query is used multiple times with different timing', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, NgModule, ViewChild} from '@angular/core'; import {Component, NgModule, ViewChild} from '@angular/core';
export class BaseClass { export class BaseClass {
@ViewChild('myRef') query: any; @ViewChild('myRef') query: any;
} }
@Component({template: '<ng-template><p #myRef></p></ng-template>'}) @Component({template: '<ng-template><p #myRef></p></ng-template>'})
export class FirstComp extends BaseClass {} export class FirstComp extends BaseClass {}
@Component({template: '<span #myRef></span>'}) @Component({template: '<span #myRef></span>'})
export class SecondComp extends BaseClass {} export class SecondComp extends BaseClass {}
@NgModule({declarations: [FirstComp, SecondComp]}) @NgModule({declarations: [FirstComp, SecondComp]})
export class MyModule {} 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() => { it('should gracefully exit migration if queries could not be analyzed', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ViewChild} from '@angular/core'; import {Component, ViewChild} from '@angular/core';
@Component({template: '<ng-template><p #myRef></p></ng-template>'}) @Component({template: '<ng-template><p #myRef></p></ng-template>'})
export class MyComp { export class MyComp {
@ViewChild('myRef') query: any; @ViewChild('myRef') query: any;
} }
// **NOTE**: Analysis will fail as there is no "NgModule" that declares the component. // **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', ` writeFile('/src/test.ts', `
import {ViewChild} from '@angular/core'; import {ViewChild} from '@angular/core';
import {AppComponent} from './app.component'; import {AppComponent} from './app.component';
@Component({template: '<span #test>Test</span>'}) @Component({template: '<span #test>Test</span>'})
class MyTestComponent { class MyTestComponent {
@ViewChild('test') query: any; @ViewChild('test') query: any;
@ -542,7 +542,7 @@ describe('static-queries migration with template strategy', () => {
writeFile('/src/app.component.ts', ` writeFile('/src/app.component.ts', `
import {Component, ViewChild} from '@angular/core'; import {Component, ViewChild} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class AppComponent { export class AppComponent {
@ViewChild('test') query: any; @ViewChild('test') query: any;
@ -552,7 +552,7 @@ describe('static-queries migration with template strategy', () => {
writeFile('/src/app.module.ts', ` writeFile('/src/app.module.ts', `
import {NgModule} from '@angular/core'; import {NgModule} from '@angular/core';
import {AppComponent} from './app.component'; import {AppComponent} from './app.component';
@NgModule({declarations: [AppComponent]}) @NgModule({declarations: [AppComponent]})
export class MyModule {} export class MyModule {}
`); `);

View File

@ -26,7 +26,7 @@ describe('static-queries migration with usage strategy', () => {
afterAll(() => process.env['NG_STATIC_QUERY_USAGE_STRATEGY'] = ''); afterAll(() => process.env['NG_STATIC_QUERY_USAGE_STRATEGY'] = '');
beforeEach(() => { beforeEach(() => {
runner = new SchematicTestRunner('test', require.resolve('../migrations.json')); runner = new SchematicTestRunner('test', require.resolve('../test-migrations.json'));
host = new TempScopedNodeJsSyncHost(); host = new TempScopedNodeJsSyncHost();
tree = new UnitTestTree(new HostTree(host)); 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() => { it('should mark view queries used in "ngAfterContentInit" as static', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ViewChild} from '@angular/core'; import {Component, ViewChild} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@ViewChild('test') query: any; @ViewChild('test') query: any;
ngAfterContentInit() { ngAfterContentInit() {
this.query.classList.add('test'); 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() => { it('should mark view queries used in "ngAfterContentChecked" as static', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ViewChild} from '@angular/core'; import {Component, ViewChild} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@ViewChild('test') query: any; @ViewChild('test') query: any;
ngAfterContentChecked() { ngAfterContentChecked() {
this.query.classList.add('test'); 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() => { it('should not mark content queries used in "ngAfterContentInit" as static', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ContentChild} from '@angular/core'; import {Component, ContentChild} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@ContentChild('test') query: any; @ContentChild('test') query: any;
ngAfterContentInit() { ngAfterContentInit() {
this.query.classList.add('test'); 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() => { it('should not mark content queries used in "ngAfterContentChecked" as static', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ContentChild} from '@angular/core'; import {Component, ContentChild} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@ContentChild('test') query: any; @ContentChild('test') query: any;
ngAfterContentChecked() { ngAfterContentChecked() {
this.query.classList.add('test'); this.query.classList.add('test');
} }
@ -145,19 +145,19 @@ describe('static-queries migration with usage strategy', () => {
} }
async function runMigration() { 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') { function createQueryTests(queryType: 'ViewChild' | 'ContentChild') {
it('should mark queries as dynamic', async() => { it('should mark queries as dynamic', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@${queryType}('test') unused: any; @${queryType}('test') unused: any;
@${queryType}('dynamic') dynamic: any; @${queryType}('dynamic') dynamic: any;
onClick() { onClick() {
this.dynamicQuery.classList.add('test'); 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() => { it('should mark queries used in "ngOnChanges" as static', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@${queryType}('test') query: any; @${queryType}('test') query: any;
ngOnChanges() { 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() => { it('should mark queries used in "ngOnInit" as static', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@${queryType}('test') query: any; @${queryType}('test') query: any;
ngOnInit() { 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() => { it('should mark queries used in "ngDoCheck" as static', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@${queryType}('test') query: any; @${queryType}('test') query: any;
ngDoCheck() { 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() => { it('should keep existing query options when updating timing', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@${queryType}('test', { /* test */ read: null }) query: any; @${queryType}('test', { /* test */ read: null }) query: any;
ngOnInit() { ngOnInit() {
this.query.classList.add('test'); 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() => { it('should not overwrite existing explicit query timing', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@${queryType}('test', {static: /* untouched */ someVal}) query: any; @${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() => { it('should detect queries used in deep method chain', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
// We intentionally add this comma for the second parameter in order // We intentionally add this comma for the second parameter in order
// to ensure that the migration does not incorrectly create an invalid // to ensure that the migration does not incorrectly create an invalid
// decorator call with three parameters. e.g. "ViewQuery('test', {...}, )" // decorator call with three parameters. e.g. "ViewQuery('test', {...}, )"
@${queryType}('test', ) query: any; @${queryType}('test', ) query: any;
ngOnInit() { ngOnInit() {
this.a(); this.a();
} }
a() { a() {
this.b(); this.b();
} }
b() { b() {
this.c(); this.c();
} }
c() { c() {
console.log(this.query); 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() => { it('should properly exit if recursive function is analyzed', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@${queryType}('test') query: any; @${queryType}('test') query: any;
ngOnInit() { ngOnInit() {
this.recursive(); this.recursive();
} }
recursive() { recursive() {
this.recursive(); this.recursive();
} }
} }
@ -330,27 +330,27 @@ describe('static-queries migration with usage strategy', () => {
it('should detect queries used in newly instantiated classes', async() => { it('should detect queries used in newly instantiated classes', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@${queryType}('test') query: any; @${queryType}('test') query: any;
@${queryType}('test') query2: any; @${queryType}('test') query2: any;
ngOnInit() { ngOnInit() {
new A(this); new A(this);
new class Inline { new class Inline {
constructor(private ctx: MyComp) { constructor(private ctx: MyComp) {
this.a(); this.a();
} }
a() { a() {
this.ctx.query2.useStatically(); this.ctx.query2.useStatically();
} }
}(this); }(this);
} }
} }
export class A { export class A {
constructor(ctx: MyComp) { constructor(ctx: MyComp) {
ctx.query.test(); ctx.query.test();
@ -369,16 +369,16 @@ describe('static-queries migration with usage strategy', () => {
it('should detect queries used in parenthesized new expressions', async() => { it('should detect queries used in parenthesized new expressions', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@${queryType}('test') query: any; @${queryType}('test') query: any;
ngOnInit() { ngOnInit() {
new ((A))(this); new ((A))(this);
} }
} }
export class A { export class A {
constructor(ctx: MyComp) { constructor(ctx: MyComp) {
ctx.query.test(); 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() => { it('should detect queries in lifecycle hook with string literal name', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@${queryType}('test') query: any; @${queryType}('test') query: any;
'ngOnInit'() { 'ngOnInit'() {
this.query.test(); this.query.test();
} }
@ -415,19 +415,19 @@ describe('static-queries migration with usage strategy', () => {
it('should detect static queries within nested inheritance', async() => { it('should detect static queries within nested inheritance', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@${queryType}('test') query: any; @${queryType}('test') query: any;
} }
export class A extends MyComp {} export class A extends MyComp {}
export class B extends A { export class B extends A {
ngOnInit() { ngOnInit() {
this.query.testFn(); this.query.testFn();
} }
} }
`); `);
@ -440,11 +440,11 @@ describe('static-queries migration with usage strategy', () => {
it('should detect static queries used within input setters', async() => { it('should detect static queries used within input setters', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, Input, ${queryType}} from '@angular/core'; import {Component, Input, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@${queryType}('test') query: any; @${queryType}('test') query: any;
@Input() @Input()
get myVal() { return null; } get myVal() { return null; }
set myVal(newVal: any) { set myVal(newVal: any) {
@ -462,14 +462,14 @@ describe('static-queries migration with usage strategy', () => {
it('should detect inputs defined in metadata', async() => { it('should detect inputs defined in metadata', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({ @Component({
template: '<span #test></span>', template: '<span #test></span>',
inputs: ["myVal"], inputs: ["myVal"],
}) })
export class MyComp { export class MyComp {
@${queryType}('test') query: any; @${queryType}('test') query: any;
// We don't use the input decorator here as we want to verify // We don't use the input decorator here as we want to verify
// that it properly detects the input through the component metadata. // that it properly detects the input through the component metadata.
get myVal() { return null; } get myVal() { return null; }
@ -488,14 +488,14 @@ describe('static-queries migration with usage strategy', () => {
it('should detect aliased inputs declared in metadata', async() => { it('should detect aliased inputs declared in metadata', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({ @Component({
template: '<span #test></span>', template: '<span #test></span>',
inputs: ['prop: publicName'], inputs: ['prop: publicName'],
}) })
export class MyComp { export class MyComp {
@${queryType}('test') query: any; @${queryType}('test') query: any;
set prop(val: any) { set prop(val: any) {
this.query.test(); 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() => { it('should not mark query as static if query is used in non-input setter', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@${queryType}('test') query: any; @${queryType}('test') query: any;
set myProperty(val: any) { set myProperty(val: any) {
this.query.test(); this.query.test();
} }
@ -531,13 +531,13 @@ describe('static-queries migration with usage strategy', () => {
it('should detect input decorator on setter', async() => { it('should detect input decorator on setter', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Input, Component, ${queryType}} from '@angular/core'; import {Input, Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@${queryType}('test') query: any; @${queryType}('test') query: any;
get myProperty() { return null; } get myProperty() { return null; }
// Usually the decorator is set on the get accessor, but it's also possible // 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. // to declare the input on the setter. This ensures that it is handled properly.
@Input() @Input()
@ -556,7 +556,7 @@ describe('static-queries migration with usage strategy', () => {
it('should detect setter inputs in derived classes', async() => { it('should detect setter inputs in derived classes', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({ @Component({
template: '<span #test></span>', template: '<span #test></span>',
inputs: ['childSetter'], inputs: ['childSetter'],
@ -564,7 +564,7 @@ describe('static-queries migration with usage strategy', () => {
export class MyComp { export class MyComp {
protected @${queryType}('test') query: any; protected @${queryType}('test') query: any;
} }
export class B extends MyComp { export class B extends MyComp {
set childSetter(newVal: any) { set childSetter(newVal: any) {
this.query.test(); 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() => { it('should properly detect static query in external derived class', async() => {
writeFile('/src/index.ts', ` writeFile('/src/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@${queryType}('test') query: any; @${queryType}('test') query: any;
@ -590,7 +590,7 @@ describe('static-queries migration with usage strategy', () => {
writeFile('/src/external.ts', ` writeFile('/src/external.ts', `
import {MyComp} from './index'; import {MyComp} from './index';
export class ExternalComp extends MyComp { export class ExternalComp extends MyComp {
ngOnInit() { ngOnInit() {
this.query.test(); 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() => { it('should not mark queries used in promises as static', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
private @${queryType}('test') query: any; private @${queryType}('test') query: any;
private @${queryType}('test') query2: any; private @${queryType}('test') query2: any;
ngOnInit() { ngOnInit() {
const a = Promise.resolve(); const a = Promise.resolve();
Promise.resolve().then(() => { Promise.resolve().then(() => {
this.query.doSomething(); this.query.doSomething();
}); });
Promise.reject().catch(() => { Promise.reject().catch(() => {
this.query.doSomething(); this.query.doSomething();
}); });
a.then(() => {}).then(() => { a.then(() => {}).then(() => {
this.query.doSomething(); this.query.doSomething();
}); });
Promise.resolve().then(this.createPromiseCb()); Promise.resolve().then(this.createPromiseCb());
} }
createPromiseCb() { createPromiseCb() {
this.query2.doSomething(); this.query2.doSomething();
return () => { /* empty callback */} return () => { /* empty callback */}
@ -656,19 +656,19 @@ describe('static-queries migration with usage strategy', () => {
it('should handle function callbacks which statically access queries', async() => { it('should handle function callbacks which statically access queries', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
private @${queryType}('test') query: any; private @${queryType}('test') query: any;
ngOnInit() { ngOnInit() {
this.callSync(() => this.query.doSomething()); this.callSync(() => this.query.doSomething());
} }
callSync(cb: Function) { callSync(cb: Function) {
this.callSync2(cb); this.callSync2(cb);
} }
callSync2(cb: Function) { callSync2(cb: Function) {
cb(); cb();
} }
@ -686,12 +686,12 @@ describe('static-queries migration with usage strategy', () => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
import {External} from './external'; import {External} from './external';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
private @${queryType}('test') query: any; private @${queryType}('test') query: any;
ngOnInit() { ngOnInit() {
new External(() => this.query.doSomething()); new External(() => this.query.doSomething());
} }
} }
@ -700,7 +700,7 @@ describe('static-queries migration with usage strategy', () => {
writeFile('/external.ts', ` writeFile('/external.ts', `
export class External { export class External {
constructor(cb: () => void) { constructor(cb: () => void) {
// Add extra parentheses to ensure that expression is unwrapped. // Add extra parentheses to ensure that expression is unwrapped.
((cb))(); ((cb))();
} }
} }
@ -715,21 +715,21 @@ describe('static-queries migration with usage strategy', () => {
it('should handle nested functions with arguments from parent closure', async() => { it('should handle nested functions with arguments from parent closure', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
private @${queryType}('test') query: any; private @${queryType}('test') query: any;
ngOnInit() { ngOnInit() {
this.callSync(() => this.query.doSomething()); this.callSync(() => this.query.doSomething());
} }
callSync(cb: Function) { callSync(cb: Function) {
function callSyncNested() { function callSyncNested() {
// The "cb" identifier comes from the "callSync" function. // The "cb" identifier comes from the "callSync" function.
cb(); cb();
} }
callSyncNested(); callSyncNested();
} }
} }
@ -744,22 +744,22 @@ describe('static-queries migration with usage strategy', () => {
it('should not mark queries used in setTimeout as static', async() => { it('should not mark queries used in setTimeout as static', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
private @${queryType}('test') query: any; private @${queryType}('test') query: any;
private @${queryType}('test') query2: any; private @${queryType}('test') query2: any;
private @${queryType}('test') query3: any; private @${queryType}('test') query3: any;
ngOnInit() { ngOnInit() {
setTimeout(function() { setTimeout(function() {
this.query.doSomething(); this.query.doSomething();
}); });
setTimeout(createCallback(this)); setTimeout(createCallback(this));
} }
} }
function createCallback(instance: MyComp) { function createCallback(instance: MyComp) {
instance.query2.doSomething(); instance.query2.doSomething();
return () => instance.query3.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() => { it('should not mark queries used in "addEventListener" as static', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ElementRef, ${queryType}} from '@angular/core'; import {Component, ElementRef, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
private @${queryType}('test') query: any; private @${queryType}('test') query: any;
constructor(private elementRef: ElementRef) {} constructor(private elementRef: ElementRef) {}
ngOnInit() { ngOnInit() {
this.elementRef.addEventListener(() => { this.elementRef.addEventListener(() => {
this.query.classList.add('test'); 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() => { it('should not mark queries used in "requestAnimationFrame" as static', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ElementRef, ${queryType}} from '@angular/core'; import {Component, ElementRef, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
private @${queryType}('test') query: any; private @${queryType}('test') query: any;
constructor(private elementRef: ElementRef) {} constructor(private elementRef: ElementRef) {}
ngOnInit() { ngOnInit() {
requestAnimationFrame(() => { requestAnimationFrame(() => {
this.query.classList.add('test'); 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() => { it('should mark queries used in immediately-invoked function expression as static', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
private @${queryType}('test') query: any; private @${queryType}('test') query: any;
private @${queryType}('test') query2: any; private @${queryType}('test') query2: any;
ngOnInit() { ngOnInit() {
(() => { (() => {
this.query.usedStatically(); this.query.usedStatically();
})(); })();
(function(ctx) { (function(ctx) {
ctx.query2.useStatically(); ctx.query2.useStatically();
})(this); })(this);
@ -857,11 +857,11 @@ describe('static-queries migration with usage strategy', () => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
import {externalFn} from './external'; import {externalFn} from './external';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
private @${queryType}('test') query: any; private @${queryType}('test') query: any;
ngOnInit() { ngOnInit() {
externalFn(this); externalFn(this);
} }
@ -870,7 +870,7 @@ describe('static-queries migration with usage strategy', () => {
writeFile('/external.ts', ` writeFile('/external.ts', `
import {MyComp} from './index'; import {MyComp} from './index';
export function externalFn(ctx: MyComp) { export function externalFn(ctx: MyComp) {
ctx.query.usedStatically(); 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() => { it('should detect static queries used through getter property access', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
private @${queryType}('test') query: any; private @${queryType}('test') query: any;
get myProp() { get myProp() {
return this.query.myValue; return this.query.myValue;
} }
ngOnInit() { ngOnInit() {
this.myProp.test(); this.myProp.test();
} }
@ -910,17 +910,17 @@ describe('static-queries migration with usage strategy', () => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
import {External} from './external'; import {External} from './external';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
@${queryType}('test') query: any; @${queryType}('test') query: any;
private external = new External(this); private external = new External(this);
get myProp() { get myProp() {
return this.query.myValue; return this.query.myValue;
} }
ngOnInit() { ngOnInit() {
console.log(this.external.query); console.log(this.external.query);
} }
@ -929,10 +929,10 @@ describe('static-queries migration with usage strategy', () => {
writeFile('/external.ts', ` writeFile('/external.ts', `
import {MyComp} from './index'; import {MyComp} from './index';
export class External { export class External {
constructor(private comp: MyComp) {} constructor(private comp: MyComp) {}
set query() { /** noop */ } set query() { /** noop */ }
get query() { return this.comp.query; } 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() => { it('should not mark queries as static if a value is assigned to accessor property', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
private @${queryType}('test') query: any; private @${queryType}('test') query: any;
set myProp(value: any) { /* noop */} set myProp(value: any) { /* noop */}
get myProp() { get myProp() {
return this.query.myValue; return this.query.myValue;
} }
ngOnInit() { ngOnInit() {
this.myProp = true; 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() => { it('should mark queries as static if non-input setter uses query', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
private @${queryType}('test') query: any; private @${queryType}('test') query: any;
get myProp() { return null; } get myProp() { return null; }
set myProp(value: any) { set myProp(value: any) {
this.query.doSomething(); this.query.doSomething();
} }
ngOnInit() { ngOnInit() {
this.myProp = 'newValue'; 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() => { it('should check setter and getter when using compound assignment', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
private @${queryType}('test') query: any; private @${queryType}('test') query: any;
private @${queryType}('test') query2: any; private @${queryType}('test') query2: any;
get myProp() { return this.query2 } get myProp() { return this.query2 }
set myProp(value: any) { set myProp(value: any) {
this.query.doSomething(); this.query.doSomething();
} }
ngOnInit() { ngOnInit() {
this.myProp *= 5; 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() => { it('should check getters when using comparison operator in binary expression', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
private @${queryType}('test') query: any; private @${queryType}('test') query: any;
get myProp() { return this.query } get myProp() { return this.query }
set myProp(value: any) { /* noop */ } set myProp(value: any) { /* noop */ }
ngOnInit() { ngOnInit() {
if (this.myProp === 3) { if (this.myProp === 3) {
// noop // noop
@ -1050,29 +1050,29 @@ describe('static-queries migration with usage strategy', () => {
it('should check derived abstract class methods', async() => { it('should check derived abstract class methods', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
export abstract class RootBaseClass { export abstract class RootBaseClass {
abstract getQuery(): any; abstract getQuery(): any;
ngOnInit() { ngOnInit() {
this.getQuery().doSomething(); this.getQuery().doSomething();
} }
} }
export abstract class BaseClass extends RootBaseClass { export abstract class BaseClass extends RootBaseClass {
abstract getQuery2(): any; abstract getQuery2(): any;
getQuery() { getQuery() {
this.getQuery2(); this.getQuery2();
} }
} }
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class Subclass extends BaseClass { export class Subclass extends BaseClass {
@${queryType}('test') query: any; @${queryType}('test') query: any;
getQuery2(): 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() => { it('should detect queries accessed through deep abstract class method', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
export abstract class RootBaseClass { export abstract class RootBaseClass {
abstract getQuery(): any; abstract getQuery(): any;
ngOnInit() { ngOnInit() {
this.getQuery().doSomething(); this.getQuery().doSomething();
} }
} }
export abstract class BaseClass extends RootBaseClass { export abstract class BaseClass extends RootBaseClass {
/* additional layer of indirection */ /* additional layer of indirection */
} }
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class Subclass extends BaseClass { export class Subclass extends BaseClass {
@${queryType}('test') query: any; @${queryType}('test') query: any;
getQuery(): 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() => { it('should detect queries accessed through abstract property getter', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
export abstract class BaseClass { export abstract class BaseClass {
abstract myQuery: any; abstract myQuery: any;
ngOnInit() { ngOnInit() {
this.myQuery.doSomething(); this.myQuery.doSomething();
} }
} }
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class Subclass extends BaseClass { export class Subclass extends BaseClass {
@${queryType}('test') query: any; @${queryType}('test') query: any;
get myQuery() { return this.query; } 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() => { it('should detect queries accessed through abstract property setter', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
export abstract class BaseClass { export abstract class BaseClass {
abstract myQuery: any; abstract myQuery: any;
ngOnInit() { ngOnInit() {
this.myQuery = "trigger"; this.myQuery = "trigger";
} }
} }
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class Subclass extends BaseClass { export class Subclass extends BaseClass {
@${queryType}('test') query: any; @${queryType}('test') query: any;
set myQuery(val: any) { this.query.doSomething() } set myQuery(val: any) { this.query.doSomething() }
get myQuery() { /* noop */ } 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() => { it('should detect query usage in abstract class methods accessing inherited query', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
export abstract class RootBaseClass { export abstract class RootBaseClass {
abstract getQuery(): any; abstract getQuery(): any;
ngOnInit() { ngOnInit() {
this.getQuery().doSomething(); this.getQuery().doSomething();
} }
} }
export abstract class BaseClass extends RootBaseClass { export abstract class BaseClass extends RootBaseClass {
@${queryType}('test') query: any; @${queryType}('test') query: any;
abstract getQuery2(): any; abstract getQuery2(): any;
getQuery() { getQuery() {
this.getQuery2(); this.getQuery2();
} }
} }
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class Subclass extends BaseClass { export class Subclass extends BaseClass {
getQuery2(): any { getQuery2(): any {
return this.query; return this.query;
} }
@ -1207,7 +1207,7 @@ describe('static-queries migration with usage strategy', () => {
it('should detect query usage within component template', async() => { it('should detect query usage within component template', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({templateUrl: 'my-template.html'}) @Component({templateUrl: 'my-template.html'})
export class MyComponent { export class MyComponent {
@${queryType}('test') query: any; @${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() => { it('should detect query usage with nested property read within component template', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({templateUrl: 'my-template.html'}) @Component({templateUrl: 'my-template.html'})
export class MyComponent { export class MyComponent {
@${queryType}('test') query: any; @${queryType}('test') query: any;
@ -1250,7 +1250,7 @@ describe('static-queries migration with usage strategy', () => {
async() => { async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({templateUrl: 'my-template.html'}) @Component({templateUrl: 'my-template.html'})
export class MyComponent { export class MyComponent {
@${queryType}('test') query: any; @${queryType}('test') query: any;
@ -1274,7 +1274,7 @@ describe('static-queries migration with usage strategy', () => {
async() => { async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({templateUrl: 'my-template.html'}) @Component({templateUrl: 'my-template.html'})
export class MyComponent { export class MyComponent {
myObject: {someProp: any}; myObject: {someProp: any};
@ -1299,7 +1299,7 @@ describe('static-queries migration with usage strategy', () => {
it('should ignore queries accessed within <ng-template> element', async() => { it('should ignore queries accessed within <ng-template> element', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({templateUrl: 'my-template.html'}) @Component({templateUrl: 'my-template.html'})
export class MyComponent { export class MyComponent {
@${queryType}('test') query: any; @${queryType}('test') query: any;
@ -1308,7 +1308,7 @@ describe('static-queries migration with usage strategy', () => {
writeFile(`/my-template.html`, ` writeFile(`/my-template.html`, `
<foo #test></foo> <foo #test></foo>
<ng-template> <ng-template>
<my-comp [myInput]="query"></my-comp> <my-comp [myInput]="query"></my-comp>
</ng-template> </ng-template>
@ -1323,11 +1323,11 @@ describe('static-queries migration with usage strategy', () => {
it('should detect inherited queries used in templates', async() => { it('should detect inherited queries used in templates', async() => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
export class ParentClass { export class ParentClass {
@${queryType}('test') query: any; @${queryType}('test') query: any;
} }
@Component({templateUrl: 'my-template.html'}) @Component({templateUrl: 'my-template.html'})
export class MyComponent extends ParentClass {} export class MyComponent extends ParentClass {}
`); `);
@ -1346,7 +1346,7 @@ describe('static-queries migration with usage strategy', () => {
it('should properly handle multiple tsconfig files', async() => { it('should properly handle multiple tsconfig files', async() => {
writeFile('/src/index.ts', ` writeFile('/src/index.ts', `
import {Component, ${queryType}} from '@angular/core'; import {Component, ${queryType}} from '@angular/core';
@Component({template: '<span #test></span>'}) @Component({template: '<span #test></span>'})
export class MyComp { export class MyComp {
private @${queryType}('test') query: any; private @${queryType}('test') query: any;

View File

@ -21,7 +21,7 @@ describe('template variable assignment migration', () => {
let warnOutput: string[]; let warnOutput: string[];
beforeEach(() => { beforeEach(() => {
runner = new SchematicTestRunner('test', require.resolve('../migrations.json')); runner = new SchematicTestRunner('test', require.resolve('../test-migrations.json'));
host = new TempScopedNodeJsSyncHost(); host = new TempScopedNodeJsSyncHost();
tree = new UnitTestTree(new HostTree(host)); tree = new UnitTestTree(new HostTree(host));
@ -58,14 +58,12 @@ describe('template variable assignment migration', () => {
host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents)); host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents));
} }
function runMigration() { function runMigration() { runner.runSchematic('migration-template-local-variables', {}, tree); }
runner.runSchematic('migration-v8-template-local-variables', {}, tree);
}
it('should warn for two-way data binding variable assignment', () => { it('should warn for two-way data binding variable assignment', () => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component} from '@angular/core'; import {Component} from '@angular/core';
@Component({ @Component({
template: '<cmp *ngFor="let optionName of options" [(opt)]="optionName"></cmp>', 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', () => { it('should warn for two-way data binding assigning to "as" variable', () => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component} from '@angular/core'; import {Component} from '@angular/core';
@Component({ @Component({
templateUrl: './tmpl.html', templateUrl: './tmpl.html',
}) })
@ -103,7 +101,7 @@ describe('template variable assignment migration', () => {
it('should warn for bound event assignments to "as" variable', () => { it('should warn for bound event assignments to "as" variable', () => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component} from '@angular/core'; import {Component} from '@angular/core';
@Component({ @Component({
templateUrl: './sub_dir/tmpl.html', 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', () => { it('should warn for bound event assignments to template "let" variables', () => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component} from '@angular/core'; import {Component} from '@angular/core';
@Component({ @Component({
templateUrl: './sub_dir/tmpl.html', 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', () => { it('should not warn for bound event assignments to component property', () => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component} from '@angular/core'; import {Component} from '@angular/core';
@Component({ @Component({
templateUrl: './sub_dir/tmpl.html', 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', () => { it('should not warn for bound event assignments to template variable object property', () => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component} from '@angular/core'; import {Component} from '@angular/core';
@Component({ @Component({
templateUrl: './sub_dir/tmpl.html', templateUrl: './sub_dir/tmpl.html',
}) })
@ -188,7 +186,7 @@ describe('template variable assignment migration', () => {
() => { () => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component} from '@angular/core'; import {Component} from '@angular/core';
@Component({ @Component({
templateUrl: './sub_dir/tmpl.html', 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', () => { it('should not warn for property writes with template variable name but different scope', () => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component} from '@angular/core'; import {Component} from '@angular/core';
@Component({ @Component({
templateUrl: './sub_dir/tmpl.html', 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', () => { it('should not throw an error if a detected template fails parsing', () => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component} from '@angular/core'; import {Component} from '@angular/core';
@Component({ @Component({
templateUrl: './sub_dir/tmpl.html', 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', () => { it('should be able to report multiple templates within the same source file', () => {
writeFile('/index.ts', ` writeFile('/index.ts', `
import {Component} from '@angular/core'; import {Component} from '@angular/core';
@Component({ @Component({
template: '<ng-template let-one><a (sayHello)="one=true"></a></ng-template>', template: '<ng-template let-one><a (sayHello)="one=true"></a></ng-template>',
}) })
export class MyComp {} export class MyComp {}
@Component({ @Component({
template: '<ng-template let-two><b (greet)="two=true"></b></ng-template>', 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. * 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 * Must be used in the context of a factory function such as one defined for an
* developer consumption! * `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 * 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. * `InjectionToken`. Throws an error if not called from such a context.
@ -97,17 +110,6 @@ export function injectInjectorOnly<T>(
* *
* @publicApi * @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; export const inject = ɵɵinject;
/** /**

View File

@ -110,6 +110,8 @@ function listenerInternal(
ngDevMode && assertNodeOfPossibleTypes( ngDevMode && assertNodeOfPossibleTypes(
tNode, TNodeType.Element, TNodeType.Container, TNodeType.ElementContainer); tNode, TNodeType.Element, TNodeType.Container, TNodeType.ElementContainer);
let processOutputs = true;
// add native event listener - applicable to elements only // add native event listener - applicable to elements only
if (tNode.type === TNodeType.Element) { if (tNode.type === TNodeType.Element) {
const native = getNativeByTNode(tNode, lView) as RElement; 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. // Attach a new listener at the head of the coalesced listeners list.
(<any>listenerFn).__ngNextListenerFn__ = (<any>existingListener).__ngNextListenerFn__; (<any>listenerFn).__ngNextListenerFn__ = (<any>existingListener).__ngNextListenerFn__;
(<any>existingListener).__ngNextListenerFn__ = listenerFn; (<any>existingListener).__ngNextListenerFn__ = listenerFn;
processOutputs = false;
} else { } else {
// The first argument of `listen` function in Procedural Renderer is: // 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) // - 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; const outputs = tNode.outputs;
let props: PropertyAliasValue|undefined; let props: PropertyAliasValue|undefined;
if (outputs && (props = outputs[eventName])) { if (processOutputs && outputs && (props = outputs[eventName])) {
const propsLength = props.length; const propsLength = props.length;
if (propsLength) { if (propsLength) {
const lCleanup = getCleanup(lView); const lCleanup = getCleanup(lView);

View File

@ -7,6 +7,7 @@
*/ */
import {assertEqual, assertLessThan} from '../../util/assert'; import {assertEqual, assertLessThan} from '../../util/assert';
import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4} from '../bindings'; import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4} from '../bindings';
import {SanitizerFn} from '../interfaces/sanitization';
import {BINDING_INDEX, TVIEW} from '../interfaces/view'; import {BINDING_INDEX, TVIEW} from '../interfaces/view';
import {getLView, getSelectedIndex} from '../state'; import {getLView, getSelectedIndex} from '../state';
import {NO_CHANGE} from '../tokens'; import {NO_CHANGE} from '../tokens';
@ -15,6 +16,7 @@ import {renderStringify} from '../util/misc_utils';
import {TsickleIssue1009, elementPropertyInternal, storeBindingMetadata} from './shared'; import {TsickleIssue1009, elementPropertyInternal, storeBindingMetadata} from './shared';
/** /**
* Create interpolation bindings with a variable number of expressions. * Create interpolation bindings with a variable number of expressions.
* *
@ -290,12 +292,6 @@ export function ɵɵinterpolation8(
/// NEW INSTRUCTIONS /// 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 * 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 prefix Static value used for concatenation only.
* @param v0 Value checked for change. * @param v0 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate(propName: string, v0: any): TsickleIssue1009 { export function ɵɵpropertyInterpolate(
ɵɵpropertyInterpolate1(propName, EMPTY_STRING, v0, EMPTY_STRING); propName: string, v0: any, sanitizer?: SanitizerFn): TsickleIssue1009 {
ɵɵpropertyInterpolate1(propName, '', v0, '', sanitizer);
return ɵɵpropertyInterpolate; return ɵɵpropertyInterpolate;
} }
@ -354,13 +352,15 @@ export function ɵɵpropertyInterpolate(propName: string, v0: any): TsickleIssue
* @param prefix Static value used for concatenation only. * @param prefix Static value used for concatenation only.
* @param v0 Value checked for change. * @param v0 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate1( 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(); const index = getSelectedIndex();
elementPropertyInternal(index, propName, ɵɵinterpolation1(prefix, v0, suffix)); elementPropertyInternal(index, propName, ɵɵinterpolation1(prefix, v0, suffix), sanitizer);
return ɵɵpropertyInterpolate1; return ɵɵpropertyInterpolate1;
} }
@ -390,14 +390,15 @@ export function ɵɵpropertyInterpolate1(
* @param i0 Static value used for concatenation only. * @param i0 Static value used for concatenation only.
* @param v1 Value checked for change. * @param v1 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate2( export function ɵɵpropertyInterpolate2(
propName: string, prefix: string, v0: any, i0: string, v1: any, propName: string, prefix: string, v0: any, i0: string, v1: any, suffix: string,
suffix: string): TsickleIssue1009 { sanitizer?: SanitizerFn): TsickleIssue1009 {
const index = getSelectedIndex(); const index = getSelectedIndex();
elementPropertyInternal(index, propName, ɵɵinterpolation2(prefix, v0, i0, v1, suffix)); elementPropertyInternal(index, propName, ɵɵinterpolation2(prefix, v0, i0, v1, suffix), sanitizer);
return ɵɵpropertyInterpolate2; return ɵɵpropertyInterpolate2;
} }
@ -430,14 +431,16 @@ export function ɵɵpropertyInterpolate2(
* @param i1 Static value used for concatenation only. * @param i1 Static value used for concatenation only.
* @param v2 Value checked for change. * @param v2 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate3( export function ɵɵpropertyInterpolate3(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, 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(); 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; return ɵɵpropertyInterpolate3;
} }
@ -472,15 +475,16 @@ export function ɵɵpropertyInterpolate3(
* @param i2 Static value used for concatenation only. * @param i2 Static value used for concatenation only.
* @param v3 Value checked for change. * @param v3 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate4( export function ɵɵpropertyInterpolate4(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, 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(); const index = getSelectedIndex();
elementPropertyInternal( 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; return ɵɵpropertyInterpolate4;
} }
@ -517,15 +521,17 @@ export function ɵɵpropertyInterpolate4(
* @param i3 Static value used for concatenation only. * @param i3 Static value used for concatenation only.
* @param v4 Value checked for change. * @param v4 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate5( export function ɵɵpropertyInterpolate5(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, 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(); const index = getSelectedIndex();
elementPropertyInternal( 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; return ɵɵpropertyInterpolate5;
} }
@ -564,16 +570,18 @@ export function ɵɵpropertyInterpolate5(
* @param i4 Static value used for concatenation only. * @param i4 Static value used for concatenation only.
* @param v5 Value checked for change. * @param v5 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate6( export function ɵɵpropertyInterpolate6(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, 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(); const index = getSelectedIndex();
elementPropertyInternal( elementPropertyInternal(
index, propName, index, propName, ɵɵinterpolation6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix),
ɵɵinterpolation6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix)); sanitizer);
return ɵɵpropertyInterpolate6; return ɵɵpropertyInterpolate6;
} }
@ -614,17 +622,19 @@ export function ɵɵpropertyInterpolate6(
* @param i5 Static value used for concatenation only. * @param i5 Static value used for concatenation only.
* @param v6 Value checked for change. * @param v6 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate7( export function ɵɵpropertyInterpolate7(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, 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, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, suffix: string,
suffix: string): TsickleIssue1009 { sanitizer?: SanitizerFn): TsickleIssue1009 {
const index = getSelectedIndex(); const index = getSelectedIndex();
elementPropertyInternal( elementPropertyInternal(
index, propName, 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; return ɵɵpropertyInterpolate7;
} }
@ -667,17 +677,19 @@ export function ɵɵpropertyInterpolate7(
* @param i6 Static value used for concatenation only. * @param i6 Static value used for concatenation only.
* @param v7 Value checked for change. * @param v7 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate8( export function ɵɵpropertyInterpolate8(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, 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, 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(); const index = getSelectedIndex();
elementPropertyInternal( elementPropertyInternal(
index, propName, 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; 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 * @param values The a collection of values and the strings inbetween those values, beginning with a
* string prefix and ending with a string suffix. * string prefix and ending with a string suffix.
* (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`) * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolateV(propName: string, values: any[]): TsickleIssue1009 { export function ɵɵpropertyInterpolateV(
propName: string, values: any[], sanitizer?: SanitizerFn): TsickleIssue1009 {
const index = getSelectedIndex(); const index = getSelectedIndex();
elementPropertyInternal(index, propName, ɵɵinterpolationV(values)); elementPropertyInternal(index, propName, ɵɵinterpolationV(values), sanitizer);
return ɵɵpropertyInterpolateV; return ɵɵpropertyInterpolateV;
} }

View File

@ -905,15 +905,20 @@ export function setNgReflectProperty(
attrName = normalizeDebugBindingName(attrName); attrName = normalizeDebugBindingName(attrName);
const debugValue = normalizeDebugBindingValue(value); const debugValue = normalizeDebugBindingValue(value);
if (type === TNodeType.Element) { if (type === TNodeType.Element) {
isProceduralRenderer(renderer) ? if (value == null) {
renderer.setAttribute((element as RElement), attrName, debugValue) : isProceduralRenderer(renderer) ? renderer.removeAttribute((element as RElement), attrName) :
(element as RElement).setAttribute(attrName, debugValue); (element as RElement).removeAttribute(attrName);
} else if (value !== undefined) {
const value = `bindings=${JSON.stringify({[attrName]: debugValue}, null, 2)}`;
if (isProceduralRenderer(renderer)) {
renderer.setValue((element as RComment), value);
} else { } 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 {registerNgModuleType} from '../../linker/ng_module_factory_loader';
import {Component} from '../../metadata'; import {Component} from '../../metadata';
import {ModuleWithProviders, NgModule, NgModuleDef, NgModuleTransitiveScopes} from '../../metadata/ng_module'; import {ModuleWithProviders, NgModule, NgModuleDef, NgModuleTransitiveScopes} from '../../metadata/ng_module';
import {flatten} from '../../util/array_utils';
import {assertDefined} from '../../util/assert'; import {assertDefined} from '../../util/assert';
import {getComponentDef, getDirectiveDef, getNgModuleDef, getPipeDef} from '../definition'; import {getComponentDef, getDirectiveDef, getNgModuleDef, getPipeDef} from '../definition';
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from '../fields'; 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 errors: string[] = [];
const declarations = maybeUnwrapFn(ngModuleDef.declarations); const declarations = maybeUnwrapFn(ngModuleDef.declarations);
const imports = maybeUnwrapFn(ngModuleDef.imports); const imports = maybeUnwrapFn(ngModuleDef.imports);
flatten(imports, unwrapModuleWithProvidersImports).forEach(verifySemanticsOfNgModuleDef);
const exports = maybeUnwrapFn(ngModuleDef.exports); const exports = maybeUnwrapFn(ngModuleDef.exports);
declarations.forEach(verifyDeclarationsHaveDefinitions); declarations.forEach(verifyDeclarationsHaveDefinitions);
const combinedDeclarations: Type<any>[] = [ const combinedDeclarations: Type<any>[] = [
@ -464,18 +466,6 @@ export function transitiveScopesFor<T>(
return scopes; 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> { function expandModuleWithProviders(value: Type<any>| ModuleWithProviders<{}>): Type<any> {
if (isModuleWithProviders(value)) { if (isModuleWithProviders(value)) {
return value.ngModule; 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. * 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[] = []; const result: any[] = [];
let i = 0; let i = 0;
while (i < list.length) { while (i < list.length) {
@ -34,7 +34,7 @@ export function flatten(list: any[]): any[] {
i++; i++;
} }
} else { } else {
result.push(item); result.push(mapFn ? mapFn(item) : item);
i++; i++;
} }
} }

View File

@ -6,8 +6,9 @@
* found in the LICENSE file at https://angular.io/license * 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 {TestBed} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/src/matchers';
describe('component', () => { describe('component', () => {
@ -49,4 +50,42 @@ describe('component', () => {
expect(destroyCalls).toBe(1, 'Expected `ngOnDestroy` to only be called once.'); 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(); fixture.detectChanges();
expect(fixture.nativeElement.querySelector('span').innerHTML).toBe('First'); 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) { function initWithTemplate(compType: Type<any>, template: string) {
@ -149,6 +229,8 @@ class ComponentToReference {
@Component({selector: 'app-comp', template: ``}) @Component({selector: 'app-comp', template: ``})
class AppComp { class AppComp {
outer = false;
inner = false;
} }
@Directive({selector: '[dir]', exportAs: 'dir'}) @Directive({selector: '[dir]', exportAs: 'dir'})

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * 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 {TestBed} from '@angular/core/testing';
import {By} from '@angular/platform-browser'; import {By} from '@angular/platform-browser';
import {onlyInIvy} from '@angular/private/testing'; import {onlyInIvy} from '@angular/private/testing';
@ -203,5 +203,40 @@ describe('event listeners', () => {
expect(returnsFalseDir.event.preventDefault).toHaveBeenCalled(); 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 {TestBed} from '@angular/core/testing';
import {By} from '@angular/platform-browser'; import {By} from '@angular/platform-browser';
import {expect} from '@angular/platform-browser/testing/src/matchers'; 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', () => { it('should bind to properties whose names do not correspond to their attribute names', () => {
@Component({template: '<label [for]="forValue"></label>'}) @Component({template: '<label [for]="forValue"></label>'})
class MyComp { class MyComp {
@ -33,6 +34,25 @@ describe('elementProperty', () => {
expect(labelNode.nativeElement.getAttribute('for')).toBe('some-textarea'); 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, ' + it('should not map properties whose names do not correspond to their attribute names, ' +
'if they correspond to inputs', 'if they correspond to inputs',
() => { () => {
@ -60,4 +80,136 @@ describe('elementProperty', () => {
expect(myCompNode.nativeElement.getAttribute('for')).toBeFalsy(); expect(myCompNode.nativeElement.getAttribute('for')).toBeFalsy();
expect(myCompNode.componentInstance.for).toBe('hej'); 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(); fixture.detectChanges();
expect(getDOM().getInnerHTML(fixture.nativeElement)).toContain('[ERROR]'); 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', () => { 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 * found in the LICENSE file at https://angular.io/license
*/ */
import {AttributeMarker, ɵɵdefineComponent, ɵɵdefineDirective} from '../../src/render3/index'; import {ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵreference, ɵɵtext, ɵɵtextBinding} from '../../src/render3/instructions/all';
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 {RenderFlags} from '../../src/render3/interfaces/definition'; import {RenderFlags} from '../../src/render3/interfaces/definition';
import {NgIf} from './common_with_def'; import {ComponentFixture, createComponent} from './render_util';
import {ComponentFixture, createComponent, renderToHtml} from './render_util';
describe('exports', () => { describe('exports', () => {
// For basic use cases, see core/test/acceptance/exports_spec.ts. // For basic use cases, see core/test/acceptance/exports_spec.ts.
describe('forward refs', () => { 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', () => { it('should work inside a view container', () => {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) { const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) { if (rf & RenderFlags.Create) {
@ -214,74 +58,5 @@ describe('exports', () => {
fixture.update(); fixture.update();
expect(fixture.html).toEqual('<div></div>'); 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", "fs": "fs",
"path": "path", "path": "path",
"typescript": "ts", "typescript": "ts",
"typescript/lib/tsserverlibrary": "tsserverlibrary",
}, },
license_banner = "banner.js.txt", license_banner = "banner.js.txt",
visibility = ["//packages/language-service:__pkg__"], visibility = ["//packages/language-service:__pkg__"],

View File

@ -6,15 +6,16 @@
* found in the LICENSE file at https://angular.io/license * 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 {createLanguageService} from './language_service';
import {Completion, Diagnostic, DiagnosticMessageChain} from './types'; import {Completion, Diagnostic, DiagnosticMessageChain} from './types';
import {TypeScriptServiceHost} from './typescript_host'; 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); const host = projectHostMap.get(project);
if (host) { if (host) {
const externalFiles = host.getTemplateReferences(); const externalFiles = host.getTemplateReferences();
@ -63,7 +64,7 @@ function diagnosticToDiagnostic(d: Diagnostic, file: ts.SourceFile): ts.Diagnost
return result; 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 oldLS: ts.LanguageService = info.languageService;
const proxy: ts.LanguageService = Object.assign({}, oldLS); const proxy: ts.LanguageService = Object.assign({}, oldLS);
const logger = info.project.projectService.logger; const logger = info.project.projectService.logger;

View File

@ -7,12 +7,8 @@
*/ */
import * as path from 'path'; import * as path from 'path';
import * as ts from 'typescript';
import {createLanguageService} from '../src/language_service';
import {ReflectorHost} from '../src/reflector_host'; import {ReflectorHost} from '../src/reflector_host';
import {Completions, LanguageService} from '../src/types';
import {TypeScriptServiceHost} from '../src/typescript_host';
import {toh} from './test_data'; import {toh} from './test_data';
import {MockTypescriptHost} from './test_utils'; import {MockTypescriptHost} from './test_utils';
@ -25,12 +21,14 @@ describe('reflector_host_spec', () => {
let mockHost = new MockTypescriptHost( let mockHost = new MockTypescriptHost(
['/app/main.ts', '/app/parsing-cases.ts'], toh, 'app/node_modules', ['/app/main.ts', '/app/parsing-cases.ts'], toh, 'app/node_modules',
{...path, join: (...args: string[]) => originalJoin.apply(path, args)}); {...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'}); 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'); const result = reflectorHost.moduleNameToFileName('@angular/core');
expect(result).not.toBeNull('could not find @angular/core using path.win32'); 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), {}); 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`). * 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, provide: core.APP_INITIALIZER,
useFactory: _createNgProbe, useFactory: _createNgProbe,
@ -49,3 +58,5 @@ export const ELEMENT_PROBE_PROVIDERS: core.Provider[] = [
multi: true, 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 * from './private_export';
export {VERSION} from './version'; 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; new (eventName: string, args?: string[]): any;
} }
/** @deprecated */
export declare const inject: typeof ɵɵinject; export declare const inject: typeof ɵɵinject;
export interface 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 ɵɵ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; 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} ` : ''; const defineFlag = (compile !== 'legacy') ? `--define=compile=${compile} ` : '';
console.error(`TEST FAILED!`); console.error(`TEST FAILED!`);
console.error(` To update the golden file run: `); 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; return passed;

View File

@ -3,12 +3,11 @@
# Use of this source code is governed by an MIT-style license that can be # 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 # 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. This test verifies that a set of top level symbols from a javascript file match a gold file.
load("@build_bazel_rules_nodejs//internal/node:node.bzl", "nodejs_binary", "nodejs_test") """
def js_expected_symbol_test(name, src, golden, data = [], **kwargs): 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. """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, src,
golden, golden,
Label("//tools/symbol-extractor:lib"), Label("//tools/symbol-extractor:lib"),
Label("@bazel_tools//tools/bash/runfiles"),
Label("@npm//typescript"), Label("@npm//typescript"),
] ]
entry_point = "angular/tools/symbol-extractor/cli.js" 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 # But it will replaced to @npm//ts-api-guardian when publishing
"@angular//tools/ts-api-guardian:lib", "@angular//tools/ts-api-guardian:lib",
"@angular//tools/ts-api-guardian:bin", "@angular//tools/ts-api-guardian:bin",
# The below are required during runtime
"@npm//chalk",
"@npm//diff",
"@npm//minimist",
"@npm//typescript",
] ]
args = [ args = [
@ -46,7 +51,8 @@ def ts_api_guardian_test(
] ]
for i in strip_export_pattern: 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: for i in allow_module_identifiers:
args += ["--allowModuleIdentifiers", i] args += ["--allowModuleIdentifiers", i]

View File

@ -298,7 +298,7 @@ class ResolvedDeclarationEmitter {
const jsdocComment = this.processJsDocTags(node, tagOptions); const jsdocComment = this.processJsDocTags(node, tagOptions);
if (jsdocComment) { if (jsdocComment) {
// Add the annotation after the leading whitespace // 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 // 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 // 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. // 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], { const output = child_process.spawnSync(process.execPath, [BINARY_PATH, ...args], {
env: { env: {
'NODE_PATH': nodePath, '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" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9"
integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w== 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: ansi-styles@^2.2.1:
version "2.2.1" version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 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" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= 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: canonical-path@1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-1.0.0.tgz#fcb470c23958def85081856be7a86e904f180d1d" 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" right-align "^0.1.1"
wordwrap "0.0.2" 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: cliui@^4.0.0:
version "4.1.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" 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" shebang-command "^1.2.0"
which "^1.2.9" which "^1.2.9"
cross-spawn@^6.0.5: cross-spawn@^6.0.0, cross-spawn@^6.0.5:
version "6.0.5" version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
@ -3004,7 +3005,7 @@ decamelize-keys@^1.0.0:
decamelize "^1.1.0" decamelize "^1.1.0"
map-obj "^1.0.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" version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= 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" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= 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: emojis-list@^2.0.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" 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" signal-exit "^3.0.0"
strip-eof "^1.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: exit-code@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/exit-code/-/exit-code-1.0.2.tgz#ce165811c9f117af6a5f882940b96ae7f9aecc34" 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: dependencies:
locate-path "^2.0.0" 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: findup-sync@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" 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== integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==
get-caller-file@^1.0.1: get-caller-file@^1.0.1:
version "1.0.2" version "1.0.3"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
integrity sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U= 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: get-func-name@^2.0.0:
version "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" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
get-stream@^4.1.0: get-stream@^4.0.0, get-stream@^4.1.0:
version "4.1.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== 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" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= 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: ip@^1.1.5:
version "1.1.5" version "1.1.5"
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
@ -6502,6 +6538,13 @@ lcid@^1.0.0:
dependencies: dependencies:
invert-kv "^1.0.0" 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: levn@~0.3.0:
version "0.3.0" version "0.3.0"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" 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" pinkie-promise "^2.0.0"
strip-bom "^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: load-json-file@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" 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" p-locate "^2.0.0"
path-exists "^3.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: lodash._basecopy@^3.0.0:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36"
@ -7000,6 +7041,13 @@ make-iterator@^1.0.0:
dependencies: dependencies:
kind-of "^6.0.2" 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: map-cache@^0.2.0, map-cache@^0.2.2:
version "0.2.2" version "0.2.2"
resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
@ -7062,6 +7110,15 @@ mem@^1.1.0:
dependencies: dependencies:
mimic-fn "^1.0.0" 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: memoizeasync@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/memoizeasync/-/memoizeasync-1.1.0.tgz#9d7028a6f266deb733510bb7dbba5f51878c561e" 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" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== 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: mimic-response@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" 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" lcid "^1.0.0"
mem "^1.1.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: os-shim@^0.1.2:
version "0.1.3" version "0.1.3"
resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" 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" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0"
integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== 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: p-finally@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" 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" resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e"
integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= 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: p-limit@^1.1.0:
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
@ -8070,6 +8151,13 @@ p-limit@^1.1.0:
dependencies: dependencies:
p-try "^1.0.0" 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: p-locate@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
@ -8077,6 +8165,13 @@ p-locate@^2.0.0:
dependencies: dependencies:
p-limit "^1.1.0" 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: p-timeout@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" 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" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= 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: package-json@^4.0.0:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" 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" pify "^2.0.0"
pinkie-promise "^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: path-type@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" 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" find-up "^1.0.0"
read-pkg "^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: read-pkg-up@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" 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" normalize-package-data "^2.3.2"
path-type "^1.0.0" 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: read-pkg@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" 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" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= 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: requirejs@2.3.5:
version "2.3.5" version "2.3.5"
resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.5.tgz#617b9acbbcb336540ef4914d790323a8d4b861b0" 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" is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.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: string_decoder@~0.10.25, string_decoder@~0.10.x:
version "0.10.31" version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
@ -10258,6 +10348,13 @@ strip-ansi@^5.0.0:
dependencies: dependencies:
ansi-regex "^4.0.0" 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: strip-bom-buf@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz#1cb45aaf57530f4caf86c7f75179d2c9a51dd572" 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" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
yargs-parser@^7.0.0: yargs-parser@^13.0.0:
version "7.0.0" version "13.0.0"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.0.0.tgz#3fc44f3e76a8bdb1cc3602e860108602e5ccde8b"
integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k= integrity sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==
dependencies: dependencies:
camelcase "^4.1.0" camelcase "^5.0.0"
decamelize "^1.2.0"
yargs-parser@^9.0.2: yargs-parser@^9.0.2:
version "9.0.2" version "9.0.2"
@ -11646,24 +11744,22 @@ yargs@11.0.0:
y18n "^3.2.1" y18n "^3.2.1"
yargs-parser "^9.0.2" yargs-parser "^9.0.2"
yargs@9.0.1: yargs@13.1.0:
version "9.0.1" version "13.1.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.1.0.tgz#b2729ce4bfc0c584939719514099d8a916ad2301"
integrity sha1-UqzCP+7Kw0BCB47njAwAf1CF20w= integrity sha512-1UhJbXfzHiPqkfXNHYhiz79qM/kZqjTE8yGlEjZa85Q+3+OwcV6NRkV7XOV1W2Eom2bzILeUn55pQYffjVOLAg==
dependencies: dependencies:
camelcase "^4.1.0" cliui "^4.0.0"
cliui "^3.2.0" find-up "^3.0.0"
decamelize "^1.1.1" get-caller-file "^2.0.1"
get-caller-file "^1.0.1" os-locale "^3.1.0"
os-locale "^2.0.0"
read-pkg-up "^2.0.0"
require-directory "^2.1.1" require-directory "^2.1.1"
require-main-filename "^1.0.1" require-main-filename "^2.0.0"
set-blocking "^2.0.0" set-blocking "^2.0.0"
string-width "^2.0.0" string-width "^3.0.0"
which-module "^2.0.0" which-module "^2.0.0"
y18n "^3.2.1" y18n "^4.0.0"
yargs-parser "^7.0.0" yargs-parser "^13.0.0"
yargs@^11.0.0: yargs@^11.0.0:
version "11.1.0" version "11.1.0"